void SoundStream::ClearQueue() { // Get the number of buffers still in the queue ALint nbQueued; ALCheck(alGetSourcei(mySource, AL_BUFFERS_QUEUED, &nbQueued)); // Unqueue them all ALuint buffer; for (ALint i = 0; i < nbQueued; ++i) ALCheck(alSourceUnqueueBuffers(mySource, 1, &buffer)); }
//////////////////////////////////////////////////////////// /// Get the current value of the global volume of all the sounds //////////////////////////////////////////////////////////// float Listener::GetGlobalVolume() { float Volume = 0.f; ALCheck(alGetListenerf(AL_GAIN, &Volume)); return Volume; }
//////////////////////////////////////////////////////////// /// Get the sample rate //////////////////////////////////////////////////////////// unsigned int SoundBuffer::GetSampleRate() const { ALint SampleRate; ALCheck(alGetBufferi(myBuffer, AL_FREQUENCY, &SampleRate)); return SampleRate; }
float Sound::GetPlayingOffset() const { ALfloat seconds = 0.f; ALCheck(alGetSourcef(mySource, AL_SEC_OFFSET, &seconds)); return seconds; }
//////////////////////////////////////////////////////////// /// Return the number of channels (1 = mono, 2 = stereo, ...) //////////////////////////////////////////////////////////// unsigned int SoundBuffer::GetChannelsCount() const { ALint ChannelsCount; ALCheck(alGetBufferi(myBuffer, AL_CHANNELS, &ChannelsCount)); return ChannelsCount; }
bool Sound::GetLoop() const { ALint loop; ALCheck(alGetSourcei(mySource, AL_LOOPING, &loop)); return loop != 0; }
//////////////////////////////////////////////////////////// /// Default constructor //////////////////////////////////////////////////////////// SoundBuffer::SoundBuffer() : myBuffer (0), myDuration(0.f) { // Create the buffer ALCheck(alGenBuffers(1, &myBuffer)); }
//////////////////////////////////////////////////////////// /// Update the internal buffer with the audio samples //////////////////////////////////////////////////////////// bool SoundBuffer::Update(unsigned int ChannelsCount, unsigned int SampleRate) { // Check parameters if (!SampleRate || !ChannelsCount || mySamples.empty()) return false; // Find the good format according to the number of channels ALenum Format = priv::AudioDevice::GetInstance().GetFormatFromChannelsCount(ChannelsCount); // Check if the format is valid if (Format == 0) { std::cerr << "Unsupported number of channels (" << ChannelsCount << ")" << std::endl; return false; } // Fill the buffer ALsizei Size = static_cast<ALsizei>(mySamples.size()) * sizeof(Int16); ALCheck(alBufferData(myBuffer, Format, &mySamples[0], Size, SampleRate)); // Compute the duration myDuration = static_cast<float>(mySamples.size()) / SampleRate / ChannelsCount; return true; }
bool SoundBuffer::Update(unsigned int channelsCount, unsigned int sampleRate) { // Check parameters if (!channelsCount || !sampleRate || mySamples.empty()) return false; // Find the good format according to the number of channels ALenum format = priv::AudioDevice::GetFormatFromChannelsCount(channelsCount); // Check if the format is valid if (format == 0) { Err() << "Failed to load sound buffer (unsupported number of channels: " << channelsCount << ")" << std::endl; return false; } // Fill the buffer ALsizei size = static_cast<ALsizei>(mySamples.size()) * sizeof(Int16); ALCheck(alBufferData(myBuffer, format, &mySamples[0], size, sampleRate)); // Compute the duration myDuration = static_cast<Uint32>(1000 * mySamples.size() / sampleRate / channelsCount); return true; }
//////////////////////////////////////////////////////////// /// Get the current position of the listener //////////////////////////////////////////////////////////// ofxVec3f Listener::GetPosition() { ofxVec3f Position; ALCheck(alGetListener3f(AL_POSITION, &Position.x, &Position.y, &Position.z)); return Position; }
Uint32 SoundStream::GetPlayingOffset() const { ALfloat seconds = 0.f; ALCheck(alGetSourcef(mySource, AL_SEC_OFFSET, &seconds)); return static_cast<Uint32>(1000 * seconds + 1000 * mySamplesProcessed / mySampleRate / myChannelCount); }
//////////////////////////////////////////////////////////// /// Get the current orientation of the listener (the point /// he's looking at) //////////////////////////////////////////////////////////// ofxVec3f Listener::GetTarget() { float Orientation[6]; ALCheck(alGetListenerfv(AL_ORIENTATION, Orientation)); return ofxVec3f(Orientation[0], Orientation[1], Orientation[2]); }
bool SoundStream::FillAndPushBuffer(unsigned int bufferNum) { bool requestStop = false; // Acquire audio data Chunk data = {NULL, 0}; if (!OnGetData(data)) { // Mark the buffer as the last one (so that we know when to reset the playing position) myEndBuffers[bufferNum] = true; // Check if the stream must loop or stop if (myLoop) { // Return to the beginning of the stream source OnSeek(0); // If we previously had no data, try to fill the buffer once again if (!data.Samples || (data.SampleCount == 0)) { return FillAndPushBuffer(bufferNum); } } else { // Not looping: request stop requestStop = true; } } // Fill the buffer if some data was returned if (data.Samples && data.SampleCount) { unsigned int buffer = myBuffers[bufferNum]; // Fill the buffer ALsizei size = static_cast<ALsizei>(data.SampleCount) * sizeof(Int16); ALCheck(alBufferData(buffer, myFormat, data.Samples, size, mySampleRate)); // Push it into the sound queue ALCheck(alSourceQueueBuffers(mySource, 1, &buffer)); } return requestStop; }
void Sound::ResetBuffer() { // First stop the sound in case it is playing Stop(); // Detach the buffer ALCheck(alSourcei(mySource, AL_BUFFER, 0)); myBuffer = NULL; }
SoundBuffer::SoundBuffer() : myBuffer (0), myDuration(0) { priv::EnsureALInit(); // Create the buffer ALCheck(alGenBuffers(1, &myBuffer)); }
//////////////////////////////////////////////////////////// /// Destructor //////////////////////////////////////////////////////////// SoundBuffer::~SoundBuffer() { // First detach the buffer from the sounds that use it (to avoid OpenAL errors) for (SoundList::const_iterator it = mySounds.begin(); it != mySounds.end(); ++it) (*it)->ResetBuffer(); // Destroy the buffer if (myBuffer) ALCheck(alDeleteBuffers(1, &myBuffer)); }
//////////////////////////////////////////////////////////// /// Fill a new buffer with audio data, and push it to the /// playing queue //////////////////////////////////////////////////////////// bool SoundStream::FillAndPushBuffer(unsigned int BufferNum) { bool RequestStop = false; // Acquire audio data Chunk Data = {NULL, 0}; if (!OnGetData(Data)) { // Mark the buffer as the last one (so that we know when to reset the playing position) myEndBuffers[BufferNum] = true; // Check if the stream must loop or stop if (myLoop && OnStart()) { // If we succeeded to restart and we previously had no data, try to fill the buffer once again if (!Data.Samples || (Data.NbSamples == 0)) { return FillAndPushBuffer(BufferNum); } } else { // Not looping or restart failed: request stop RequestStop = true; } } // Fill the buffer if some data was returned if (Data.Samples && Data.NbSamples) { unsigned int Buffer = myBuffers[BufferNum]; // Fill the buffer ALsizei Size = static_cast<ALsizei>(Data.NbSamples) * sizeof(Int16); ALCheck(alBufferData(Buffer, myFormat, Data.Samples, Size, mySampleRate)); // Push it into the sound queue ALCheck(alSourceQueueBuffers(Sound::mySource, 1, &Buffer)); } return RequestStop; }
//////////////////////////////////////////////////////////// /// Copy constructor //////////////////////////////////////////////////////////// SoundBuffer::SoundBuffer(const SoundBuffer& Copy) : AudioResource(Copy), myBuffer (0), mySamples (Copy.mySamples), myDuration (Copy.myDuration) { // Create the buffer ALCheck(alGenBuffers(1, &myBuffer)); // Update the internal buffer with the new samples Update(Copy.GetChannelsCount(), Copy.GetSampleRate()); }
SoundBuffer::SoundBuffer(const SoundBuffer& copy) : myBuffer (0), mySamples (copy.mySamples), myDuration(copy.myDuration), mySounds () // don't copy the attached sounds { // Create the buffer ALCheck(alGenBuffers(1, &myBuffer)); // Update the internal buffer with the new samples Update(copy.GetChannelsCount(), copy.GetSampleRate()); }
//////////////////////////////////////////////////////////// /// Destroy all sound data and buffer //////////////////////////////////////////////////////////// void SoundBufferDestroy() { Int32 i = 0; for (i = 0; i < SOUND_BUFFER_SIZE; i++) { if (SoundData[i].Buffer != 0) { // Stop sound SoundStop(&SoundData[i]); // Delete source ALCheck(alDeleteSources(1, &SoundData[i].Source)); // Delete buffer ALCheck(alDeleteBuffers(1, &SoundData[i].Buffer)); // Free data Delete(SoundData[i].Samples); } } }
//////////////////////////////////////////////////////////// /// Fill a new buffer with audio data, and push it to the /// playing queue //////////////////////////////////////////////////////////// bool SoundStream::FillAndPushBuffer(unsigned int Buffer) { bool RequestStop = false; // Acquire audio data Chunk Data = {NULL, 0}; if (!OnGetData(Data)) RequestStop = true; // Create and fill the buffer, and push it to the queue if (Data.Samples && Data.NbSamples) { // Fill the buffer ALsizei Size = static_cast<ALsizei>(Data.NbSamples) * sizeof(Int16); ALCheck(alBufferData(Buffer, myFormat, Data.Samples, Size, mySampleRate)); // Push it into the sound queue ALCheck(alSourceQueueBuffers(Sound::mySource, 1, &Buffer)); } return RequestStop; }
void Sound::SetBuffer(const SoundBuffer& buffer) { // First detach from the previous buffer if (myBuffer) { Stop(); myBuffer->DetachSound(this); } // Assign and use the new buffer myBuffer = &buffer; myBuffer->AttachSound(this); ALCheck(alSourcei(mySource, AL_BUFFER, myBuffer->myBuffer)); }
void SoundStream::Play() { // Check if the sound parameters have been set if (myFormat == 0) { Err() << "Failed to play audio stream: sound parameters have not been initialized (call Initialize first)" << std::endl; return; } // If the sound is already playing (probably paused), just resume it if (myIsStreaming) { ALCheck(alSourcePlay(mySource)); return; } // Move to the beginning OnSeek(0); // Start updating the stream in a separate thread to avoid blocking the application mySamplesProcessed = 0; myIsStreaming = true; myThread.Launch(); }
//////////////////////////////////////////////////////////// /// Load sound into buffer //////////////////////////////////////////////////////////// void SoundBufferLoad(struct Sound * SoundStruct, char * File) { UInt32 MinorTime = 0; // Minor time means the most old file UInt32 Dimension = 0; // Dimension found Int32 i = 0; // Search if the sound is loaded for (i = 0; i < SOUND_BUFFER_SIZE; i++) { if (SoundData[i].File != NULL) { if (strcmp(SoundData[i].File, File) == 0) { // The sound is loaded.. just play it SoundStruct = &SoundData[i]; return; } } } // Search free sound for (i = 0; i < SOUND_BUFFER_SIZE; i++) { if (SoundData[i].Buffer == 0) { // Load sound if (SOUND_FROM_MEMORY) { char * BufferData; UInt32 BufferSize; // Load buffer from pack // if (!PackLoadData(File, BufferData, &BufferSize)) // { // return; // } // Load buffer data from memory if (SoundFileOpenReadFromMemory(SoundStruct, BufferData, BufferSize)) { // Destroy data Delete(BufferData); return; } } else { if (SoundFileOpenReadFromFile(SoundStruct, File)) { strcpy(SoundStruct->File, File); return; } } } } // Search last used for (i = 0; i < SOUND_BUFFER_SIZE; i++) { if (SoundStatus(&SoundData[i]) == Stopped) { if (SoundData[i].Time < MinorTime) { MinorTime = SoundData[i].Time; Dimension = i; } } } if (MinorTime != 0) { if (SoundData[Dimension].Buffer != 0) { // Remove data from the previous sound ALCheck(alDeleteBuffers(1, &SoundData[Dimension].Buffer)); // Delete source ALCheck(alDeleteSources(1, &SoundData[Dimension].Source)); } // Return last used SoundStruct = &SoundData[Dimension]; } else { // There isn't sounds available SoundStruct = NULL; } }
//////////////////////////////////////////////////////////// /// Destructor //////////////////////////////////////////////////////////// SoundBuffer::~SoundBuffer() { if (myBuffer) ALCheck(alDeleteBuffers(1, &myBuffer)); }
void Sound::SetPlayingOffset(float timeOffset) { ALCheck(alSourcef(mySource, AL_SEC_OFFSET, timeOffset)); }
void Sound::Play() { ALCheck(alSourcePlay(mySource)); }
void Sound::Stop() { ALCheck(alSourceStop(mySource)); }
void SoundStream::Stream() { // Create the buffers ALCheck(alGenBuffers(BufferCount, myBuffers)); for (int i = 0; i < BufferCount; ++i) myEndBuffers[i] = false; // Fill the queue bool requestStop = FillQueue(); // Play the sound ALCheck(alSourcePlay(mySource)); while (myIsStreaming) { // The stream has been interrupted! if (SoundSource::GetStatus() == Stopped) { if (!requestStop) { // Just continue ALCheck(alSourcePlay(mySource)); } else { // End streaming myIsStreaming = false; } } // Get the number of buffers that have been processed (ie. ready for reuse) ALint nbProcessed = 0; ALCheck(alGetSourcei(mySource, AL_BUFFERS_PROCESSED, &nbProcessed)); while (nbProcessed--) { // Pop the first unused buffer from the queue ALuint buffer; ALCheck(alSourceUnqueueBuffers(mySource, 1, &buffer)); // Find its number unsigned int bufferNum = 0; for (int i = 0; i < BufferCount; ++i) if (myBuffers[i] == buffer) { bufferNum = i; break; } // Retrieve its size and add it to the samples count if (myEndBuffers[bufferNum]) { // This was the last buffer: reset the sample count mySamplesProcessed = 0; myEndBuffers[bufferNum] = false; } else { ALint size, bits; ALCheck(alGetBufferi(buffer, AL_SIZE, &size)); ALCheck(alGetBufferi(buffer, AL_BITS, &bits)); mySamplesProcessed += size / (bits / 8); } // Fill it and push it back into the playing queue if (!requestStop) { if (FillAndPushBuffer(bufferNum)) requestStop = true; } } // Leave some time for the other threads if the stream is still playing if (SoundSource::GetStatus() != Stopped) Sleep(10); } // Stop the playback ALCheck(alSourceStop(mySource)); // Unqueue any buffer left in the queue ClearQueue(); // Delete the buffers ALCheck(alSourcei(mySource, AL_BUFFER, 0)); ALCheck(alDeleteBuffers(BufferCount, myBuffers)); }
void SoundStream::Pause() { ALCheck(alSourcePause(mySource)); }