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/ALCheck.hpp> 00031 #include <SFML/System/Sleep.hpp> 00032 #include <SFML/System/Err.hpp> 00033 00034 00035 namespace sf 00036 { 00038 SoundStream::SoundStream() : 00039 myIsStreaming (false), 00040 myChannelsCount (0), 00041 mySampleRate (0), 00042 myFormat (0), 00043 myLoop (false), 00044 mySamplesProcessed(0) 00045 { 00046 00047 } 00048 00049 00051 SoundStream::~SoundStream() 00052 { 00053 // Stop the sound if it was playing 00054 Stop(); 00055 } 00056 00057 00059 void SoundStream::Initialize(unsigned int channelsCount, unsigned int sampleRate) 00060 { 00061 myChannelsCount = channelsCount; 00062 mySampleRate = sampleRate; 00063 00064 // Deduce the format from the number of channels 00065 myFormat = priv::AudioDevice::GetFormatFromChannelsCount(channelsCount); 00066 00067 // Check if the format is valid 00068 if (myFormat == 0) 00069 { 00070 myChannelsCount = 0; 00071 mySampleRate = 0; 00072 Err() << "Unsupported number of channels (" << myChannelsCount << ")" << std::endl; 00073 } 00074 } 00075 00076 00078 void SoundStream::Play() 00079 { 00080 // Check if the sound parameters have been set 00081 if (myFormat == 0) 00082 { 00083 Err() << "Failed to play audio stream: sound parameters have not been initialized (call Initialize first)" << std::endl; 00084 return; 00085 } 00086 00087 // If the sound is already playing (probably paused), just resume it 00088 if (myIsStreaming) 00089 { 00090 ALCheck(alSourcePlay(mySource)); 00091 return; 00092 } 00093 00094 // Move to the beginning 00095 OnSeek(0); 00096 00097 // Start updating the stream in a separate thread to avoid blocking the application 00098 mySamplesProcessed = 0; 00099 myIsStreaming = true; 00100 Launch(); 00101 } 00102 00103 00105 void SoundStream::Pause() 00106 { 00107 ALCheck(alSourcePause(mySource)); 00108 } 00109 00110 00112 void SoundStream::Stop() 00113 { 00114 // Wait for the thread to terminate 00115 myIsStreaming = false; 00116 Wait(); 00117 } 00118 00119 00121 unsigned int SoundStream::GetChannelsCount() const 00122 { 00123 return myChannelsCount; 00124 } 00125 00126 00128 unsigned int SoundStream::GetSampleRate() const 00129 { 00130 return mySampleRate; 00131 } 00132 00133 00135 SoundStream::Status SoundStream::GetStatus() const 00136 { 00137 Status status = SoundSource::GetStatus(); 00138 00139 // To compensate for the lag between Play() and alSourcePlay() 00140 if ((status == Stopped) && myIsStreaming) 00141 status = Playing; 00142 00143 return status; 00144 } 00145 00146 00148 void SoundStream::SetPlayingOffset(float timeOffset) 00149 { 00150 // Stop the stream 00151 Stop(); 00152 00153 // Let the derived class update the current position 00154 OnSeek(timeOffset); 00155 00156 // Restart streaming 00157 mySamplesProcessed = static_cast<unsigned int>(timeOffset * mySampleRate * myChannelsCount); 00158 myIsStreaming = true; 00159 Launch(); 00160 } 00161 00162 00164 float SoundStream::GetPlayingOffset() const 00165 { 00166 ALfloat seconds = 0.f; 00167 ALCheck(alGetSourcef(mySource, AL_SEC_OFFSET, &seconds)); 00168 00169 return seconds + static_cast<float>(mySamplesProcessed) / mySampleRate / myChannelsCount; 00170 } 00171 00172 00174 void SoundStream::SetLoop(bool loop) 00175 { 00176 myLoop = loop; 00177 } 00178 00179 00181 bool SoundStream::GetLoop() const 00182 { 00183 return myLoop; 00184 } 00185 00186 00188 void SoundStream::Run() 00189 { 00190 // Create the buffers 00191 ALCheck(alGenBuffers(BuffersCount, myBuffers)); 00192 for (int i = 0; i < BuffersCount; ++i) 00193 myEndBuffers[i] = false; 00194 00195 // Fill the queue 00196 bool requestStop = FillQueue(); 00197 00198 // Play the sound 00199 ALCheck(alSourcePlay(mySource)); 00200 00201 while (myIsStreaming) 00202 { 00203 // The stream has been interrupted! 00204 if (SoundSource::GetStatus() == Stopped) 00205 { 00206 if (!requestStop) 00207 { 00208 // Just continue 00209 ALCheck(alSourcePlay(mySource)); 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(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(mySource, 1, &buffer)); 00227 00228 // Find its number 00229 unsigned int bufferNum = 0; 00230 for (int i = 0; i < BuffersCount; ++i) 00231 if (myBuffers[i] == buffer) 00232 { 00233 bufferNum = i; 00234 break; 00235 } 00236 00237 // Retrieve its size and add it to the samples count 00238 if (myEndBuffers[bufferNum]) 00239 { 00240 // This was the last buffer: reset the sample count 00241 mySamplesProcessed = 0; 00242 myEndBuffers[bufferNum] = false; 00243 } 00244 else 00245 { 00246 ALint size; 00247 ALCheck(alGetBufferi(buffer, AL_SIZE, &size)); 00248 mySamplesProcessed += size / sizeof(Int16); 00249 } 00250 00251 // Fill it and push it back into the playing queue 00252 if (!requestStop) 00253 { 00254 if (FillAndPushBuffer(bufferNum)) 00255 requestStop = true; 00256 } 00257 } 00258 00259 // Leave some time for the other threads if the stream is still playing 00260 if (SoundSource::GetStatus() != Stopped) 00261 Sleep(0.1f); 00262 } 00263 00264 // Stop the playback 00265 ALCheck(alSourceStop(mySource)); 00266 00267 // Unqueue any buffer left in the queue 00268 ClearQueue(); 00269 00270 // Delete the buffers 00271 ALCheck(alSourcei(mySource, AL_BUFFER, 0)); 00272 ALCheck(alDeleteBuffers(BuffersCount, myBuffers)); 00273 } 00274 00275 00277 bool SoundStream::FillAndPushBuffer(unsigned int bufferNum) 00278 { 00279 bool requestStop = false; 00280 00281 // Acquire audio data 00282 Chunk data = {NULL, 0}; 00283 if (!OnGetData(data)) 00284 { 00285 // Mark the buffer as the last one (so that we know when to reset the playing position) 00286 myEndBuffers[bufferNum] = true; 00287 00288 // Check if the stream must loop or stop 00289 if (myLoop) 00290 { 00291 // Return to the beginning of the stream source 00292 OnSeek(0); 00293 00294 // If we previously had no data, try to fill the buffer once again 00295 if (!data.Samples || (data.NbSamples == 0)) 00296 { 00297 return FillAndPushBuffer(bufferNum); 00298 } 00299 } 00300 else 00301 { 00302 // Not looping: request stop 00303 requestStop = true; 00304 } 00305 } 00306 00307 // Fill the buffer if some data was returned 00308 if (data.Samples && data.NbSamples) 00309 { 00310 unsigned int buffer = myBuffers[bufferNum]; 00311 00312 // Fill the buffer 00313 ALsizei size = static_cast<ALsizei>(data.NbSamples) * sizeof(Int16); 00314 ALCheck(alBufferData(buffer, myFormat, data.Samples, size, mySampleRate)); 00315 00316 // Push it into the sound queue 00317 ALCheck(alSourceQueueBuffers(mySource, 1, &buffer)); 00318 } 00319 00320 return requestStop; 00321 } 00322 00323 00325 bool SoundStream::FillQueue() 00326 { 00327 // Fill and enqueue all the available buffers 00328 bool requestStop = false; 00329 for (int i = 0; (i < BuffersCount) && !requestStop; ++i) 00330 { 00331 if (FillAndPushBuffer(i)) 00332 requestStop = true; 00333 } 00334 00335 return requestStop; 00336 } 00337 00338 00340 void SoundStream::ClearQueue() 00341 { 00342 // Get the number of buffers still in the queue 00343 ALint nbQueued; 00344 ALCheck(alGetSourcei(mySource, AL_BUFFERS_QUEUED, &nbQueued)); 00345 00346 // Unqueue them all 00347 ALuint buffer; 00348 for (ALint i = 0; i < nbQueued; ++i) 00349 ALCheck(alSourceUnqueueBuffers(mySource, 1, &buffer)); 00350 } 00351 00352 } // namespace sf
:: Copyright © 2007-2008 Laurent Gomila, all rights reserved :: Documentation generated by doxygen 1.5.2 ::