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