SFML logo
  • Main Page
  • Namespaces
  • Classes
  • Files
  • File List

SoundStream.cpp

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