From 157d94fae3ac4375b8d1499958511853d0b682ff Mon Sep 17 00:00:00 2001 From: raidho36 Date: Thu, 22 Jun 2017 15:07:31 +0300 Subject: [PATCH 1/3] Effects re-made to operate on literal names instead of numerical indices. Added buffer count parameter to queueable source constructor. Added getEffectsList function. Internal cleanup. --HG-- branch : minor --- src/modules/audio/Audio.h | 21 +- src/modules/audio/Source.h | 9 +- src/modules/audio/null/Audio.cpp | 13 +- src/modules/audio/null/Audio.h | 9 +- src/modules/audio/null/Source.cpp | 13 +- src/modules/audio/null/Source.h | 9 +- src/modules/audio/openal/Audio.cpp | 120 ++++++---- src/modules/audio/openal/Audio.h | 27 ++- src/modules/audio/openal/Source.cpp | 357 +++++++++++++++++----------- src/modules/audio/openal/Source.h | 37 +-- src/modules/audio/wrap_Audio.cpp | 43 +++- src/modules/audio/wrap_Source.cpp | 56 +++-- 12 files changed, 435 insertions(+), 279 deletions(-) diff --git a/src/modules/audio/Audio.h b/src/modules/audio/Audio.h index b59496750..50c31412b 100644 --- a/src/modules/audio/Audio.h +++ b/src/modules/audio/Audio.h @@ -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 ¶ms) = 0; + virtual bool setEffect(const char *name, std::map ¶ms) = 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 ¶ms) = 0; + virtual bool getEffect(const char *name, std::map ¶ms) = 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 &list) = 0; /** * Gets maximum number of scene EFX effects. diff --git a/src/modules/audio/Source.h b/src/modules/audio/Source.h index 17d2da1b0..593e78b91 100644 --- a/src/modules/audio/Source.h +++ b/src/modules/audio/Source.h @@ -113,10 +113,11 @@ public: virtual bool setFilter() = 0; virtual bool getFilter(std::map ¶ms) = 0; - virtual bool setSceneEffect(int slot, int effect) = 0; - virtual bool setSceneEffect(int slot, int effect, const std::map ¶ms) = 0; - virtual bool setSceneEffect(int slot) = 0; - virtual bool getSceneEffect(int slot, int &effect, std::map ¶ms) = 0; + virtual bool setEffect(const char *effect) = 0; + virtual bool setEffect(const char *effect, const std::map ¶ms) = 0; + virtual bool unsetEffect(const char *effect) = 0; + virtual bool getEffect(const char *effect, std::map ¶ms) = 0; + virtual bool getEffectsList(std::vector &list) = 0; virtual int getFreeBufferCount() const = 0; virtual bool queue(void *data, size_t length, int dataSampleRate, int dataBitDepth, int dataChannels) = 0; diff --git a/src/modules/audio/null/Audio.cpp b/src/modules/audio/null/Audio.cpp index a52f27814..6cf33e963 100644 --- a/src/modules/audio/null/Audio.cpp +++ b/src/modules/audio/null/Audio.cpp @@ -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 &) +bool Audio::setEffect(const char *, std::map &) { return false; } -bool Audio::setSceneEffect(int) +bool Audio::unsetEffect(const char *) { return false; } -bool Audio::getSceneEffect(int, std::map &) +bool Audio::getEffect(const char *, std::map &) +{ + return false; +} + +bool Audio::getEffectsList(std::vector &list) { return false; } diff --git a/src/modules/audio/null/Audio.h b/src/modules/audio/null/Audio.h index 102293fd8..34f1f592a 100644 --- a/src/modules/audio/null/Audio.h +++ b/src/modules/audio/null/Audio.h @@ -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 ¶ms); - bool setSceneEffect(int slot); - bool getSceneEffect(int slot, std::map ¶ms); + bool setEffect(const char *, std::map ¶ms); + bool unsetEffect(const char *); + bool getEffect(const char *, std::map ¶ms); + bool getEffectsList(std::vector &list); int getMaxSceneEffects() const; int getMaxSourceEffects() const; bool isEFXsupported() const; diff --git a/src/modules/audio/null/Source.cpp b/src/modules/audio/null/Source.cpp index 17550f0aa..1a1a8d655 100644 --- a/src/modules/audio/null/Source.cpp +++ b/src/modules/audio/null/Source.cpp @@ -254,22 +254,27 @@ bool Source::getFilter(std::map &) return false; } -bool Source::setSceneEffect(int, int) +bool Source::setEffect(const char *) { return false; } -bool Source::setSceneEffect(int, int, const std::map &) +bool Source::setEffect(const char *, const std::map &) { return false; } -bool Source::setSceneEffect(int) +bool Source::unsetEffect(const char *) { return false; } -bool Source::getSceneEffect(int, int &, std::map &) +bool Source::getEffect(const char *, std::map &) +{ + return false; +} + +bool Source::getEffectsList(std::vector &) { return false; } diff --git a/src/modules/audio/null/Source.h b/src/modules/audio/null/Source.h index c71d62004..b158f909e 100644 --- a/src/modules/audio/null/Source.h +++ b/src/modules/audio/null/Source.h @@ -86,10 +86,11 @@ public: virtual bool setFilter(); virtual bool getFilter(std::map ¶ms); - virtual bool setSceneEffect(int slot, int effect); - virtual bool setSceneEffect(int slot, int effect, const std::map ¶ms); - virtual bool setSceneEffect(int slot); - virtual bool getSceneEffect(int slot, int &effect, std::map ¶ms); + virtual bool setEffect(const char *effect); + virtual bool setEffect(const char *effect, const std::map ¶ms); + virtual bool unsetEffect(const char *effect); + virtual bool getEffect(const char *effect, std::map ¶ms); + virtual bool getEffectsList(std::vector &list); private: diff --git a/src/modules/audio/openal/Audio.cpp b/src/modules/audio/openal/Audio.cpp index f9a9a897a..105849236 100644 --- a/src/modules/audio/openal/Audio.cpp +++ b/src/modules/audio/openal/Audio.cpp @@ -129,11 +129,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; @@ -159,8 +155,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 @@ -186,16 +185,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); @@ -218,9 +220,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 @@ -456,27 +458,44 @@ const std::vector &Audio::getRecordingDevices() return capture; } -bool Audio::setSceneEffect(int slot, std::map ¶ms) +bool Audio::setEffect(const char *name, std::map ¶ms) { - 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 @@ -484,33 +503,45 @@ bool Audio::setSceneEffect(int slot, std::map ¶ms) 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 ¶ms) +{ + 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 ¶ms) +bool Audio::getEffectsList(std::vector &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; } @@ -534,17 +565,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 diff --git a/src/modules/audio/openal/Audio.h b/src/modules/audio/openal/Audio.h index 54d4e14b4..54f006777 100644 --- a/src/modules/audio/openal/Audio.h +++ b/src/modules/audio/openal/Audio.h @@ -25,6 +25,7 @@ #include #include #include +#include #include // 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 ¶ms); - bool setSceneEffect(int slot); - bool getSceneEffect(int slot, std::map ¶ms); + bool setEffect(const char *name, std::map ¶ms); + bool unsetEffect(const char *name); + bool getEffect(const char *name, std::map ¶ms); + bool getEffectsList(std::vector &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 effects; - std::vector effectSlots; - std::map effectIndex; - int MAX_SCENE_EFFECTS = 16; - int MAX_SOURCE_EFFECTS = 16; + struct effectmapStorage + { + Effect *effect; + ALuint slot; + }; + std::map effectmap; + std::stack slotlist; + int MAX_SCENE_EFFECTS = 64; + int MAX_SOURCE_EFFECTS = 64; // The Pool. Pool *pool; diff --git a/src/modules/audio/openal/Source.cpp b/src/modules/audio/openal/Source.cpp index ba2ac2338..a0461b491 100644 --- a/src/modules/audio/openal/Source.cpp +++ b/src/modules/audio/openal/Source.cpp @@ -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; } } @@ -329,7 +392,7 @@ bool Source::update() if (!isFinished()) { ALint processed; - ALuint buffers[MAX_BUFFERS]; + ALuint buffers[this->buffers]; float curOffsetSamples, curOffsetSecs, newOffsetSamples, newOffsetSecs; int freq = decoder->getSampleRate(); @@ -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,10 +426,10 @@ bool Source::update() return true; } return false; - case TYPE_QUEUE: + case TYPE_QUEUE: { ALint processed; - ALuint buffers[MAX_BUFFERS]; + ALuint buffers[this->buffers]; alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed); alSourceUnqueueBuffers(source, processed, 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 ¶ms) 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(audiomodule())->getEffectID(name, target)) return false; - sendtargets[slot] = dynamic_cast(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 ¶ms) +bool Source::setEffect(const char *name, const std::map ¶ms) { - if (slot < 0 || slot >= (int)sendtargets.size()) + ALuint slot, target; + Filter *filter; + + // effect with this name doesn't exist + if (!dynamic_cast(audiomodule())->getEffectID(name, target)) return false; - sendtargets[slot] = dynamic_cast(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 ¶ms) +{ + 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 ¶ms) +bool Source::getEffectsList(std::vector &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(audiomodule())->getSceneEffectIndex(sendtargets[slot]); - - if(sendfilters[slot]) - params = sendfilters[slot]->getParams(); + for (auto i : effectmap) + list.push_back(i.first); return true; } diff --git a/src/modules/audio/openal/Source.h b/src/modules/audio/openal/Source.h index d63ddc652..0f47e67bf 100644 --- a/src/modules/audio/openal/Source.h +++ b/src/modules/audio/openal/Source.h @@ -33,6 +33,7 @@ // STL #include +#include // C #include @@ -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 ¶ms); - virtual bool setSceneEffect(int slot, int effect); - virtual bool setSceneEffect(int slot, int effect, const std::map ¶ms); - virtual bool setSceneEffect(int slot); - virtual bool getSceneEffect(int slot, int &effect, std::map ¶ms); + virtual bool setEffect(const char *effect); + virtual bool setEffect(const char *effect, const std::map ¶ms); + virtual bool unsetEffect(const char *effect); + virtual bool getEffect(const char *effect, std::map ¶ms); + virtual bool getEffectsList(std::vector &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 streamBuffers; + std::stack unusedBuffers; StrongRef staticBuffer; @@ -226,12 +223,18 @@ private: StrongRef decoder; unsigned int toLoop = 0; - int unusedBufferTop = -1; ALsizei bufferedBytes = 0; + int buffers = 0; Filter *directfilter = nullptr; - std::vector sendfilters; - std::vector sendtargets; + + struct effectmapStorage + { + Filter *filter; + ALuint slot, target; + }; + std::map effectmap; + std::stack slotlist; }; // Source } // openal diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index fc230a297..434079753 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -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 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 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 } }; diff --git a/src/modules/audio/wrap_Source.cpp b/src/modules/audio/wrap_Source.cpp index 3951ed995..000ba69ad 100644 --- a/src/modules/audio/wrap_Source.cpp +++ b/src/modules/audio/wrap_Source.cpp @@ -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 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 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 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 }, From 8737e2e70ffa2616743ef47ec1d42d997fe27617 Mon Sep 17 00:00:00 2001 From: raidho36 Date: Mon, 10 Jul 2017 03:14:41 +0300 Subject: [PATCH 2/3] C++11 VLA usage removed, prettifyed naming. --HG-- branch : minor --- src/modules/audio/openal/Audio.h | 4 ++-- src/modules/audio/openal/Source.cpp | 2 +- src/modules/audio/openal/Source.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/audio/openal/Audio.h b/src/modules/audio/openal/Audio.h index 54f006777..9d9badb07 100644 --- a/src/modules/audio/openal/Audio.h +++ b/src/modules/audio/openal/Audio.h @@ -137,12 +137,12 @@ private: ALCcontext *context; // The OpenAL effects - struct effectmapStorage + struct EffectMapStorage { Effect *effect; ALuint slot; }; - std::map effectmap; + std::map effectmap; std::stack slotlist; int MAX_SCENE_EFFECTS = 64; int MAX_SOURCE_EFFECTS = 64; diff --git a/src/modules/audio/openal/Source.cpp b/src/modules/audio/openal/Source.cpp index a0461b491..1bd92ff9d 100644 --- a/src/modules/audio/openal/Source.cpp +++ b/src/modules/audio/openal/Source.cpp @@ -392,7 +392,7 @@ bool Source::update() if (!isFinished()) { ALint processed; - ALuint buffers[this->buffers]; + ALuint buffers[MAX_BUFFERS]; float curOffsetSamples, curOffsetSecs, newOffsetSamples, newOffsetSecs; int freq = decoder->getSampleRate(); diff --git a/src/modules/audio/openal/Source.h b/src/modules/audio/openal/Source.h index 0f47e67bf..2e6f1cd39 100644 --- a/src/modules/audio/openal/Source.h +++ b/src/modules/audio/openal/Source.h @@ -228,12 +228,12 @@ private: Filter *directfilter = nullptr; - struct effectmapStorage + struct EffectMapStorage { Filter *filter; ALuint slot, target; }; - std::map effectmap; + std::map effectmap; std::stack slotlist; }; // Source From 16180a7e9bb0622ecddb375299e119b0442d0cc6 Mon Sep 17 00:00:00 2001 From: raidho36 Date: Mon, 10 Jul 2017 03:30:16 +0300 Subject: [PATCH 3/3] That should be all. --HG-- branch : minor --- src/modules/audio/openal/Source.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/audio/openal/Source.cpp b/src/modules/audio/openal/Source.cpp index 1bd92ff9d..cbaa68686 100644 --- a/src/modules/audio/openal/Source.cpp +++ b/src/modules/audio/openal/Source.cpp @@ -429,7 +429,7 @@ bool Source::update() case TYPE_QUEUE: { ALint processed; - ALuint buffers[this->buffers]; + ALuint buffers[MAX_BUFFERS]; alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed); alSourceUnqueueBuffers(source, processed, buffers);