From 82a309a56dac8d5208dd2b6c3706d170bcbc34fe Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 1 Apr 2021 16:46:16 -0600 Subject: [PATCH] Draft new effects API; - A list or map of effects can be provided to newSource. - false can be used to bypass effects. - All effects are enabled by default. - Occlusion-y effects should only take effect when setGeometry is called - Spatializer is responsible for ensuring this. --- src/api/l_audio.c | 34 ++++++++++++++++++++++++++++------ src/api/l_audio_source.c | 8 -------- src/modules/audio/audio.c | 20 +++++++------------- src/modules/audio/audio.h | 6 ++++-- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/api/l_audio.c b/src/api/l_audio.c index 0b6b5e7c..77b40dd5 100644 --- a/src/api/l_audio.c +++ b/src/api/l_audio.c @@ -223,18 +223,40 @@ static int l_lovrAudioSetAbsorption(lua_State* L) { static int l_lovrAudioNewSource(lua_State* L) { Sound* sound = luax_totype(L, 1, Sound); - bool spatial = true; bool decode = false; + uint32_t effects = EFFECT_ALL; if (lua_gettop(L) >= 2) { luaL_checktype(L, 2, LUA_TTABLE); - lua_getfield(L, 2, "spatial"); - spatial = lua_isnil(L, -1) || lua_toboolean(L, -1); - lua_pop(L, 1); - lua_getfield(L, 2, "decode"); decode = lua_toboolean(L, -1); lua_pop(L, 1); + + lua_getfield(L, 2, "effects"); + switch (lua_type(L, -1)) { + case LUA_TNIL: effects = EFFECT_ALL; break; + case LUA_TBOOLEAN: effects = lua_toboolean(L, -1) ? EFFECT_ALL : EFFECT_NONE; break; + case LUA_TTABLE: + effects = 0; + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + if (lua_type(L, -2) == LUA_TSTRING) { + Effect effect = luax_checkenum(L, -2, Effect, NULL); + if (lua_toboolean(L, -1)) { + effects |= (1 << effect); + } else { + effects &= ~(1 << effect); + } + } else if (lua_type(L, -2) == LUA_TNUMBER) { + Effect effect = luax_checkenum(L, -1, Effect, NULL); + effects |= (1 << effect); + } + lua_pop(L, 1); + } + break; + default: break; + } + lua_pop(L, 1); } if (!sound) { @@ -245,7 +267,7 @@ static int l_lovrAudioNewSource(lua_State* L) { lovrRetain(sound); } - Source* source = lovrSourceCreate(sound, spatial); + Source* source = lovrSourceCreate(sound, effects); luax_pushtype(L, Source, source); lovrRelease(sound, lovrSoundDestroy); lovrRelease(source, lovrSourceDestroy); diff --git a/src/api/l_audio_source.c b/src/api/l_audio_source.c index 3497903a..b6780832 100644 --- a/src/api/l_audio_source.c +++ b/src/api/l_audio_source.c @@ -96,13 +96,6 @@ static int l_lovrSourceGetDuration(lua_State* L) { return 1; } -static int l_lovrSourceIsSpatial(lua_State* L) { - Source* source = luax_checktype(L, 1, Source); - bool spatial = lovrSourceIsSpatial(source); - lua_pushboolean(L, spatial); - return 1; -} - static int l_lovrSourceGetPosition(lua_State* L) { Source* source = luax_checktype(L, 1, Source); float position[4], orientation[4]; @@ -229,7 +222,6 @@ const luaL_Reg lovrSource[] = { { "seek", l_lovrSourceSeek }, { "tell", l_lovrSourceTell }, { "getDuration", l_lovrSourceGetDuration }, - { "isSpatial", l_lovrSourceIsSpatial }, { "getPosition", l_lovrSourceGetPosition }, { "setPosition", l_lovrSourceSetPosition }, { "getOrientation", l_lovrSourceGetOrientation }, diff --git a/src/modules/audio/audio.c b/src/modules/audio/audio.c index abc9b01c..a5612d7e 100644 --- a/src/modules/audio/audio.c +++ b/src/modules/audio/audio.c @@ -33,7 +33,6 @@ struct Source { uint8_t effects; bool playing; bool looping; - bool spatial; }; static struct { @@ -111,7 +110,7 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co } // Read and convert raw frames until there's BUFFER_SIZE converted frames - uint32_t channels = source->spatial ? 1 : 2; + uint32_t channels = source->effects == EFFECT_NONE ? 2 : 1; uint64_t frameLimit = sizeof(raw) / lovrSoundGetChannelCount(source->sound) / sizeof(float); uint32_t framesToConvert = BUFFER_SIZE; uint32_t framesConverted = 0; @@ -146,7 +145,7 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co } // Spatialize - if (source->spatial) { + if (source->effects != EFFECT_NONE) { state.spatializer->apply(source, src, mix, BUFFER_SIZE, BUFFER_SIZE); src = mix; } @@ -394,7 +393,7 @@ void lovrAudioSetAbsorption(float absorption[3]) { // Source -Source* lovrSourceCreate(Sound* sound, bool spatial) { +Source* lovrSourceCreate(Sound* sound, uint32_t effects) { lovrAssert(lovrSoundGetChannelLayout(sound) != CHANNEL_AMBISONIC, "Ambisonic Sources are not currently supported"); Source* source = calloc(1, sizeof(Source)); lovrAssert(source, "Out of memory"); @@ -404,13 +403,13 @@ Source* lovrSourceCreate(Sound* sound, bool spatial) { lovrRetain(source->sound); source->volume = 1.f; - source->spatial = spatial; + source->effects = effects; ma_data_converter_config config = ma_data_converter_config_init_default(); config.formatIn = miniaudioFormats[lovrSoundGetFormat(sound)]; config.formatOut = miniaudioFormats[OUTPUT_FORMAT]; config.channelsIn = lovrSoundGetChannelCount(sound); - config.channelsOut = spatial ? 1 : 2; + config.channelsOut = effects == EFFECT_NONE ? 2 : 1; config.sampleRateIn = lovrSoundGetSampleRate(sound); config.sampleRateOut = SAMPLE_RATE; @@ -439,7 +438,6 @@ Source* lovrSourceClone(Source* source) { clone->dipolePower = source->dipolePower; clone->effects = source->effects; clone->looping = source->looping; - clone->spatial = source->spatial; clone->converter = malloc(sizeof(ma_data_converter)); ma_result status = ma_data_converter_init(&source->converter->config, clone->converter); lovrAssert(status == MA_SUCCESS, "Problem creating Source data converter: %s (%d)", ma_result_description(status), status); @@ -527,10 +525,6 @@ double lovrSourceGetDuration(Source* source, TimeUnit units) { return units == UNIT_SECONDS ? (double) frames / lovrSoundGetSampleRate(source->sound) : frames; } -bool lovrSourceIsSpatial(Source *source) { - return source->spatial; -} - void lovrSourceGetPose(Source *source, float position[4], float orientation[4]) { memcpy(position, source->position, sizeof(source->position)); memcpy(orientation, source->orientation, sizeof(source->orientation)); @@ -562,11 +556,11 @@ void lovrSourceSetDirectivity(Source* source, float weight, float power) { } bool lovrSourceIsEffectEnabled(Source* source, Effect effect) { - return source->effects & (1 << effect); + return source->effects == EFFECT_NONE ? false : (source->effects & (1 << effect)); } void lovrSourceSetEffectEnabled(Source* source, Effect effect, bool enabled) { - if (enabled) { + if (enabled && source->effects != EFFECT_NONE) { source->effects |= (1 << effect); } else { source->effects &= ~(1 << effect); diff --git a/src/modules/audio/audio.h b/src/modules/audio/audio.h index f536d804..704b888b 100644 --- a/src/modules/audio/audio.h +++ b/src/modules/audio/audio.h @@ -18,7 +18,9 @@ typedef enum { EFFECT_OCCLUSION, EFFECT_REVERB, EFFECT_SPATIALIZATION, - EFFECT_TRANSMISSION + EFFECT_TRANSMISSION, + EFFECT_ALL = 0x3f, + EFFECT_NONE = 0xff } Effect; typedef enum { @@ -75,7 +77,7 @@ void lovrAudioSetAbsorption(float absorption[3]); // Source -Source* lovrSourceCreate(struct Sound* sound, bool spatial); +Source* lovrSourceCreate(struct Sound* sound, uint32_t effects); Source* lovrSourceClone(Source* source); void lovrSourceDestroy(void* ref); struct Sound* lovrSourceGetSound(Source* source);