SFML logo
  • Main Page
  • Namespaces
  • Classes
  • Files
  • File List

SoundStream.cpp

00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
00005 //
00006 // This software is provided 'as-is', without any express or implied warranty.
00007 // In no event will the authors be held liable for any damages arising from the use of this software.
00008 //
00009 // Permission is granted to anyone to use this software for any purpose,
00010 // including commercial applications, and to alter it and redistribute it freely,
00011 // subject to the following restrictions:
00012 //
00013 // 1. The origin of this software must not be misrepresented;
00014 //    you must not claim that you wrote the original software.
00015 //    If you use this software in a product, an acknowledgment
00016 //    in the product documentation would be appreciated but is not required.
00017 //
00018 // 2. Altered source versions must be plainly marked as such,
00019 //    and must not be misrepresented as being the original software.
00020 //
00021 // 3. This notice may not be removed or altered from any source distribution.
00022 //
00024 
00026 // Headers
00028 #include <SFML/Audio/SoundStream.hpp>
00029 #include <SFML/Audio/AudioDevice.hpp>
00030 #include <SFML/Audio/OpenAL.hpp>
00031 #include <SFML/System/Sleep.hpp>
00032 
00033 
00034 namespace sf
00035 {
00039 SoundStream::SoundStream() :
00040 myIsStreaming     (false),
00041 myChannelsCount   (0),
00042 mySampleRate      (0),
00043 myFormat          (0),
00044 myLoop            (false),
00045 mySamplesProcessed(0)
00046 {
00047 
00048 }
00049 
00050 
00054 SoundStream::~SoundStream()
00055 {
00056     // Stop the sound if it was playing
00057     Stop();
00058 }
00059 
00060 
00064 void SoundStream::Initialize(unsigned int ChannelsCount, unsigned int SampleRate)
00065 {
00066     myChannelsCount = ChannelsCount;
00067     mySampleRate    = SampleRate;
00068 
00069     // Deduce the format from the number of channels
00070     myFormat = priv::AudioDevice::GetInstance().GetFormatFromChannelsCount(ChannelsCount);
00071 
00072     // Check if the format is valid
00073     if (myFormat == 0)
00074     {
00075         myChannelsCount = 0;
00076         mySampleRate    = 0;
00077         std::cerr << "Unsupported number of channels (" << myChannelsCount << ")" << std::endl;
00078     }
00079 }
00080 
00081 
00085 void SoundStream::Play()
00086 {
00087     // Check if the sound parameters have been set
00088     if (myFormat == 0)
00089     {
00090         std::cerr << "Failed to play audio stream : sound parameters have not been initialized (call Initialize first)" << std::endl;
00091         return;
00092     }
00093 
00094     // If the sound is already playing (probably paused), just resume it
00095     if (myIsStreaming)
00096     {
00097         Sound::Play();
00098         return;
00099     }
00100 
00101     // Notify the derived class
00102     if (OnStart())
00103     {
00104         // Start updating the stream in a separate thread to avoid blocking the application
00105         mySamplesProcessed = 0;
00106         myIsStreaming = true;
00107         Launch();
00108     }
00109 }
00110 
00111 
00115 void SoundStream::Stop()
00116 {
00117     // Wait for the thread to terminate
00118     myIsStreaming = false;
00119     Wait();
00120 }
00121 
00122 
00126 unsigned int SoundStream::GetChannelsCount() const
00127 {
00128     return myChannelsCount;
00129 }
00130 
00131 
00135 unsigned int SoundStream::GetSampleRate() const
00136 {
00137     return mySampleRate;
00138 }
00139 
00140 
00144 Sound::Status SoundStream::GetStatus() const
00145 {
00146     Status Status = Sound::GetStatus();
00147 
00148     // To compensate for the lag between Play() and alSourcePlay()
00149     if ((Status == Stopped) && myIsStreaming)
00150         Status = Playing;
00151 
00152     return Status;
00153 }
00154 
00155 
00162 float SoundStream::GetPlayingOffset() const
00163 {
00164     return Sound::GetPlayingOffset() + static_cast<float>(mySamplesProcessed) / mySampleRate / myChannelsCount;
00165 }
00166 
00167 
00171 void SoundStream::SetLoop(bool Loop)
00172 {
00173     myLoop = Loop;
00174 }
00175 
00176 
00180 bool SoundStream::GetLoop() const
00181 {
00182     return myLoop;
00183 }
00184 
00185 
00189 void SoundStream::Run()
00190 {
00191     // Create buffers
00192     ALCheck(alGenBuffers(BuffersCount, myBuffers));
00193     unsigned int EndBuffer = 0xFFFF;
00194 
00195     // Fill the queue
00196     bool RequestStop = FillQueue();
00197 
00198     // Play the sound
00199     Sound::Play();
00200 
00201     while (myIsStreaming)
00202     {
00203         // The stream has been interrupted !
00204         if (Sound::GetStatus() == Stopped)
00205         {
00206             if (!RequestStop)
00207             {
00208                 // Just continue
00209                 Sound::Play();
00210             }
00211             else
00212             {
00213                 // End streaming
00214                 myIsStreaming = false;
00215             }
00216         }
00217 
00218         // Get the number of buffers that have been processed (ie. ready for reuse)
00219         ALint NbProcessed;
00220         ALCheck(alGetSourcei(Sound::mySource, AL_BUFFERS_PROCESSED, &NbProcessed));
00221 
00222         while (NbProcessed--)
00223         {
00224             // Pop the first unused buffer from the queue
00225             ALuint Buffer;
00226             ALCheck(alSourceUnqueueBuffers(Sound::mySource, 1, &Buffer));
00227 
00228             // Retrieve its size and add it to the samples count
00229             if (Buffer == EndBuffer)
00230             {
00231                 // This was the last buffer: reset the sample count
00232                 mySamplesProcessed = 0;
00233                 EndBuffer = 0xFFFF;
00234             }
00235             else
00236             {
00237                 ALint Size;
00238                 ALCheck(alGetBufferi(Buffer, AL_SIZE, &Size));
00239                 mySamplesProcessed += Size / sizeof(Int16);
00240             }
00241 
00242             // Fill it and push it back into the playing queue
00243             if (!RequestStop)
00244             {
00245                 if (FillAndPushBuffer(Buffer))
00246                 {
00247                     // User requested to stop: check if we must loop or really stop
00248                     if (myLoop && OnStart())
00249                     {
00250                         // Looping: mark the current buffer as the last one
00251                         // (to know when to reset the sample count)
00252                         EndBuffer = Buffer;
00253                     }
00254                     else
00255                     {
00256                         // Not looping or restart failed: request stop
00257                         RequestStop = true;
00258                     }
00259                 }
00260             }
00261         }
00262 
00263         // Leave some time for the other threads if the stream is still playing
00264         if (Sound::GetStatus() != Stopped)
00265             Sleep(0.1f);
00266     }
00267 
00268     // Stop the playback
00269     Sound::Stop();
00270 
00271     // Unqueue any buffer left in the queue
00272     ClearQueue();
00273 
00274     // Delete the buffers
00275     ALCheck(alSourcei(Sound::mySource, AL_BUFFER, 0));
00276     ALCheck(alDeleteBuffers(BuffersCount, myBuffers));
00277 }
00278 
00279 
00284 bool SoundStream::FillAndPushBuffer(unsigned int Buffer)
00285 {
00286     bool RequestStop = false;
00287 
00288     // Acquire audio data
00289     Chunk Data = {NULL, 0};
00290     if (!OnGetData(Data))
00291         RequestStop = true;
00292 
00293     // Create and fill the buffer, and push it to the queue
00294     if (Data.Samples && Data.NbSamples)
00295     {
00296         // Fill the buffer
00297         ALsizei Size = static_cast<ALsizei>(Data.NbSamples) * sizeof(Int16);
00298         ALCheck(alBufferData(Buffer, myFormat, Data.Samples, Size, mySampleRate));
00299 
00300         // Push it into the sound queue
00301         ALCheck(alSourceQueueBuffers(Sound::mySource, 1, &Buffer));
00302     }
00303 
00304     return RequestStop;
00305 }
00306 
00307 
00311 bool SoundStream::FillQueue()
00312 {
00313     // Fill and enqueue all the available buffers
00314     bool RequestStop = false;
00315     for (int i = 0; (i < BuffersCount) && !RequestStop; ++i)
00316     {
00317         if (FillAndPushBuffer(myBuffers[i]))
00318             RequestStop = true;
00319     }
00320 
00321     return RequestStop;
00322 }
00323 
00324 
00328 void SoundStream::ClearQueue()
00329 {
00330     // Get the number of buffers still in the queue
00331     ALint NbQueued;
00332     ALCheck(alGetSourcei(Sound::mySource, AL_BUFFERS_QUEUED, &NbQueued));
00333 
00334     // Unqueue them all
00335     ALuint Buffer;
00336     for (ALint i = 0; i < NbQueued; ++i)
00337         ALCheck(alSourceUnqueueBuffers(Sound::mySource, 1, &Buffer));
00338 }
00339 
00340 
00344 bool SoundStream::OnStart()
00345 {
00346     // Does nothing by default
00347 
00348     return true;
00349 }
00350 
00351 } // namespace sf

 ::  Copyright © 2007-2008 Laurent Gomila, all rights reserved  ::  Documentation generated by doxygen 1.5.2  ::