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