SoundStream.cpp

00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007 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/SoundBuffer.hpp>
00030 #include <SFML/Audio/AudioDevice.hpp>
00031 #include <SFML/Audio/OpenAL.hpp>
00032 #include <SFML/System/Sleep.hpp>
00033 
00034 
00038 sfSoundStream::sfSoundStream() :
00039 myIsStreaming  (false),
00040 myChannelsCount(0),
00041 mySampleRate   (0),
00042 myFormat       (0)
00043 {
00044 
00045 }
00046 
00047 
00051 sfSoundStream::~sfSoundStream()
00052 {
00053     // Stop the sound if it was playing
00054     Stop();
00055 }
00056 
00057 
00061 void sfSoundStream::Initialize(unsigned int ChannelsCount, unsigned int SampleRate)
00062 {
00063     myChannelsCount = ChannelsCount;
00064     mySampleRate    = SampleRate;
00065 
00066     // Deduce thee format from the number of channels
00067     myFormat = sf_private::sfAudioDevice::GetInstance().GetFormatFromChannelsCount(ChannelsCount);
00068 
00069     // Check if the format is valid
00070     if (myFormat == 0)
00071     {
00072         myChannelsCount = 0;
00073         mySampleRate    = 0;
00074         std::cerr << "Unsupported number of channels (" << myChannelsCount << ")" << std::endl;
00075     }
00076 }
00077 
00078 
00082 void sfSoundStream::Play()
00083 {
00084     // Check if the sound parameters have been set
00085     if (myFormat == 0)
00086     {
00087         std::cerr << "Failed to play audio stream : sound parameters have not been initialized (call Initialize first)" << std::endl;
00088         return;
00089     }
00090 
00091     // If the sound is already playing (probably paused), just resume it
00092     if (myIsStreaming)
00093     {
00094         sfSound::Play();
00095         return;
00096     }
00097 
00098     // Notify the derived class
00099     if (OnStart())
00100     {
00101         // Start updating the stream in a separate thread to avoid blocking the application
00102         myIsStreaming = true;
00103         Launch();
00104     }
00105 }
00106 
00107 
00111 void sfSoundStream::Stop()
00112 {
00113     // Wait for the thread to terminate
00114     myIsStreaming = false;
00115     Wait();
00116 }
00117 
00118 
00122 unsigned int sfSoundStream::GetChannelsCount() const
00123 {
00124     return myChannelsCount;
00125 }
00126 
00127 
00131 unsigned int sfSoundStream::GetSampleRate() const
00132 {
00133     return mySampleRate;
00134 }
00135 
00136 
00140 sfSound::Status sfSoundStream::GetStatus() const
00141 {
00142     Status Status = sfSound::GetStatus();
00143 
00144     // To compensate for the lag between Play() and alSourcePlay()
00145     if ((Status == Stopped) && myIsStreaming)
00146         Status = Playing;
00147 
00148     return Status;
00149 }
00150 
00151 
00155 void sfSoundStream::Run()
00156 {
00157     // Enqueue the buffers
00158     sfALCheck(alGenBuffers(BuffersCount, myBuffers));
00159     for (int i = 0; i < BuffersCount; ++i)
00160     {
00161         // Acquire audio data
00162         Chunk Data = {NULL, 0};
00163         if (OnGetData(Data))
00164         {
00165             // Create and fill a buffer, and push it to the queue
00166             if (Data.Samples && Data.NbSamples)
00167             {
00168                 // Fill the buffer
00169                 ALsizei Size = static_cast<ALsizei>(Data.NbSamples) * sizeof(sfInt16);
00170                 sfALCheck(alBufferData(myBuffers[i], myFormat, Data.Samples, Size, mySampleRate));
00171 
00172                 // Push it into the sound queue
00173                 sfALCheck(alSourceQueueBuffers(sfSound::mySource, 1, &myBuffers[i]));
00174             }
00175         }
00176     }
00177 
00178     // Play the sound
00179     sfSound::Play();
00180 
00181     while (myIsStreaming)
00182     {
00183         // If the stream has been interrupted the source is stopped, so we have to keep it on playing
00184         if (sfSound::GetStatus() == Stopped)
00185             sfSound::Play();
00186 
00187         // Get the number of buffers that have been processed (ie. ready for reuse)
00188         ALint NbProcessed;
00189         sfALCheck(alGetSourcei(sfSound::mySource, AL_BUFFERS_PROCESSED, &NbProcessed));
00190 
00191         for (ALint i = 0; i < NbProcessed; ++i)
00192         {
00193             // Pop the first unused buffer from the queue
00194             ALuint Buffer;
00195             sfALCheck(alSourceUnqueueBuffers(sfSound::mySource, 1, &Buffer));
00196 
00197             // Acquire new data
00198             Chunk Data = {NULL, 0};
00199             if (OnGetData(Data))
00200             {
00201                 // Fill the buffer with the new data, and push it back to the queue
00202                 if (Data.Samples && Data.NbSamples)
00203                 {
00204                     // Fill the buffer
00205                     ALsizei Size = static_cast<ALsizei>(Data.NbSamples) * sizeof(sfInt16);
00206                     sfALCheck(alBufferData(Buffer, myFormat, Data.Samples, Size, mySampleRate));
00207 
00208                     // Push it into the sound queue
00209                     sfALCheck(alSourceQueueBuffers(sfSound::mySource, 1, &Buffer));
00210                 }
00211             }
00212             else
00213             {
00214                 // Oops... the user wants to stop the sound :(
00215                 myIsStreaming = false;
00216                 break;
00217             }
00218         }
00219 
00220         // Leave some time for the other threads
00221         sfSleep(0.1f);
00222     }
00223 
00224     // Streaming finished : clean up everything
00225     CleanUp();
00226 }
00227 
00228 
00232 void sfSoundStream::CleanUp()
00233 {
00234     // Stop the playback
00235     sfSound::Stop();
00236 
00237     // Unqueue any buffer left in the queue
00238     ALint  NbQueued;
00239     ALuint Buffer;
00240     sfALCheck(alGetSourcei(sfSound::mySource, AL_BUFFERS_QUEUED, &NbQueued));
00241     for (ALint i = 0; i < NbQueued; ++i)
00242         sfALCheck(alSourceUnqueueBuffers(sfSound::mySource, 1, &Buffer));
00243 
00244     // Delete the buffers
00245     sfALCheck(alDeleteBuffers(BuffersCount, myBuffers));
00246 }
00247 
00248 
00252 bool sfSoundStream::OnStart()
00253 {
00254     // Does nothing by default
00255 
00256     return true;
00257 }