SoundSource::SoundSource() { priv::ensureALInit(); alCheck(alGenSources(1, &m_source)); alCheck(alSourcei(m_source, AL_BUFFER, 0)); }
mad_flow MADStream::ms_output(void* user, mad_header const* header, mad_pcm* pcm) { RW_UNUSED(header); MADStream* self = static_cast<MADStream*>(user); if (self->stopped) { return MAD_FLOW_STOP; } if (!self->numFreeBuffers) { ALint buffersProcessed; do { /** * Sleep a bit while waiting for OpenAL buffers to become available. * The number is arbitrary and depends on the size of the * buffer/audio samples, * as well as how quickly the computer can feed more buffers into * OpenAL. */ std::this_thread::sleep_for(std::chrono::milliseconds(20)); alGetSourcei(self->alSource, AL_BUFFERS_PROCESSED, &buffersProcessed); } while (buffersProcessed <= 0); alCheck(alSourceUnqueueBuffers(self->alSource, buffersProcessed, self->unqueuedBuffers)); self->numFreeBuffers += buffersProcessed; } int nsamples = pcm->length; mad_fixed_t const *left, *right; left = pcm->samples[0]; right = pcm->samples[1]; int s = 0; while (nsamples--) { signed int sample = *left++; self->mCurrentSamples.push_back(scale(sample)); sample = *right++; self->mCurrentSamples.push_back(scale(sample)); s++; } alCheck(alBufferData(self->buffers[self->currentBuffer], AL_FORMAT_STEREO16, self->mCurrentSamples.data(), self->mCurrentSamples.size() * sizeof(uint16_t), pcm->samplerate)); alCheck(alSourceQueueBuffers(self->alSource, 1, self->buffers + self->currentBuffer)); self->mCurrentSamples.clear(); self->currentBuffer++; self->currentBuffer %= numALbuffers; self->numFreeBuffers--; return MAD_FLOW_CONTINUE; }
bool SoundStream::fillAndPushBuffer(unsigned int bufferNum, bool immediateLoop) { bool requestStop = false; // Acquire audio data, also address EOF and error cases if they occur Chunk data = {NULL, 0}; for (Uint32 retryCount = 0; !onGetData(data) && (retryCount < BufferRetries); ++retryCount) { // Mark the buffer as the last one (so that we know when to reset the playing position) m_endBuffers[bufferNum] = true; // Check if the stream must loop or stop if (!m_loop) { // Not looping: request stop requestStop = true; break; } // Return to the beginning of the stream source onSeek(Time::Zero); // If we got data, break and process it, else try to fill the buffer once again if (data.samples && data.sampleCount) break; // If immediateLoop is specified, we have to immediately adjust the sample count if (immediateLoop) { // We just tried to begin preloading at EOF: reset the sample count m_samplesProcessed = 0; m_endBuffers[bufferNum] = false; } // We're a looping sound that got no data, so we retry onGetData() } // Fill the buffer if some data was returned if (data.samples && data.sampleCount) { unsigned int buffer = m_buffers[bufferNum]; // Fill the buffer ALsizei size = static_cast<ALsizei>(data.sampleCount) * sizeof(Int16); alCheck(alBufferData(buffer, m_format, data.samples, size, m_sampleRate)); // Push it into the sound queue alCheck(alSourceQueueBuffers(m_source, 1, &buffer)); } else { // If we get here, we most likely ran out of retries requestStop = true; } return requestStop; }
void SoundStream::clearQueue() { // Get the number of buffers still in the queue ALint nbQueued; alCheck(alGetSourcei(m_source, AL_BUFFERS_QUEUED, &nbQueued)); // Unqueue them all ALuint buffer; for (ALint i = 0; i < nbQueued; ++i) alCheck(alSourceUnqueueBuffers(m_source, 1, &buffer)); }
SoundSource::SoundSource(const SoundSource& copy) { alCheck(alGenSources(1, &m_source)); alCheck(alSourcei(m_source, AL_BUFFER, 0)); setPitch(copy.getPitch()); setVolume(copy.getVolume()); setPosition(copy.getPosition()); setRelativeToListener(copy.isRelativeToListener()); setMinDistance(copy.getMinDistance()); setAttenuation(copy.getAttenuation()); }
bool SoundManager::SoundBuffer::bufferData(SoundSource& soundSource) { alCheck(alBufferData( buffer, soundSource.fileInfo.channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, &soundSource.data.front(), soundSource.data.size() * sizeof(uint16_t), soundSource.fileInfo.samplerate )); alCheck(alSourcei(source, AL_BUFFER, buffer)); return true; }
Time Sound::getPlayingOffset() const { ALfloat secs = 0.f; alCheck(alGetSourcef(m_source, AL_SEC_OFFSET, &secs)); return seconds(secs); }
bool Sound::getLoop() const { ALint loop; alCheck(alGetSourcei(m_source, AL_LOOPING, &loop)); return loop != 0; }
void Listener::setDirection(float x, float y, float z) { priv::ensureALInit(); float orientation[] = {x, y, z, 0.f, 1.f, 0.f}; alCheck(alListenerfv(AL_ORIENTATION, orientation)); }
bool SoundBuffer::update(unsigned int channelCount, unsigned int sampleRate) { // Check parameters if (!channelCount || !sampleRate || m_samples.empty()) return false; // Find the good format according to the number of channels ALenum format = priv::AudioDevice::getFormatFromChannelCount(channelCount); // Check if the format is valid if (format == 0) { err() << "Failed to load sound buffer (unsupported number of channels: " << channelCount << ")" << std::endl; return false; } // Fill the buffer ALsizei size = static_cast<ALsizei>(m_samples.size()) * sizeof(Int16); alCheck(alBufferData(m_buffer, format, &m_samples[0], size, sampleRate)); // Compute the duration m_duration = seconds(static_cast<float>(m_samples.size()) / sampleRate / channelCount); return true; }
Vector3f Listener::getDirection() { float orientation[6]; alCheck(alGetListenerfv(AL_ORIENTATION, orientation)); return Vector3f(orientation[0], orientation[1], orientation[2]); }
Vector3f Listener::getPosition() { Vector3f position; alCheck(alGetListener3f(AL_POSITION, &position.x, &position.y, &position.z)); return position; }
float Listener::getGlobalVolume() { float volume = 0.f; alCheck(alGetListenerf(AL_GAIN, &volume)); return volume * 100; }
Channel::Channel() { alGenSources(1, &m_source); if (alCheck()) { GetLogger()->Debug("Failed to create sound source. Code: %d\n", alGetCode()); m_ready = false; } else { m_ready = true; } m_priority = 0; m_buffer = nullptr; m_loop = false; m_mute = false; m_initFrequency = 0.0f; m_startAmplitude = 0.0f; m_startFrequency = 0.0f; m_changeFrequency = 0.0f; m_volume = 0.0f; m_id = 0; }
SoundBuffer::SoundBuffer() : m_buffer (0), m_duration() { // Create the buffer alCheck(alGenBuffers(1, &m_buffer)); }
unsigned int SoundBuffer::getChannelCount() const { ALint channelCount; alCheck(alGetBufferi(m_buffer, AL_CHANNELS, &channelCount)); return channelCount; }
float SoundSource::getPitch() const { ALfloat pitch; alCheck(alGetSourcef(m_source, AL_PITCH, &pitch)); return pitch; }
void AudioDevice::setPosition(const Vector3f& position) { if (audioContext) alCheck(alListener3f(AL_POSITION, position.x, position.y, position.z)); listenerPosition = position; }
unsigned int SoundBuffer::getSampleRate() const { ALint sampleRate; alCheck(alGetBufferi(m_buffer, AL_FREQUENCY, &sampleRate)); return sampleRate; }
float SoundSource::getAttenuation() const { ALfloat attenuation; alCheck(alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation)); return attenuation; }
void AudioDevice::setGlobalVolume(float volume) { if (audioContext) alCheck(alListenerf(AL_GAIN, volume * 0.01f)); listenerVolume = volume; }
float SoundSource::getMinDistance() const { ALfloat distance; alCheck(alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance)); return distance; }
bool SoundSource::isRelativeToListener() const { ALint relative; alCheck(alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative)); return relative != 0; }
Vector3f SoundSource::getPosition() const { Vector3f position; alCheck(alGetSource3f(m_source, AL_POSITION, &position.x, &position.y, &position.z)); return position; }
float SoundSource::getVolume() const { ALfloat gain; alCheck(alGetSourcef(m_source, AL_GAIN, &gain)); return gain * 100.f; }
Source::~Source() { stop(); if (id) { alCheck(alDeleteSources(1, &id)); } }
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) m_endBuffers[bufferNum] = true; // Check if the stream must loop or stop if (m_loop) { // Return to the beginning of the stream source onSeek(Time::Zero); // 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 = m_buffers[bufferNum]; // Fill the buffer ALsizei size = static_cast<ALsizei>(data.sampleCount) * sizeof(Int16); alCheck(alBufferData(buffer, m_format, data.samples, size, m_sampleRate)); // Push it into the sound queue alCheck(alSourceQueueBuffers(m_source, 1, &buffer)); } return requestStop; }
SoundBuffer::SoundBuffer() : m_buffer (0), m_duration() { priv::ensureALInit(); // Create the buffer alCheck(alGenBuffers(1, &m_buffer)); }
float Listener::getGlobalVolume() { priv::ensureALInit(); float volume = 0.f; alCheck(alGetListenerf(AL_GAIN, &volume)); return volume * 100; }
Vector3f Listener::getPosition() { priv::ensureALInit(); Vector3f position; alCheck(alGetListener3f(AL_POSITION, &position.x, &position.y, &position.z)); return position; }