199 lines
3.9 KiB
C++
199 lines
3.9 KiB
C++
#include <cassert>
|
|
#include <algorithm>
|
|
#include <functional>
|
|
|
|
#include "SoundSource.h"
|
|
#include "SoundResource.h"
|
|
#include "SoundEngine.h"
|
|
#include "ThreadPool.h"
|
|
|
|
SoundSource::SoundSource()
|
|
{
|
|
alGenSources(1, &m_source);
|
|
m_resource = NULL;
|
|
m_isPlaying = false;
|
|
m_isLooping = false;
|
|
m_isLoadingBuffer = false;
|
|
m_isLoadingResource = false;
|
|
m_cancelBufferLoading = false;
|
|
m_nextSample = 0;
|
|
m_pendingSeek = -1.0f;
|
|
}
|
|
|
|
SoundSource::~SoundSource()
|
|
{
|
|
SetResource(NULL);
|
|
alDeleteSources(1, &m_source);
|
|
}
|
|
|
|
void SoundSource::ReleaseAllQueuedBuffers()
|
|
{
|
|
if (!m_resource || !m_resource->IsStreaming())
|
|
return;
|
|
|
|
int count = 0;
|
|
ALuint buffer = AL_NONE;
|
|
|
|
alSourceStop(m_source);
|
|
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &count);
|
|
|
|
for(int i = 0; i < count; i++)
|
|
{
|
|
alSourceUnqueueBuffers(m_source, 1, &buffer);
|
|
SoundEngine::ReleaseBuffer(buffer);
|
|
}
|
|
}
|
|
|
|
void SoundSource::SetResource(const char *name)
|
|
{
|
|
if (m_isLoadingResource)
|
|
{
|
|
printf("SoundSource::SetResource(\"%s\"), another resource is already being loaded!\n", name);
|
|
return;
|
|
}
|
|
|
|
if (name && m_resource && m_resource->GetName() == std::string(name))
|
|
return;
|
|
|
|
if (m_isLoadingBuffer)
|
|
m_cancelBufferLoading = true;
|
|
|
|
// The source must be stopped before we can change any buffers.
|
|
alSourceStop(m_source);
|
|
|
|
if (m_resource)
|
|
{
|
|
ReleaseAllQueuedBuffers();
|
|
alSourcei(m_source, AL_BUFFER, AL_NONE);
|
|
SoundEngine::ReleaseSoundResource(m_resource);
|
|
}
|
|
|
|
m_resource = NULL;
|
|
|
|
if (name)
|
|
{
|
|
SoundSource *source = this;
|
|
|
|
std::function<void()> task = [source, name]() {
|
|
SoundResource *resource = SoundEngine::GetSoundResource(name);
|
|
|
|
if (resource)
|
|
{
|
|
if (!resource->IsStreaming())
|
|
{
|
|
alSourcei(source->m_source, AL_BUFFER, resource->GetBuffer());
|
|
alSourcei(source->m_source, AL_LOOPING, (source->m_isLooping? AL_TRUE : AL_FALSE));
|
|
}
|
|
else
|
|
{
|
|
source->m_nextSample = 0;
|
|
alSourcei(source->m_source, AL_LOOPING, AL_FALSE);
|
|
}
|
|
|
|
if (source->m_isPlaying)
|
|
source->Play();
|
|
}
|
|
|
|
source->m_resource = resource;
|
|
source->m_isLoadingResource = false;
|
|
|
|
if (source->m_pendingSeek > 0.0f)
|
|
{
|
|
source->Seek(source->m_pendingSeek);
|
|
source->m_pendingSeek = -1.0f;
|
|
}
|
|
};
|
|
|
|
m_isLoadingResource = true;
|
|
SoundEngine::m_threadPool->EnqueueTask(task);
|
|
}
|
|
}
|
|
|
|
SoundResource *SoundSource::GetResource()
|
|
{
|
|
return m_resource;
|
|
}
|
|
|
|
bool SoundSource::IsPlaying()
|
|
{
|
|
return m_isPlaying;
|
|
}
|
|
|
|
bool SoundSource::IsLooping()
|
|
{
|
|
return m_isLooping;
|
|
}
|
|
|
|
void SoundSource::Play()
|
|
{
|
|
alSourcePlay(m_source);
|
|
m_isPlaying = true;
|
|
}
|
|
|
|
void SoundSource::Pause()
|
|
{
|
|
alSourcePause(m_source);
|
|
m_isPlaying = false;
|
|
}
|
|
|
|
void SoundSource::Seek(float time)
|
|
{
|
|
if (m_isLoadingResource)
|
|
{
|
|
m_pendingSeek = time;
|
|
return;
|
|
}
|
|
|
|
if (!m_resource)
|
|
return;
|
|
|
|
size_t sample = std::min(m_resource->GetSampleCountForTime(std::max(time, 0.0f)), m_resource->GetTotalSampleCount() - 1);
|
|
|
|
if (!m_resource->IsStreaming())
|
|
{
|
|
alSourcei(m_source, AL_SAMPLE_OFFSET, (ALint)sample);
|
|
}
|
|
else
|
|
{
|
|
if (m_isLoadingBuffer)
|
|
m_cancelBufferLoading = true;
|
|
|
|
ReleaseAllQueuedBuffers();
|
|
m_nextSample = sample;
|
|
}
|
|
}
|
|
|
|
void SoundSource::SetPosition(const float position[3])
|
|
{
|
|
const float scaledPosition[3] = {position[0] * SOUNDENGINE_POSITION_SCALE, position[1] * SOUNDENGINE_POSITION_SCALE, position[2] * SOUNDENGINE_POSITION_SCALE};
|
|
alSourcefv(m_source, AL_POSITION, scaledPosition);
|
|
}
|
|
|
|
void SoundSource::SetVelocity(const float velocity[3])
|
|
{
|
|
alSourcefv(m_source, AL_VELOCITY, velocity);
|
|
}
|
|
|
|
void SoundSource::SetVolume(float volume)
|
|
{
|
|
alSourcef(m_source, AL_GAIN, volume);
|
|
}
|
|
|
|
void SoundSource::SetLooping(bool looping)
|
|
{
|
|
m_isLooping = looping;
|
|
|
|
if (m_resource && !m_resource->IsStreaming())
|
|
alSourcei(m_source, AL_LOOPING, (looping? AL_TRUE : AL_FALSE));
|
|
}
|
|
|
|
void SoundSource::SetPitch(float pitch)
|
|
{
|
|
alSourcef(m_source, AL_PITCH, pitch);
|
|
}
|
|
|
|
void SoundSource::SetIsRelativeToListener(bool relative)
|
|
{
|
|
alSourcei(m_source, AL_SOURCE_RELATIVE, (relative? AL_TRUE : AL_FALSE));
|
|
}
|