Added Source:clone() and love.audio.newSource(source): creates a new (stopped) Source which has all of the settable state of the original.

Static sources don’t duplicate their OpenAL data buffer when cloned (resolves issue #319). Cloned streaming sources also clone the original Decoder.
This commit is contained in:
Alex Szpakowski
2013-12-20 00:20:41 -04:00
parent d0d629a314
commit e6f2d4f1ac
8 changed files with 126 additions and 24 deletions
+76 -19
View File
@@ -33,10 +33,22 @@ namespace audio
namespace openal
{
StaticDataBuffer::StaticDataBuffer(ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
{
alGenBuffers(1, &buffer);
alBufferData(buffer, format, data, size, freq);
}
StaticDataBuffer::~StaticDataBuffer()
{
alDeleteBuffers(1, &buffer);
}
Source::Source(Pool *pool, love::sound::SoundData *soundData)
: love::audio::Source(Source::TYPE_STATIC)
, pool(pool)
, valid(false)
, staticBuffer(nullptr)
, pitch(1.0f)
, volume(1.0f)
, relative(false)
@@ -51,14 +63,13 @@ Source::Source(Pool *pool, love::sound::SoundData *soundData)
, offsetSamples(0)
, offsetSeconds(0)
, channels(soundData->getChannels())
, decoder(0)
, decoder(nullptr)
, toLoop(0)
{
alGenBuffers(1, buffers);
ALenum fmt = getFormat(soundData->getChannels(), soundData->getBitDepth());
alBufferData(buffers[0], fmt, soundData->getData(), soundData->getSize(), soundData->getSampleRate());
staticBuffer = new StaticDataBuffer(fmt, soundData->getData(), soundData->getSize(), soundData->getSampleRate());
static float z[3] = {0, 0, 0};
float z[3] = {0, 0, 0};
setFloatv(position, z);
setFloatv(velocity, z);
@@ -69,6 +80,7 @@ Source::Source(Pool *pool, love::sound::Decoder *decoder)
: love::audio::Source(Source::TYPE_STREAM)
, pool(pool)
, valid(false)
, staticBuffer(nullptr)
, pitch(1.0f)
, volume(1.0f)
, relative(false)
@@ -87,27 +99,70 @@ Source::Source(Pool *pool, love::sound::Decoder *decoder)
, toLoop(0)
{
decoder->retain();
alGenBuffers(MAX_BUFFERS, buffers);
alGenBuffers(MAX_BUFFERS, streamBuffers);
static float z[3] = {0, 0, 0};
float z[3] = {0, 0, 0};
setFloatv(position, z);
setFloatv(velocity, z);
setFloatv(direction, z);
}
Source::Source(Source *s)
: love::audio::Source(s->type)
, pool(s->pool)
, valid(false)
, staticBuffer(s->staticBuffer)
, pitch(s->pitch)
, volume(s->volume)
, relative(s->relative)
, looping(s->looping)
, paused(false)
, minVolume(s->minVolume)
, maxVolume(s->maxVolume)
, referenceDistance(s->referenceDistance)
, rolloffFactor(s->rolloffFactor)
, maxDistance(s->maxDistance)
, cone(s->cone)
, offsetSamples(0)
, offsetSeconds(0)
, channels(s->channels)
, decoder(nullptr)
, toLoop(0)
{
if (type == TYPE_STREAM)
{
if (s->decoder)
decoder = s->decoder->clone();
alGenBuffers(MAX_BUFFERS, streamBuffers);
}
else
staticBuffer->retain();
setFloatv(position, s->position);
setFloatv(velocity, s->velocity);
setFloatv(direction, s->direction);
}
Source::~Source()
{
if (valid)
pool->stop(this);
alDeleteBuffers((type == TYPE_STATIC) ? 1 : MAX_BUFFERS, buffers);
if (type == TYPE_STREAM)
alDeleteBuffers(MAX_BUFFERS, streamBuffers);
if (staticBuffer)
staticBuffer->release();
if (decoder)
decoder->release();
}
love::audio::Source *Source::copy()
love::audio::Source *Source::clone()
{
return 0;
return new Source(this);
}
void Source::play()
@@ -341,13 +396,15 @@ float Source::tellAtomic(void *unit) const
break;
case Source::UNIT_SECONDS:
default:
alGetSourcef(source, AL_SAMPLE_OFFSET, &offset);
ALint buffer;
alGetSourcei(source, AL_BUFFER, &buffer);
int freq;
alGetBufferi(buffer, AL_FREQUENCY, &freq);
offset /= freq;
if (type == TYPE_STREAM) offset += offsetSeconds;
{
alGetSourcef(source, AL_SAMPLE_OFFSET, &offset);
ALint buffer;
alGetSourcei(source, AL_BUFFER, &buffer);
int freq;
alGetBufferi(buffer, AL_FREQUENCY, &freq);
offset /= freq;
if (type == TYPE_STREAM) offset += offsetSeconds;
}
break;
}
return offset;
@@ -459,7 +516,7 @@ void Source::playAtomic()
{
if (type == TYPE_STATIC)
{
alSourcei(source, AL_BUFFER, buffers[0]);
alSourcei(source, AL_BUFFER, staticBuffer->getBuffer());
}
else if (type == TYPE_STREAM)
{
@@ -467,14 +524,14 @@ void Source::playAtomic()
for (unsigned int i = 0; i < MAX_BUFFERS; i++)
{
streamAtomic(buffers[i], decoder);
streamAtomic(streamBuffers[i], decoder);
++usedBuffers;
if (decoder->isFinished())
break;
}
if (usedBuffers > 0)
alSourceQueueBuffers(source, usedBuffers, buffers);
alSourceQueueBuffers(source, usedBuffers, streamBuffers);
}
// This Source may now be associated with an OpenAL source that still has
+26 -2
View File
@@ -47,14 +47,35 @@ namespace openal
class Audio;
class Pool;
// Basically just a reference-counted non-streaming OpenAL buffer object.
class StaticDataBuffer : public love::Object
{
public:
StaticDataBuffer(ALenum format, const ALvoid *data, ALsizei size, ALsizei freq);
virtual ~StaticDataBuffer();
inline ALuint getBuffer() const
{
return buffer;
}
private:
ALuint buffer;
}; // StaticDataBuffer
class Source : public love::audio::Source
{
public:
Source(Pool *pool, love::sound::SoundData *soundData);
Source(Pool *pool, love::sound::Decoder *decoder);
Source(Source *s);
virtual ~Source();
virtual love::audio::Source *copy();
virtual love::audio::Source *clone();
virtual void play();
virtual void stop();
virtual void pause();
@@ -123,8 +144,11 @@ private:
Pool *pool;
ALuint source;
bool valid;
static const unsigned int MAX_BUFFERS = 32;
ALuint buffers[MAX_BUFFERS];
ALuint streamBuffers[MAX_BUFFERS];
StaticDataBuffer *staticBuffer;
float pitch;
float volume;