Merged in rcoaxil/love-audio/minor (pull request #91)

Effects re-made to operate on literal names instead of numerical indices.

--HG--
branch : minor
This commit is contained in:
Alex Szpakowski
2017-07-10 00:32:41 +00:00
12 changed files with 433 additions and 277 deletions
+14 -7
View File
@@ -77,7 +77,7 @@ public:
virtual Source *newSource(love::sound::Decoder *decoder) = 0;
virtual Source *newSource(love::sound::SoundData *soundData) = 0;
virtual Source *newSource(int sampleRate, int bitDepth, int channels) = 0;
virtual Source *newSource(int sampleRate, int bitDepth, int channels, int buffers) = 0;
/**
* Gets the current number of simultaneous playing sources.
@@ -210,26 +210,33 @@ public:
/**
* Sets scene EFX effect.
* @param slot Slot to put effect into.
* @param name Effect name to use.
* @param fxparams Effect description table.
* @return true if successful, false otherwise.
*/
virtual bool setSceneEffect(int slot, std::map<Effect::Parameter, float> &params) = 0;
virtual bool setEffect(const char *name, std::map<Effect::Parameter, float> &params) = 0;
/**
* Removes scene EFX effect.
* @param slot Effect slot to clear.
* @param name Effect name to clear.
* @return true if successful, false otherwise.
*/
virtual bool setSceneEffect(int slot) = 0;
virtual bool unsetEffect(const char *name) = 0;
/**
* Gets scene EFX effect.
* @param slot Slot from which to get effect.
* @param name Effect name to get data from.
* @param fxparams Effect description table.
* @return true if effect was present, false otherwise.
*/
virtual bool getSceneEffect(int slot, std::map<Effect::Parameter, float> &params) = 0;
virtual bool getEffect(const char *name, std::map<Effect::Parameter, float> &params) = 0;
/**
* Gets list of EFX effect names.
* @param list List of EFX names to fill.
* @return true if effect was present, false otherwise.
*/
virtual bool getEffectsList(std::vector<std::string> &list) = 0;
/**
* Gets maximum number of scene EFX effects.
+5 -4
View File
@@ -113,10 +113,11 @@ public:
virtual bool setFilter() = 0;
virtual bool getFilter(std::map<Filter::Parameter, float> &params) = 0;
virtual bool setSceneEffect(int slot, int effect) = 0;
virtual bool setSceneEffect(int slot, int effect, const std::map<Filter::Parameter, float> &params) = 0;
virtual bool setSceneEffect(int slot) = 0;
virtual bool getSceneEffect(int slot, int &effect, std::map<Filter::Parameter, float> &params) = 0;
virtual bool setEffect(const char *effect) = 0;
virtual bool setEffect(const char *effect, const std::map<Filter::Parameter, float> &params) = 0;
virtual bool unsetEffect(const char *effect) = 0;
virtual bool getEffect(const char *effect, std::map<Filter::Parameter, float> &params) = 0;
virtual bool getEffectsList(std::vector<std::string> &list) = 0;
virtual int getFreeBufferCount() const = 0;
virtual bool queue(void *data, size_t length, int dataSampleRate, int dataBitDepth, int dataChannels) = 0;
+9 -4
View File
@@ -51,7 +51,7 @@ love::audio::Source *Audio::newSource(love::sound::SoundData *)
return new Source();
}
love::audio::Source *Audio::newSource(int, int, int)
love::audio::Source *Audio::newSource(int, int, int, int)
{
return new Source();
}
@@ -168,17 +168,22 @@ void Audio::setDistanceModel(DistanceModel distanceModel)
this->distanceModel = distanceModel;
}
bool Audio::setSceneEffect(int, std::map<Effect::Parameter, float> &)
bool Audio::setEffect(const char *, std::map<Effect::Parameter, float> &)
{
return false;
}
bool Audio::setSceneEffect(int)
bool Audio::unsetEffect(const char *)
{
return false;
}
bool Audio::getSceneEffect(int, std::map<Effect::Parameter, float> &)
bool Audio::getEffect(const char *, std::map<Effect::Parameter, float> &)
{
return false;
}
bool Audio::getEffectsList(std::vector<std::string> &list)
{
return false;
}
+5 -4
View File
@@ -47,7 +47,7 @@ public:
// Implements Audio.
love::audio::Source *newSource(love::sound::Decoder *decoder);
love::audio::Source *newSource(love::sound::SoundData *soundData);
love::audio::Source *newSource(int sampleRate, int bitDepth, int channels);
love::audio::Source *newSource(int sampleRate, int bitDepth, int channels, int buffers);
int getSourceCount() const;
int getMaxSources() const;
bool play(love::audio::Source *source);
@@ -78,9 +78,10 @@ public:
DistanceModel getDistanceModel() const;
void setDistanceModel(DistanceModel distanceModel);
bool setSceneEffect(int slot, std::map<Effect::Parameter, float> &params);
bool setSceneEffect(int slot);
bool getSceneEffect(int slot, std::map<Effect::Parameter, float> &params);
bool setEffect(const char *, std::map<Effect::Parameter, float> &params);
bool unsetEffect(const char *);
bool getEffect(const char *, std::map<Effect::Parameter, float> &params);
bool getEffectsList(std::vector<std::string> &list);
int getMaxSceneEffects() const;
int getMaxSourceEffects() const;
bool isEFXsupported() const;
+9 -4
View File
@@ -254,22 +254,27 @@ bool Source::getFilter(std::map<Filter::Parameter, float> &)
return false;
}
bool Source::setSceneEffect(int, int)
bool Source::setEffect(const char *)
{
return false;
}
bool Source::setSceneEffect(int, int, const std::map<Filter::Parameter, float> &)
bool Source::setEffect(const char *, const std::map<Filter::Parameter, float> &)
{
return false;
}
bool Source::setSceneEffect(int)
bool Source::unsetEffect(const char *)
{
return false;
}
bool Source::getSceneEffect(int, int &, std::map<Filter::Parameter, float> &)
bool Source::getEffect(const char *, std::map<Filter::Parameter, float> &)
{
return false;
}
bool Source::getEffectsList(std::vector<std::string> &)
{
return false;
}
+5 -4
View File
@@ -86,10 +86,11 @@ public:
virtual bool setFilter();
virtual bool getFilter(std::map<Filter::Parameter, float> &params);
virtual bool setSceneEffect(int slot, int effect);
virtual bool setSceneEffect(int slot, int effect, const std::map<Filter::Parameter, float> &params);
virtual bool setSceneEffect(int slot);
virtual bool getSceneEffect(int slot, int &effect, std::map<Filter::Parameter, float> &params);
virtual bool setEffect(const char *effect);
virtual bool setEffect(const char *effect, const std::map<Filter::Parameter, float> &params);
virtual bool unsetEffect(const char *effect);
virtual bool getEffect(const char *effect, std::map<Filter::Parameter, float> &params);
virtual bool getEffectsList(std::vector<std::string> &list);
private:
+74 -46
View File
@@ -138,11 +138,7 @@ Audio::Audio()
ALuint slot;
alGenAuxiliaryEffectSlots(1, &slot);
if (alGetError() == AL_NO_ERROR)
{
effectIndex[slot] = effectSlots.size();
effectSlots.push_back(slot);
effects.push_back(nullptr);
}
slotlist.push(slot);
else
{
MAX_SCENE_EFFECTS = i;
@@ -168,8 +164,11 @@ Audio::Audio()
#ifdef ALC_EXT_EFX
if (alDeleteAuxiliaryEffectSlots)
{
for (auto slot : effectSlots)
alDeleteAuxiliaryEffectSlots(1, &slot);
while (!slotlist.empty())
{
alDeleteAuxiliaryEffectSlots(1, &slotlist.top());
slotlist.pop();
}
}
#endif
@@ -195,16 +194,19 @@ Audio::~Audio()
delete c;
#ifdef ALC_EXT_EFX
for (auto e : effects)
for (auto e : effectmap)
{
if (e != nullptr)
delete e;
delete e.second.effect;
slotlist.push(e.second.slot);
}
if (alDeleteAuxiliaryEffectSlots)
{
for (auto slot : effectSlots)
alDeleteAuxiliaryEffectSlots(1, &slot);
while (!slotlist.empty())
{
alDeleteAuxiliaryEffectSlots(1, &slotlist.top());
slotlist.pop();
}
}
#endif
alcMakeContextCurrent(nullptr);
@@ -227,9 +229,9 @@ love::audio::Source *Audio::newSource(love::sound::SoundData *soundData)
return new Source(pool, soundData);
}
love::audio::Source *Audio::newSource(int sampleRate, int bitDepth, int channels)
love::audio::Source *Audio::newSource(int sampleRate, int bitDepth, int channels, int buffers)
{
return new Source(pool, sampleRate, bitDepth, channels);
return new Source(pool, sampleRate, bitDepth, channels, buffers);
}
int Audio::getSourceCount() const
@@ -465,27 +467,44 @@ const std::vector<love::audio::RecordingDevice*> &Audio::getRecordingDevices()
return capture;
}
bool Audio::setSceneEffect(int slot, std::map<Effect::Parameter, float> &params)
bool Audio::setEffect(const char *name, std::map<Effect::Parameter, float> &params)
{
if (slot < 0 || slot >= MAX_SCENE_EFFECTS)
return false;
Effect *effect;
ALuint slot;
if (!effects[slot])
effects[slot] = new Effect();
auto iter = effectmap.find(name);
if (iter == effectmap.end())
{
//new effect needed but no more slots
if (effectmap.size() >= (unsigned int)MAX_SCENE_EFFECTS)
return false;
bool result = effects[slot]->setParams(params);
effect = new Effect();
slot = slotlist.top();
slotlist.pop();
effectmap[name] = {effect, slot};
}
else
{
effect = iter->second.effect;
slot = iter->second.slot;
}
bool result = effect->setParams(params);
#ifdef ALC_EXT_EFX
if (alAuxiliaryEffectSloti)
{
if (result)
{
if (params.find(Effect::EFFECT_VOLUME) != params.end())
alAuxiliaryEffectSlotf(effectSlots[slot], AL_EFFECTSLOT_GAIN, params[Effect::EFFECT_VOLUME]);
alAuxiliaryEffectSloti(effectSlots[slot], AL_EFFECTSLOT_EFFECT, effects[slot]->getEffect());
auto iter = params.find(Effect::EFFECT_VOLUME);
if (iter != params.end())
alAuxiliaryEffectSlotf(slot, AL_EFFECTSLOT_GAIN, iter->second);
alAuxiliaryEffectSloti(slot, AL_EFFECTSLOT_EFFECT, effect->getEffect());
}
else
alAuxiliaryEffectSloti(effectSlots[slot], AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
alAuxiliaryEffectSloti(slot, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
alGetError();
}
#endif
@@ -493,33 +512,45 @@ bool Audio::setSceneEffect(int slot, std::map<Effect::Parameter, float> &params)
return result;
}
bool Audio::setSceneEffect(int slot)
bool Audio::unsetEffect(const char *name)
{
if (slot < 0 || slot >= MAX_SCENE_EFFECTS)
auto iter = effectmap.find(name);
if (iter == effectmap.end())
return false;
if (effects[slot])
delete effects[slot];
effects[slot] = nullptr;
Effect *effect = iter->second.effect;
ALuint slot = iter->second.slot;
#ifdef ALC_EXT_EFX
if (alAuxiliaryEffectSloti)
alAuxiliaryEffectSloti(effectSlots[slot], AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
alAuxiliaryEffectSloti(slot, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
#endif
delete effect;
effectmap.erase(iter);
slotlist.push(slot);
return true;
}
bool Audio::getEffect(const char *name, std::map<Effect::Parameter, float> &params)
{
auto iter = effectmap.find(name);
if (iter == effectmap.end())
return false;
params = iter->second.effect->getParams();
return true;
}
bool Audio::getSceneEffect(int slot, std::map<Effect::Parameter, float> &params)
bool Audio::getEffectsList(std::vector<std::string> &list)
{
if (slot < 0 || slot >= MAX_SCENE_EFFECTS)
if (effectmap.empty())
return false;
if (!effects[slot])
return false;
params = effects[slot]->getParams();
list.reserve(effectmap.size());
for (auto i : effectmap)
list.push_back(i.first);
return true;
}
@@ -543,17 +574,14 @@ bool Audio::isEFXsupported() const
#endif
}
ALuint Audio::getSceneEffectID(int slot)
bool Audio::getEffectID(const char *name, ALuint &id)
{
if (slot < 0 || slot >= MAX_SCENE_EFFECTS)
return effectSlots[0];
auto iter = effectmap.find(name);
if (iter == effectmap.end())
return false;
return effectSlots[slot];
}
int Audio::getSceneEffectIndex(ALuint effect)
{
return effectIndex[effect];
id = iter->second.slot;
return true;
}
#ifdef ALC_EXT_EFX
+16 -11
View File
@@ -25,6 +25,7 @@
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <cmath>
// LOVE
@@ -83,7 +84,7 @@ public:
// Implements Audio.
love::audio::Source *newSource(love::sound::Decoder *decoder);
love::audio::Source *newSource(love::sound::SoundData *soundData);
love::audio::Source *newSource(int sampleRate, int bitDepth, int channels);
love::audio::Source *newSource(int sampleRate, int bitDepth, int channels, int buffers);
int getSourceCount() const;
int getMaxSources() const;
bool play(love::audio::Source *source);
@@ -114,15 +115,15 @@ public:
DistanceModel getDistanceModel() const;
void setDistanceModel(DistanceModel distanceModel);
bool setSceneEffect(int slot, std::map<Effect::Parameter, float> &params);
bool setSceneEffect(int slot);
bool getSceneEffect(int slot, std::map<Effect::Parameter, float> &params);
bool setEffect(const char *name, std::map<Effect::Parameter, float> &params);
bool unsetEffect(const char *name);
bool getEffect(const char *name, std::map<Effect::Parameter, float> &params);
bool getEffectsList(std::vector<std::string> &list);
int getMaxSceneEffects() const;
int getMaxSourceEffects() const;
bool isEFXsupported() const;
ALuint getSceneEffectID(int slot);
int getSceneEffectIndex(ALuint effect);
bool getEffectID(const char *name, ALuint &id);
private:
void initializeEFX();
@@ -136,11 +137,15 @@ private:
ALCcontext *context;
// The OpenAL effects
std::vector<Effect*> effects;
std::vector<ALuint> effectSlots;
std::map<ALuint, int> effectIndex;
int MAX_SCENE_EFFECTS = 16;
int MAX_SOURCE_EFFECTS = 16;
struct EffectMapStorage
{
Effect *effect;
ALuint slot;
};
std::map<std::string, struct EffectMapStorage> effectmap;
std::stack<ALuint> slotlist;
int MAX_SCENE_EFFECTS = 64;
int MAX_SOURCE_EFFECTS = 64;
// The Pool.
Pool *pool;
+213 -140
View File
@@ -124,8 +124,6 @@ Source::Source(Pool *pool, love::sound::SoundData *soundData)
, sampleRate(soundData->getSampleRate())
, channels(soundData->getChannels())
, bitDepth(soundData->getBitDepth())
, sendfilters(audiomodule()->getMaxSourceEffects(), nullptr)
, sendtargets(audiomodule()->getMaxSourceEffects(), AL_EFFECTSLOT_NULL)
{
ALenum fmt = Audio::getFormat(soundData->getBitDepth(), soundData->getChannels());
if (fmt == AL_NONE)
@@ -138,6 +136,9 @@ Source::Source(Pool *pool, love::sound::SoundData *soundData)
setFloatv(position, z);
setFloatv(velocity, z);
setFloatv(direction, z);
for (unsigned int i = 0; i < (unsigned int)audiomodule()->getMaxSourceEffects(); i++)
slotlist.push(i);
}
Source::Source(Pool *pool, love::sound::Decoder *decoder)
@@ -147,46 +148,72 @@ Source::Source(Pool *pool, love::sound::Decoder *decoder)
, channels(decoder->getChannels())
, bitDepth(decoder->getBitDepth())
, decoder(decoder)
, unusedBufferTop(MAX_BUFFERS - 1)
, sendfilters(audiomodule()->getMaxSourceEffects(), nullptr)
, sendtargets(audiomodule()->getMaxSourceEffects(), AL_EFFECTSLOT_NULL)
, buffers(DEFAULT_BUFFERS)
{
if (Audio::getFormat(decoder->getBitDepth(), decoder->getChannels()) == AL_NONE)
throw InvalidFormatException(decoder->getChannels(), decoder->getBitDepth());
alGenBuffers(MAX_BUFFERS, streamBuffers);
for (unsigned int i = 0; i < MAX_BUFFERS; i++)
unusedBuffers[i] = streamBuffers[i];
for (int i = 0; i < buffers; i++)
{
ALuint buf;
alGenBuffers(1, &buf);
if (alGetError() == AL_NO_ERROR)
unusedBuffers.push(buf);
else
{
buffers = i;
break;
}
}
float z[3] = {0, 0, 0};
setFloatv(position, z);
setFloatv(velocity, z);
setFloatv(direction, z);
for (unsigned int i = 0; i < (unsigned int)audiomodule()->getMaxSourceEffects(); i++)
slotlist.push(i);
}
Source::Source(Pool *pool, int sampleRate, int bitDepth, int channels)
Source::Source(Pool *pool, int sampleRate, int bitDepth, int channels, int buffers)
: love::audio::Source(Source::TYPE_QUEUE)
, pool(pool)
, sampleRate(sampleRate)
, channels(channels)
, bitDepth(bitDepth)
, sendfilters(audiomodule()->getMaxSourceEffects(), nullptr)
, sendtargets(audiomodule()->getMaxSourceEffects(), AL_EFFECTSLOT_NULL)
, buffers(buffers)
{
ALenum fmt = Audio::getFormat(bitDepth, channels);
if (fmt == AL_NONE)
throw InvalidFormatException(channels, bitDepth);
alGenBuffers(MAX_BUFFERS, streamBuffers);
for (unsigned int i = 0; i < MAX_BUFFERS; i++)
unusedBuffers[i] = streamBuffers[i];
if (buffers < 1)
buffers = DEFAULT_BUFFERS;
if (buffers > MAX_BUFFERS)
buffers = MAX_BUFFERS;
for (int i = 0; i < buffers; i++)
{
ALuint buf;
alGenBuffers(1, &buf);
if (alGetError() == AL_NO_ERROR)
unusedBuffers.push(buf);
else
{
buffers = i;
break;
}
}
float z[3] = {0, 0, 0};
setFloatv(position, z);
setFloatv(velocity, z);
setFloatv(direction, z);
for (unsigned int i = 0; i < (unsigned int)audiomodule()->getMaxSourceEffects(); i++)
slotlist.push(i);
}
Source::Source(const Source &s)
@@ -211,9 +238,7 @@ Source::Source(const Source &s)
, bitDepth(s.bitDepth)
, decoder(nullptr)
, toLoop(0)
, unusedBufferTop(s.sourceType == TYPE_STREAM ? MAX_BUFFERS - 1 : -1)
, sendfilters(s.sendfilters)
, sendtargets(s.sendtargets)
, buffers(s.buffers)
{
if (sourceType == TYPE_STREAM)
{
@@ -222,16 +247,43 @@ Source::Source(const Source &s)
}
if (sourceType != TYPE_STATIC)
{
alGenBuffers(MAX_BUFFERS, streamBuffers);
for (unsigned int i = 0; i < MAX_BUFFERS; i++)
unusedBuffers[i] = streamBuffers[i];
for (int i = 0; i < buffers; i++)
{
ALuint buf;
alGenBuffers(1, &buf);
if (alGetError() == AL_NO_ERROR)
unusedBuffers.push(buf);
else
{
buffers = i;
break;
}
}
}
if (s.directfilter)
directfilter = s.directfilter->clone();
for (auto e : s.effectmap)
effectmap[e.first] = { e.second.filter ? e.second.filter->clone() : nullptr, e.second.slot, e.second.target };
setFloatv(position, s.position);
setFloatv(velocity, s.velocity);
setFloatv(direction, s.direction);
for (unsigned int i = 0; i < (unsigned int)audiomodule()->getMaxSourceEffects(); i++)
{
// filter out already taken slots
bool push = true;
for (auto e : effectmap)
{
if (e.second.slot)
push = false;
break;
}
if (push)
slotlist.push(i);
}
}
Source::~Source()
@@ -239,15 +291,26 @@ Source::~Source()
stop();
if (sourceType != TYPE_STATIC)
alDeleteBuffers(MAX_BUFFERS, streamBuffers);
{
while (!streamBuffers.empty())
{
alDeleteBuffers(1, &streamBuffers.front());
streamBuffers.pop();
}
while (!unusedBuffers.empty())
{
alDeleteBuffers(1, &unusedBuffers.top());
unusedBuffers.pop();
}
}
if (directfilter)
delete directfilter;
for (auto sf : sendfilters)
for (auto e : effectmap)
{
if (sf != nullptr)
delete sf;
if (e.second.filter)
delete e.second.filter;
}
}
@@ -346,12 +409,16 @@ bool Source::update()
offsetSeconds += (curOffsetSecs - newOffsetSecs);
for (unsigned int i = 0; i < (unsigned int)processed; i++)
unusedBufferPush(buffers[i]);
unusedBuffers.push(buffers[i]);
while (unusedBufferPeek() != AL_NONE)
while (!unusedBuffers.empty())
{
if(streamAtomic(unusedBufferPeek(), decoder.get()) > 0)
alSourceQueueBuffers(source, 1, unusedBufferPop());
auto b = unusedBuffers.top();
if (streamAtomic(b, decoder.get()) > 0)
{
alSourceQueueBuffers(source, 1, &b);
unusedBuffers.pop();
}
else
break;
}
@@ -359,7 +426,7 @@ bool Source::update()
return true;
}
return false;
case TYPE_QUEUE:
case TYPE_QUEUE:
{
ALint processed;
ALuint buffers[MAX_BUFFERS];
@@ -372,7 +439,7 @@ bool Source::update()
ALint size;
alGetBufferi(buffers[i], AL_SIZE, &size);
bufferedBytes -= size;
unusedBufferPush(buffers[i]);
unusedBuffers.push(buffers[i]);
}
return !isFinished();
}
@@ -475,23 +542,21 @@ void Source::seek(float offset, Source::Unit unit)
}
else
{
ALint size;
ALuint buffer = unusedBufferPeek();
//emulate AL behavior, discarding buffer once playback head is past one
while (buffer != AL_NONE)
while (!unusedBuffers.empty())
{
ALint size;
auto buffer = unusedBuffers.top();
alGetBufferi(buffer, AL_SIZE, &size);
if (offsetSamples < size / (bitDepth / 8 * channels))
break;
unusedBufferPop();
buffer = unusedBufferPeek();
unusedBuffers.pop();
bufferedBytes -= size;
offsetSamples -= size / (bitDepth / 8 * channels);
}
if (buffer == AL_NONE)
if (unusedBuffers.empty())
offsetSamples = 0;
offsetSeconds = offsetSamples / sampleRate;
}
@@ -723,28 +788,19 @@ bool Source::queue(void *data, size_t length, int dataSampleRate, int dataBitDep
Lock l = pool->lock();
if (valid)
{
ALuint buffer = unusedBufferPeek();
if (buffer == AL_NONE)
return false;
if (unusedBuffers.empty())
return false;
alBufferData(buffer, Audio::getFormat(bitDepth, channels), data, length, sampleRate);
alSourceQueueBuffers(source, 1, &buffer);
unusedBufferPop();
}
else
{
ALuint buffer = unusedBufferPeekNext();
if (buffer == AL_NONE)
return false;
//stack acts as queue while stopped
alBufferData(buffer, Audio::getFormat(bitDepth, channels), data, length, sampleRate);
unusedBufferQueue(buffer);
}
auto buffer = unusedBuffers.top();
unusedBuffers.pop();
alBufferData(buffer, Audio::getFormat(bitDepth, channels), data, length, sampleRate);
bufferedBytes += length;
if (valid)
alSourceQueueBuffers(source, 1, &buffer);
else
streamBuffers.push(buffer);
return true;
}
@@ -755,9 +811,9 @@ int Source::getFreeBufferCount() const
case TYPE_STATIC:
return 0;
case TYPE_STREAM:
return unusedBufferTop + 1;
return unusedBuffers.size();
case TYPE_QUEUE:
return valid ? unusedBufferTop + 1 : (int)MAX_BUFFERS - unusedBufferTop - 1;
return unusedBuffers.size();
case TYPE_MAX_ENUM:
return 0;
}
@@ -777,12 +833,14 @@ void Source::prepareAtomic()
alSourcei(source, AL_BUFFER, staticBuffer->getBuffer());
break;
case TYPE_STREAM:
while (unusedBufferPeek() != AL_NONE)
while (!unusedBuffers.empty())
{
if(streamAtomic(unusedBufferPeek(), decoder.get()) == 0)
auto b = unusedBuffers.top();
if (streamAtomic(b, decoder.get()) == 0)
break;
alSourceQueueBuffers(source, 1, unusedBufferPop());
alSourceQueueBuffers(source, 1, &b);
unusedBuffers.pop();
if (decoder->isFinished())
break;
@@ -790,14 +848,11 @@ void Source::prepareAtomic()
break;
case TYPE_QUEUE:
{
int top = unusedBufferTop;
//when queue source is stopped, loaded buffers are stored in unused buffers stack
while (unusedBufferPeek() != AL_NONE)
alSourceQueueBuffers(source, 1, unusedBufferPop());
//construct a stack of unused buffers (beyond the end of stack)
for (unsigned int i = top + 1; i < MAX_BUFFERS; i++)
unusedBufferPush(unusedBuffers[i]);
while (!streamBuffers.empty())
{
alSourceQueueBuffers(source, 1, &streamBuffers.front());
streamBuffers.pop();
}
break;
}
case TYPE_MAX_ENUM:
@@ -821,13 +876,10 @@ void Source::teardownAtomic()
//since we only unqueue 1 buffer, it's OK to use singular variable pointer instead of array
alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
for (unsigned int i = 0; i < (unsigned int)queued; i++)
{
alSourceUnqueueBuffers(source, 1, &buffer);
// generate unused buffers list
for (unsigned int i = 0; i < MAX_BUFFERS; i++)
unusedBuffers[i] = streamBuffers[i];
unusedBufferTop = MAX_BUFFERS - 1;
unusedBuffers.push(buffer);
}
break;
}
case TYPE_QUEUE:
@@ -837,13 +889,10 @@ void Source::teardownAtomic()
alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
for (unsigned int i = (unsigned int)queued; i > 0; i--)
{
alSourceUnqueueBuffers(source, 1, &buffer);
// generate unused buffers list
for (unsigned int i = 0; i < MAX_BUFFERS; i++)
unusedBuffers[i] = streamBuffers[i];
unusedBufferTop = -1;
unusedBuffers.push(buffer);
}
break;
}
case TYPE_MAX_ENUM:
@@ -912,7 +961,8 @@ void Source::resumeAtomic()
{
alSourcePlay(source);
if (alGetError() == AL_INVALID_VALUE || (sourceType == TYPE_STREAM && unusedBufferTop == MAX_BUFFERS - 1))
//failed to play or nothing to play
if (alGetError() == AL_INVALID_VALUE || (sourceType == TYPE_STREAM && unusedBuffers.empty()))
stop();
}
}
@@ -1059,8 +1109,11 @@ void Source::reset()
alSourcef(source, AL_CONE_OUTER_GAINHF, cone.outerHighGain);
alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, rolloffFactor); //reverb-specific rolloff
alSourcei(source, AL_DIRECT_FILTER, directfilter ? directfilter->getFilter() : AL_FILTER_NULL);
for (unsigned int i = 0; i < sendtargets.size(); i++)
alSource3i(source, AL_AUXILIARY_SEND_FILTER, sendtargets[i], i, sendfilters[i] ? sendfilters[i]->getFilter() : AL_FILTER_NULL);
// clear all send slots, then re-enable applied ones
for (int i = 0; i < audiomodule()->getMaxSourceEffects(); i++)
alSource3i(source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, i, AL_FILTER_NULL);
for (auto i : effectmap)
alSource3i(source, AL_AUXILIARY_SEND_FILTER, i.second.target, i.second.slot, i.second.filter ? i.second.filter->getFilter() : AL_FILTER_NULL);
//alGetError();
#endif
}
@@ -1072,33 +1125,6 @@ void Source::setFloatv(float *dst, const float *src) const
dst[2] = src[2];
}
ALuint Source::unusedBufferPeek()
{
return (unusedBufferTop < 0) ? AL_NONE : unusedBuffers[unusedBufferTop];
}
ALuint Source::unusedBufferPeekNext()
{
return (unusedBufferTop >= (int)MAX_BUFFERS - 1) ? AL_NONE : unusedBuffers[unusedBufferTop + 1];
}
ALuint *Source::unusedBufferPop()
{
return &unusedBuffers[unusedBufferTop--];
}
void Source::unusedBufferPush(ALuint buffer)
{
unusedBuffers[++unusedBufferTop] = buffer;
}
void Source::unusedBufferQueue(ALuint buffer)
{
for (unsigned int i = ++unusedBufferTop; i > 0; i--)
unusedBuffers[i] = unusedBuffers[i - 1];
unusedBuffers[0] = buffer;
}
int Source::streamAtomic(ALuint buffer, love::sound::Decoder *d)
{
// Get more sound data.
@@ -1123,7 +1149,7 @@ int Source::streamAtomic(ALuint buffer, love::sound::Decoder *d)
if (queued > processed)
toLoop = queued-processed;
else
toLoop = MAX_BUFFERS-processed;
toLoop = buffers-processed;
d->rewind();
}
@@ -1339,22 +1365,39 @@ bool Source::getFilter(std::map<Filter::Parameter, float> &params)
return true;
}
bool Source::setSceneEffect(int slot, int effect)
bool Source::setEffect(const char *name)
{
if (slot < 0 || slot >= (int)sendtargets.size())
ALuint slot, target;
Filter *filter;
// effect with this name doesn't exist
if (!dynamic_cast<Audio*>(audiomodule())->getEffectID(name, target))
return false;
sendtargets[slot] = dynamic_cast<Audio*>(audiomodule())->getSceneEffectID(effect);
auto iter = effectmap.find(name);
if (iter == effectmap.end())
{
// new send target needed but no more room
if (slotlist.empty())
return false;
if (sendfilters[slot])
delete sendfilters[slot];
slot = slotlist.top();
slotlist.pop();
}
else
{
slot = iter->second.slot;
filter = iter->second.filter;
sendfilters[slot] = nullptr;
if (filter)
delete filter;
}
effectmap[name] = {nullptr, slot, target};
#ifdef ALC_EXT_EFX
if (valid)
{
alSource3i(source, AL_AUXILIARY_SEND_FILTER, sendtargets[slot], slot, AL_FILTER_NULL);
alSource3i(source, AL_AUXILIARY_SEND_FILTER, target, slot, AL_FILTER_NULL);
//alGetError();
}
#endif
@@ -1362,39 +1405,59 @@ bool Source::setSceneEffect(int slot, int effect)
return true;
}
bool Source::setSceneEffect(int slot, int effect, const std::map<Filter::Parameter, float> &params)
bool Source::setEffect(const char *name, const std::map<Filter::Parameter, float> &params)
{
if (slot < 0 || slot >= (int)sendtargets.size())
ALuint slot, target;
Filter *filter;
// effect with this name doesn't exist
if (!dynamic_cast<Audio*>(audiomodule())->getEffectID(name, target))
return false;
sendtargets[slot] = dynamic_cast<Audio*>(audiomodule())->getSceneEffectID(effect);
auto iter = effectmap.find(name);
if (iter == effectmap.end())
{
// new send target needed but no more room
if (slotlist.empty())
return false;
if (!sendfilters[slot])
sendfilters[slot] = new Filter();
slot = slotlist.top();
slotlist.pop();
}
else
{
slot = iter->second.slot;
filter = iter->second.filter;
}
if (!filter)
filter = new Filter();
sendfilters[slot]->setParams(params);
effectmap[name] = {filter, slot, target};
filter->setParams(params);
#ifdef ALC_EXT_EFX
if (valid)
{
//in case of failure contains AL_FILTER_NULL, a valid non-filter
alSource3i(source, AL_AUXILIARY_SEND_FILTER, sendtargets[slot], slot, sendfilters[slot]->getFilter());
alSource3i(source, AL_AUXILIARY_SEND_FILTER, target, slot, filter->getFilter());
//alGetError();
}
#endif
return true;
}
bool Source::setSceneEffect(int slot)
bool Source::unsetEffect(const char *name)
{
if (slot < 0 || slot >= (int)sendtargets.size())
auto iter = effectmap.find(name);
if (iter == effectmap.end())
return false;
sendtargets[slot] = AL_EFFECTSLOT_NULL;
ALuint slot = iter->second.slot;
Filter *filter = iter->second.filter;
if (sendfilters[slot])
delete sendfilters[slot];
sendfilters[slot] = nullptr;
if (filter)
delete filter;
#ifdef ALC_EXT_EFX
if (valid)
@@ -1403,22 +1466,32 @@ bool Source::setSceneEffect(int slot)
//alGetError();
}
#endif
effectmap.erase(iter);
slotlist.push(slot);
return true;
}
bool Source::getEffect(const char *name, std::map<Filter::Parameter, float> &params)
{
auto iter = effectmap.find(name);
if (iter == effectmap.end())
return false;
if (iter->second.filter)
params = iter->second.filter->getParams();
return true;
}
bool Source::getSceneEffect(int slot, int &effect, std::map<Filter::Parameter, float> &params)
bool Source::getEffectsList(std::vector<std::string> &list)
{
if (slot < 0 || slot >= (int)sendtargets.size())
if (effectmap.empty())
return false;
if (sendtargets[slot] == AL_EFFECTSLOT_NULL)
return false;
list.reserve(effectmap.size());
effect = dynamic_cast<Audio*>(audiomodule())->getSceneEffectIndex(sendtargets[slot]);
if(sendfilters[slot])
params = sendfilters[slot]->getParams();
for (auto i : effectmap)
list.push_back(i.first);
return true;
}
+20 -17
View File
@@ -33,6 +33,7 @@
// STL
#include <vector>
#include <stack>
// C
#include <float.h>
@@ -99,7 +100,7 @@ public:
Source(Pool *pool, love::sound::SoundData *soundData);
Source(Pool *pool, love::sound::Decoder *decoder);
Source(Pool *pool, int sampleRate, int bitDepth, int channels);
Source(Pool *pool, int sampleRate, int bitDepth, int channels, int buffers);
Source(const Source &s);
virtual ~Source();
@@ -147,10 +148,11 @@ public:
virtual bool setFilter();
virtual bool getFilter(std::map<Filter::Parameter, float> &params);
virtual bool setSceneEffect(int slot, int effect);
virtual bool setSceneEffect(int slot, int effect, const std::map<Filter::Parameter, float> &params);
virtual bool setSceneEffect(int slot);
virtual bool getSceneEffect(int slot, int &effect, std::map<Filter::Parameter, float> &params);
virtual bool setEffect(const char *effect);
virtual bool setEffect(const char *effect, const std::map<Filter::Parameter, float> &params);
virtual bool unsetEffect(const char *effect);
virtual bool getEffect(const char *effect, std::map<Filter::Parameter, float> &params);
virtual bool getEffectsList(std::vector<std::string> &list);
virtual int getFreeBufferCount() const;
virtual bool queue(void *data, size_t length, int dataSampleRate, int dataBitDepth, int dataChannels);
@@ -178,19 +180,14 @@ private:
int streamAtomic(ALuint buffer, love::sound::Decoder *d);
ALuint unusedBufferPeek();
ALuint unusedBufferPeekNext();
ALuint *unusedBufferPop();
void unusedBufferPush(ALuint buffer);
void unusedBufferQueue(ALuint buffer);
Pool *pool = nullptr;
ALuint source = 0;
bool valid = false;
static const unsigned int MAX_BUFFERS = 8;
ALuint streamBuffers[MAX_BUFFERS];
ALuint unusedBuffers[MAX_BUFFERS];
const static int DEFAULT_BUFFERS = 8;
const static int MAX_BUFFERS = 64;
std::queue<ALuint> streamBuffers;
std::stack<ALuint> unusedBuffers;
StrongRef<StaticDataBuffer> staticBuffer;
@@ -226,12 +223,18 @@ private:
StrongRef<love::sound::Decoder> decoder;
unsigned int toLoop = 0;
int unusedBufferTop = -1;
ALsizei bufferedBytes = 0;
int buffers = 0;
Filter *directfilter = nullptr;
std::vector<Filter*> sendfilters;
std::vector<ALint> sendtargets;
struct EffectMapStorage
{
Filter *filter;
ALuint slot, target;
};
std::map<std::string, struct EffectMapStorage> effectmap;
std::stack<ALuint> slotlist;
}; // Source
} // openal
+30 -13
View File
@@ -84,7 +84,7 @@ int w_newQueueableSource(lua_State *L)
Source *t = nullptr;
luax_catchexcept(L, [&]() {
t = instance()->newSource((int)luaL_checknumber(L, 1), (int)luaL_checknumber(L, 2), (int)luaL_checknumber(L, 3));
t = instance()->newSource((int)luaL_checknumber(L, 1), (int)luaL_checknumber(L, 2), (int)luaL_checknumber(L, 3), (int)luaL_optnumber(L, 4, 0));
});
if (t != nullptr)
@@ -305,13 +305,13 @@ int w_getRecordingDevices(lua_State *L)
return 1;
}
int w_setSceneEffect(lua_State *L)
int w_setEffect(lua_State *L)
{
int slot = luaL_checknumber(L, 1) - 1;
const char *namestr = luaL_checkstring(L, 1);
if (lua_gettop(L) == 1 || (lua_gettop(L) == 2 && lua_isnoneornil(L, 2)))
if (lua_isnoneornil(L, 2) || (lua_gettop(L) == 2 && lua_isboolean(L, 2) && !lua_toboolean(L, 2)))
{
lua_pushboolean(L, instance()->setSceneEffect(slot));
lua_pushboolean(L, instance()->unsetEffect(namestr));
return 1;
}
@@ -405,17 +405,17 @@ int w_setSceneEffect(lua_State *L)
lua_pop(L, 1);
}
luax_catchexcept(L, [&]() { lua_pushboolean(L, instance()->setSceneEffect(slot, params)); });
luax_catchexcept(L, [&]() { lua_pushboolean(L, instance()->setEffect(namestr, params)); });
return 1;
}
int w_getSceneEffect(lua_State *L)
int w_getEffect(lua_State *L)
{
int slot = luaL_checknumber(L, 1) - 1;
const char *namestr = luaL_checkstring(L, 1);
std::map<Effect::Parameter, float> params;
if (!instance()->getSceneEffect(slot, params))
if (!instance()->getEffect(namestr, params))
return 0;
const char *keystr, *valstr;
@@ -463,6 +463,22 @@ int w_getSceneEffect(lua_State *L)
return 1;
}
int w_getEffectsList(lua_State *L)
{
std::vector<std::string> list;
if (!instance()->getEffectsList(list))
return 0;
lua_createtable(L, 0, list.size());
for (unsigned int i = 0; i < list.size(); i++)
{
lua_pushnumber(L, i + 1);
lua_pushstring(L, list[i].c_str());
lua_rawset(L, -3);
}
return 1;
}
int w_getMaxSceneEffects(lua_State *L)
{
lua_pushnumber(L, instance()->getMaxSceneEffects());
@@ -475,7 +491,7 @@ int w_getMaxSourceEffects(lua_State *L)
return 1;
}
int w_isSceneEffectsSupported(lua_State *L)
int w_isEffectsSupported(lua_State *L)
{
lua_pushboolean(L, instance()->isEFXsupported());
return 1;
@@ -505,11 +521,12 @@ static const luaL_Reg functions[] =
{ "setDistanceModel", w_setDistanceModel },
{ "getDistanceModel", w_getDistanceModel },
{ "getRecordingDevices", w_getRecordingDevices },
{ "setEffect", w_setSceneEffect },
{ "getEffect", w_getSceneEffect },
{ "setEffect", w_setEffect },
{ "getEffect", w_getEffect },
{ "getEffectsList", w_getEffectsList },
{ "getMaxSceneEffects", w_getMaxSceneEffects },
{ "getMaxSourceEffects", w_getMaxSourceEffects },
{ "isEffectsSupported", w_isSceneEffectsSupported },
{ "isEffectsSupported", w_isEffectsSupported },
{ 0, 0 }
};
+33 -23
View File
@@ -456,49 +456,58 @@ int w_Source_getFilter(lua_State *L)
return 1;
}
int w_Source_setSceneEffect(lua_State *L)
int w_Source_setEffect(lua_State *L)
{
Source *t = luax_checksource(L, 1);
const char *namestr = luaL_checkstring(L, 2);
int slot = luaL_checknumber(L, 2) - 1;
if (lua_gettop(L) == 2)
// :setEffect(effect, false) = clear effect
if (lua_gettop(L) == 3 && lua_isboolean(L, 3) && !lua_toboolean(L, 3))
{
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setSceneEffect(slot)); });
return 1;
}
int effect = luaL_checknumber(L, 3) - 1;
if (lua_gettop(L) == 3)
{
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setSceneEffect(slot, effect)); });
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->unsetEffect(namestr)); });
return 1;
}
std::map<Filter::Parameter, float> params;
if (setFilterReadFilter(L, 4, params) == 1)
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setSceneEffect(slot, effect, params)); });
if (setFilterReadFilter(L, 3, params) == 1)
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setEffect(namestr, params)); });
else
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setSceneEffect(slot, effect)); });
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setEffect(namestr)); });
return 1;
}
int w_Source_getSceneEffect(lua_State *L)
int w_Source_getEffect(lua_State *L)
{
Source *t = luax_checksource(L, 1);
int slot = luaL_checknumber(L, 2) - 1;
const char *namestr = luaL_checkstring(L, 2);
int effect;
std::map<Filter::Parameter, float> params;
if (!t->getSceneEffect(slot, effect, params))
if (!t->getEffect(namestr, params))
return 0;
lua_pushnumber(L, effect + 1);
if (params.size() == 0)
return 1;
return 0;
getFilterWriteFilter(L, params);
return 2;
return 1;
}
int w_Source_getEffectsList(lua_State *L)
{
Source *t = luax_checksource(L, 1);
std::vector<std::string> list;
if (!t->getEffectsList(list))
return 0;
lua_createtable(L, 0, list.size());
for (unsigned int i = 0; i < list.size(); i++)
{
lua_pushnumber(L, i + 1);
lua_pushstring(L, list[i].c_str());
lua_rawset(L, -3);
}
return 1;
}
int w_Source_getFreeBufferCount(lua_State *L)
@@ -613,8 +622,9 @@ static const luaL_Reg w_Source_functions[] =
{ "setFilter", w_Source_setFilter },
{ "getFilter", w_Source_getFilter },
{ "setEffect", w_Source_setSceneEffect },
{ "getEffect", w_Source_getSceneEffect },
{ "setEffect", w_Source_setEffect },
{ "getEffect", w_Source_getEffect },
{ "getEffectsList", w_Source_getEffectsList },
{ "getFreeBufferCount", w_Source_getFreeBufferCount },
{ "queue", w_Source_queue },