diff --git a/src/api/l_audio.c b/src/api/l_audio.c index d573e076..8849107c 100644 --- a/src/api/l_audio.c +++ b/src/api/l_audio.c @@ -229,7 +229,8 @@ static int l_lovrAudioNewSource(lua_State* L) { Sound* sound = luax_totype(L, 1, Sound); bool decode = false; - uint32_t effects = EFFECT_ALL; + bool spatial = true; + uint32_t effects = ~0u; if (lua_gettop(L) >= 2) { luaL_checktype(L, 2, LUA_TTABLE); @@ -238,30 +239,27 @@ static int l_lovrAudioNewSource(lua_State* L) { 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); + if (!lua_isnil(L, -1)) { + effects = 0; + lovrAssert(lua_istable(L, -1), "Source effects must be a table"); + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + if (lua_type(L, -2) == LUA_TSTRING) { + Effect effect = luax_checkenum(L, -2, Effect, NULL); + bool enabled = lua_toboolean(L, -1); + effects |= enabled << effect; + } else if (lua_type(L, -2) == LUA_TNUMBER) { + Effect effect = luax_checkenum(L, -1, Effect, NULL); + effects |= 1 << effect; } - break; - default: break; + lua_pop(L, 1); + } } lua_pop(L, 1); + + lua_getfield(L, 2, "spatial"); + spatial = lua_isnil(L, -1) ? true : lua_toboolean(L, -1); + lua_pop(L, 1); } if (!sound) { @@ -272,7 +270,7 @@ static int l_lovrAudioNewSource(lua_State* L) { lovrRetain(sound); } - Source* source = lovrSourceCreate(sound, effects); + Source* source = lovrSourceCreate(sound, spatial, 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 90b959c4..0c9bc9d4 100644 --- a/src/api/l_audio_source.c +++ b/src/api/l_audio_source.c @@ -208,6 +208,13 @@ static int l_lovrSourceSetEffectEnabled(lua_State* L) { return 0; } +static int l_lovrSourceIsSpatial(lua_State* L) { + Source* source = luax_checktype(L, 1, Source); + bool spatial = lovrSourceIsSpatial(source); + lua_pushboolean(L, spatial); + return 1; +} + const luaL_Reg lovrSource[] = { { "clone", l_lovrSourceClone }, { "getSound", l_lovrSourceGetSound }, @@ -234,5 +241,6 @@ const luaL_Reg lovrSource[] = { { "setDirectivity", l_lovrSourceSetDirectivity }, { "isEffectEnabled", l_lovrSourceIsEffectEnabled }, { "setEffectEnabled", l_lovrSourceSetEffectEnabled }, + { "isSpatial", l_lovrSourceIsSpatial }, { NULL, NULL } }; diff --git a/src/modules/audio/audio.c b/src/modules/audio/audio.c index 58fb1bfb..e78519c5 100644 --- a/src/modules/audio/audio.c +++ b/src/modules/audio/audio.c @@ -34,6 +34,7 @@ struct Source { uint8_t effects; bool playing; bool looping; + bool spatial; }; static struct { @@ -94,7 +95,7 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co // - If EOF is reached, rewind and continue for looping sources, otherwise pad end with zero. buf = source->converter ? aux : raw; float* cursor = buf; // Edge of processed frames - uint32_t channelsOut = lovrSourceUsesSpatializer(source) ? 1 : 2; // If spatializer isn't converting to stereo, converter must do it + uint32_t channelsOut = source->spatial ? 1 : 2; // If spatializer isn't converting to stereo, converter must do it uint32_t framesRemaining = BUFFER_SIZE; while (framesRemaining > 0) { uint32_t framesRead; @@ -136,7 +137,7 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co } // Spatialize - if (lovrSourceUsesSpatializer(source)) { + if (source->spatial) { state.spatializer->apply(source, buf, mix, BUFFER_SIZE, BUFFER_SIZE); buf = mix; } @@ -378,7 +379,7 @@ void lovrAudioSetAbsorption(float absorption[3]) { // Source -Source* lovrSourceCreate(Sound* sound, uint32_t effects) { +Source* lovrSourceCreate(Sound* sound, bool spatial, 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"); @@ -388,14 +389,15 @@ Source* lovrSourceCreate(Sound* sound, uint32_t effects) { lovrRetain(source->sound); source->volume = 1.f; - source->effects = effects; + source->spatial = spatial; + source->effects = spatial ? effects : 0; quat_identity(source->orientation); 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 = lovrSourceUsesSpatializer(source) ? 1 : 2; // See onPlayback + config.channelsOut = spatial ? 1 : 2; config.sampleRateIn = lovrSoundGetSampleRate(sound); config.sampleRateOut = state.sampleRate; @@ -424,6 +426,7 @@ Source* lovrSourceClone(Source* source) { clone->dipolePower = source->dipolePower; clone->effects = source->effects; clone->looping = source->looping; + clone->spatial = source->spatial; if (source->converter) { clone->converter = malloc(sizeof(ma_data_converter)); lovrAssert(clone->converter, "Out of memory"); @@ -521,8 +524,8 @@ double lovrSourceGetDuration(Source* source, TimeUnit units) { return units == UNIT_SECONDS ? (double) frames / lovrSoundGetSampleRate(source->sound) : frames; } -bool lovrSourceUsesSpatializer(Source* source) { - return source->effects != EFFECT_NONE; // Currently, all effects require the spatializer +bool lovrSourceIsSpatial(Source* source) { + return source->spatial; } void lovrSourceGetPose(Source* source, float position[4], float orientation[4]) { @@ -556,11 +559,11 @@ void lovrSourceSetDirectivity(Source* source, float weight, float power) { } bool lovrSourceIsEffectEnabled(Source* source, Effect effect) { - return source->effects == EFFECT_NONE ? false : (source->effects & (1 << effect)); + return source->effects & (1 << effect); } void lovrSourceSetEffectEnabled(Source* source, Effect effect, bool enabled) { - lovrCheck(source->effects != EFFECT_NONE, "Unable to change effects on a Source with effects disabled"); + lovrCheck(source->spatial, "Sources must be created with the spatial flag to enable effects"); if (enabled) { source->effects |= (1 << effect); } else { diff --git a/src/modules/audio/audio.h b/src/modules/audio/audio.h index 79c177a5..89987b77 100644 --- a/src/modules/audio/audio.h +++ b/src/modules/audio/audio.h @@ -17,9 +17,7 @@ typedef enum { EFFECT_OCCLUSION, EFFECT_REVERB, EFFECT_SPATIALIZATION, - EFFECT_TRANSMISSION, - EFFECT_ALL = 0x3f, - EFFECT_NONE = 0xff + EFFECT_TRANSMISSION } Effect; typedef enum { @@ -77,7 +75,7 @@ void lovrAudioSetAbsorption(float absorption[3]); // Source -Source* lovrSourceCreate(struct Sound* sound, uint32_t effects); +Source* lovrSourceCreate(struct Sound* sound, bool spatial, uint32_t effects); Source* lovrSourceClone(Source* source); void lovrSourceDestroy(void* ref); struct Sound* lovrSourceGetSound(Source* source); @@ -92,7 +90,7 @@ void lovrSourceSetVolume(Source* source, float volume, VolumeUnit units); void lovrSourceSeek(Source* source, double time, TimeUnit units); double lovrSourceTell(Source* source, TimeUnit units); double lovrSourceGetDuration(Source* source, TimeUnit units); -bool lovrSourceUsesSpatializer(Source* source); +bool lovrSourceIsSpatial(Source* source); void lovrSourceGetPose(Source* source, float position[4], float orientation[4]); void lovrSourceSetPose(Source* source, float position[4], float orientation[4]); float lovrSourceGetRadius(Source* source);