SoundStream.cpp
00001 00002 // 00003 // SFML - Simple and Fast Multimedia Library 00004 // Copyright (C) 2007-2009 Laurent Gomila ([email protected]) 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 the buffers 00192 ALCheck(alGenBuffers(BuffersCount, myBuffers)); 00193 for (int i = 0; i < BuffersCount; ++i) 00194 myEndBuffers[i] = false; 00195 00196 // Fill the queue 00197 bool RequestStop = FillQueue(); 00198 00199 // Play the sound 00200 Sound::Play(); 00201 00202 while (myIsStreaming) 00203 { 00204 // The stream has been interrupted ! 00205 if (Sound::GetStatus() == Stopped) 00206 { 00207 if (!RequestStop) 00208 { 00209 // Just continue 00210 Sound::Play(); 00211 } 00212 else 00213 { 00214 // End streaming 00215 myIsStreaming = false; 00216 } 00217 } 00218 00219 // Get the number of buffers that have been processed (ie. ready for reuse) 00220 ALint NbProcessed; 00221 ALCheck(alGetSourcei(Sound::mySource, AL_BUFFERS_PROCESSED, &NbProcessed)); 00222 00223 while (NbProcessed--) 00224 { 00225 // Pop the first unused buffer from the queue 00226 ALuint Buffer; 00227 ALCheck(alSourceUnqueueBuffers(Sound::mySource, 1, &Buffer)); 00228 00229 // Find its number 00230 unsigned int BufferNum = 0; 00231 for (int i = 0; i < BuffersCount; ++i) 00232 if (myBuffers[i] == Buffer) 00233 { 00234 BufferNum = i; 00235 break; 00236 } 00237 00238 // Retrieve its size and add it to the samples count 00239 if (myEndBuffers[BufferNum]) 00240 { 00241 // This was the last buffer: reset the sample count 00242 mySamplesProcessed = 0; 00243 myEndBuffers[BufferNum] = false; 00244 } 00245 else 00246 { 00247 ALint Size; 00248 ALCheck(alGetBufferi(Buffer, AL_SIZE, &Size)); 00249 mySamplesProcessed += Size / sizeof(Int16); 00250 } 00251 00252 // Fill it and push it back into the playing queue 00253 if (!RequestStop) 00254 { 00255 if (FillAndPushBuffer(BufferNum)) 00256 RequestStop = true; 00257 } 00258 } 00259 00260 // Leave some time for the other threads if the stream is still playing 00261 if (Sound::GetStatus() != Stopped) 00262 Sleep(0.1f); 00263 } 00264 00265 // Stop the playback 00266 Sound::Stop(); 00267 00268 // Unqueue any buffer left in the queue 00269 ClearQueue(); 00270 00271 // Delete the buffers 00272 ALCheck(alSourcei(Sound::mySource, AL_BUFFER, 0)); 00273 ALCheck(alDeleteBuffers(BuffersCount, myBuffers)); 00274 } 00275 00276 00281 bool SoundStream::FillAndPushBuffer(unsigned int BufferNum) 00282 { 00283 bool RequestStop = false; 00284 00285 // Acquire audio data 00286 Chunk Data = {NULL, 0}; 00287 if (!OnGetData(Data)) 00288 { 00289 // Mark the buffer as the last one (so that we know when to reset the playing position) 00290 myEndBuffers[BufferNum] = true; 00291 00292 // Check if the stream must loop or stop 00293 if (myLoop && OnStart()) 00294 { 00295 // If we succeeded to restart and we previously had no data, try to fill the buffer once again 00296 if (!Data.Samples || (Data.NbSamples == 0)) 00297 { 00298 return FillAndPushBuffer(BufferNum); 00299 } 00300 } 00301 else 00302 { 00303 // Not looping or restart failed: request stop 00304 RequestStop = true; 00305 } 00306 } 00307 00308 // Fill the buffer if some data was returned 00309 if (Data.Samples && Data.NbSamples) 00310 { 00311 unsigned int Buffer = myBuffers[BufferNum]; 00312 00313 // Fill the buffer 00314 ALsizei Size = static_cast<ALsizei>(Data.NbSamples) * sizeof(Int16); 00315 ALCheck(alBufferData(Buffer, myFormat, Data.Samples, Size, mySampleRate)); 00316 00317 // Push it into the sound queue 00318 ALCheck(alSourceQueueBuffers(Sound::mySource, 1, &Buffer)); 00319 } 00320 00321 return RequestStop; 00322 } 00323 00324 00328 bool SoundStream::FillQueue() 00329 { 00330 // Fill and enqueue all the available buffers 00331 bool RequestStop = false; 00332 for (int i = 0; (i < BuffersCount) && !RequestStop; ++i) 00333 { 00334 if (FillAndPushBuffer(i)) 00335 RequestStop = true; 00336 } 00337 00338 return RequestStop; 00339 } 00340 00341 00345 void SoundStream::ClearQueue() 00346 { 00347 // Get the number of buffers still in the queue 00348 ALint NbQueued; 00349 ALCheck(alGetSourcei(Sound::mySource, AL_BUFFERS_QUEUED, &NbQueued)); 00350 00351 // Unqueue them all 00352 ALuint Buffer; 00353 for (ALint i = 0; i < NbQueued; ++i) 00354 ALCheck(alSourceUnqueueBuffers(Sound::mySource, 1, &Buffer)); 00355 } 00356 00357 00361 bool SoundStream::OnStart() 00362 { 00363 // Does nothing by default 00364 00365 return true; 00366 } 00367 00368 } // namespace sf
:: Copyright © 2007-2008 Laurent Gomila, all rights reserved :: Documentation generated by doxygen 1.5.2 ::