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