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 ::