mirror of
https://github.com/love2d/love.git
synced 2026-08-14 10:13:46 +02:00
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:
@@ -51,7 +51,7 @@ public:
|
||||
Source(Type type);
|
||||
virtual ~Source();
|
||||
|
||||
virtual Source *copy() = 0;
|
||||
virtual Source *clone() = 0;
|
||||
|
||||
virtual void play() = 0;
|
||||
virtual void stop() = 0;
|
||||
|
||||
@@ -36,7 +36,7 @@ Source::~Source()
|
||||
{
|
||||
}
|
||||
|
||||
love::audio::Source *Source::copy()
|
||||
love::audio::Source *Source::clone()
|
||||
{
|
||||
this->retain();
|
||||
return this;
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
Source();
|
||||
virtual ~Source();
|
||||
|
||||
virtual love::audio::Source *copy();
|
||||
virtual love::audio::Source *clone();
|
||||
virtual void play();
|
||||
virtual void stop();
|
||||
virtual void pause();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -41,6 +41,15 @@ int w_getSourceCount(lua_State *L)
|
||||
|
||||
int w_newSource(lua_State *L)
|
||||
{
|
||||
if (luax_istype(L, 1, AUDIO_SOURCE_T))
|
||||
{
|
||||
Source *t = luax_checksource(L, 1);
|
||||
Source *clone = 0;
|
||||
EXCEPT_GUARD(clone = t->clone();)
|
||||
luax_pushtype(L, "Source", AUDIO_SOURCE_T, clone);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
|
||||
luax_convobj(L, 1, "filesystem", "newFileData");
|
||||
|
||||
|
||||
@@ -30,6 +30,15 @@ Source *luax_checksource(lua_State *L, int idx)
|
||||
return luax_checktype<Source>(L, idx, "Source", AUDIO_SOURCE_T);
|
||||
}
|
||||
|
||||
int w_Source_clone(lua_State *L)
|
||||
{
|
||||
Source *t = luax_checksource(L, 1);
|
||||
Source *clone = nullptr;
|
||||
EXCEPT_GUARD(clone = t->clone();)
|
||||
luax_pushtype(L, "Source", AUDIO_SOURCE_T, clone);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Source_play(lua_State *L)
|
||||
{
|
||||
Source *t = luax_checksource(L, 1);
|
||||
@@ -333,6 +342,8 @@ int w_Source_getChannels(lua_State *L)
|
||||
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "clone", w_Source_clone },
|
||||
|
||||
{ "play", w_Source_play },
|
||||
{ "stop", w_Source_stop },
|
||||
{ "pause", w_Source_pause },
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace audio
|
||||
{
|
||||
|
||||
Source *luax_checksource(lua_State *L, int idx);
|
||||
int w_Source_clone(lua_State *L);
|
||||
int w_Source_play(lua_State *L);
|
||||
int w_Source_stop(lua_State *L);
|
||||
int w_Source_pause(lua_State *L);
|
||||
|
||||
Reference in New Issue
Block a user