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.
This commit is contained in:
bjorn 2021-04-01 16:46:16 -06:00
parent 923498a927
commit 82a309a56d
4 changed files with 39 additions and 29 deletions

View File

@ -223,18 +223,40 @@ static int l_lovrAudioSetAbsorption(lua_State* L) {
static int l_lovrAudioNewSource(lua_State* L) { static int l_lovrAudioNewSource(lua_State* L) {
Sound* sound = luax_totype(L, 1, Sound); Sound* sound = luax_totype(L, 1, Sound);
bool spatial = true;
bool decode = false; bool decode = false;
uint32_t effects = EFFECT_ALL;
if (lua_gettop(L) >= 2) { if (lua_gettop(L) >= 2) {
luaL_checktype(L, 2, LUA_TTABLE); 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"); lua_getfield(L, 2, "decode");
decode = lua_toboolean(L, -1); decode = lua_toboolean(L, -1);
lua_pop(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) { if (!sound) {
@ -245,7 +267,7 @@ static int l_lovrAudioNewSource(lua_State* L) {
lovrRetain(sound); lovrRetain(sound);
} }
Source* source = lovrSourceCreate(sound, spatial); Source* source = lovrSourceCreate(sound, effects);
luax_pushtype(L, Source, source); luax_pushtype(L, Source, source);
lovrRelease(sound, lovrSoundDestroy); lovrRelease(sound, lovrSoundDestroy);
lovrRelease(source, lovrSourceDestroy); lovrRelease(source, lovrSourceDestroy);

View File

@ -96,13 +96,6 @@ static int l_lovrSourceGetDuration(lua_State* L) {
return 1; 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) { static int l_lovrSourceGetPosition(lua_State* L) {
Source* source = luax_checktype(L, 1, Source); Source* source = luax_checktype(L, 1, Source);
float position[4], orientation[4]; float position[4], orientation[4];
@ -229,7 +222,6 @@ const luaL_Reg lovrSource[] = {
{ "seek", l_lovrSourceSeek }, { "seek", l_lovrSourceSeek },
{ "tell", l_lovrSourceTell }, { "tell", l_lovrSourceTell },
{ "getDuration", l_lovrSourceGetDuration }, { "getDuration", l_lovrSourceGetDuration },
{ "isSpatial", l_lovrSourceIsSpatial },
{ "getPosition", l_lovrSourceGetPosition }, { "getPosition", l_lovrSourceGetPosition },
{ "setPosition", l_lovrSourceSetPosition }, { "setPosition", l_lovrSourceSetPosition },
{ "getOrientation", l_lovrSourceGetOrientation }, { "getOrientation", l_lovrSourceGetOrientation },

View File

@ -33,7 +33,6 @@ struct Source {
uint8_t effects; uint8_t effects;
bool playing; bool playing;
bool looping; bool looping;
bool spatial;
}; };
static struct { 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 // 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); uint64_t frameLimit = sizeof(raw) / lovrSoundGetChannelCount(source->sound) / sizeof(float);
uint32_t framesToConvert = BUFFER_SIZE; uint32_t framesToConvert = BUFFER_SIZE;
uint32_t framesConverted = 0; uint32_t framesConverted = 0;
@ -146,7 +145,7 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co
} }
// Spatialize // Spatialize
if (source->spatial) { if (source->effects != EFFECT_NONE) {
state.spatializer->apply(source, src, mix, BUFFER_SIZE, BUFFER_SIZE); state.spatializer->apply(source, src, mix, BUFFER_SIZE, BUFFER_SIZE);
src = mix; src = mix;
} }
@ -394,7 +393,7 @@ void lovrAudioSetAbsorption(float absorption[3]) {
// Source // 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"); lovrAssert(lovrSoundGetChannelLayout(sound) != CHANNEL_AMBISONIC, "Ambisonic Sources are not currently supported");
Source* source = calloc(1, sizeof(Source)); Source* source = calloc(1, sizeof(Source));
lovrAssert(source, "Out of memory"); lovrAssert(source, "Out of memory");
@ -404,13 +403,13 @@ Source* lovrSourceCreate(Sound* sound, bool spatial) {
lovrRetain(source->sound); lovrRetain(source->sound);
source->volume = 1.f; source->volume = 1.f;
source->spatial = spatial; source->effects = effects;
ma_data_converter_config config = ma_data_converter_config_init_default(); ma_data_converter_config config = ma_data_converter_config_init_default();
config.formatIn = miniaudioFormats[lovrSoundGetFormat(sound)]; config.formatIn = miniaudioFormats[lovrSoundGetFormat(sound)];
config.formatOut = miniaudioFormats[OUTPUT_FORMAT]; config.formatOut = miniaudioFormats[OUTPUT_FORMAT];
config.channelsIn = lovrSoundGetChannelCount(sound); config.channelsIn = lovrSoundGetChannelCount(sound);
config.channelsOut = spatial ? 1 : 2; config.channelsOut = effects == EFFECT_NONE ? 2 : 1;
config.sampleRateIn = lovrSoundGetSampleRate(sound); config.sampleRateIn = lovrSoundGetSampleRate(sound);
config.sampleRateOut = SAMPLE_RATE; config.sampleRateOut = SAMPLE_RATE;
@ -439,7 +438,6 @@ Source* lovrSourceClone(Source* source) {
clone->dipolePower = source->dipolePower; clone->dipolePower = source->dipolePower;
clone->effects = source->effects; clone->effects = source->effects;
clone->looping = source->looping; clone->looping = source->looping;
clone->spatial = source->spatial;
clone->converter = malloc(sizeof(ma_data_converter)); clone->converter = malloc(sizeof(ma_data_converter));
ma_result status = ma_data_converter_init(&source->converter->config, clone->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); 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; 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]) { void lovrSourceGetPose(Source *source, float position[4], float orientation[4]) {
memcpy(position, source->position, sizeof(source->position)); memcpy(position, source->position, sizeof(source->position));
memcpy(orientation, source->orientation, sizeof(source->orientation)); 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) { 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) { void lovrSourceSetEffectEnabled(Source* source, Effect effect, bool enabled) {
if (enabled) { if (enabled && source->effects != EFFECT_NONE) {
source->effects |= (1 << effect); source->effects |= (1 << effect);
} else { } else {
source->effects &= ~(1 << effect); source->effects &= ~(1 << effect);

View File

@ -18,7 +18,9 @@ typedef enum {
EFFECT_OCCLUSION, EFFECT_OCCLUSION,
EFFECT_REVERB, EFFECT_REVERB,
EFFECT_SPATIALIZATION, EFFECT_SPATIALIZATION,
EFFECT_TRANSMISSION EFFECT_TRANSMISSION,
EFFECT_ALL = 0x3f,
EFFECT_NONE = 0xff
} Effect; } Effect;
typedef enum { typedef enum {
@ -75,7 +77,7 @@ void lovrAudioSetAbsorption(float absorption[3]);
// Source // Source
Source* lovrSourceCreate(struct Sound* sound, bool spatial); Source* lovrSourceCreate(struct Sound* sound, uint32_t effects);
Source* lovrSourceClone(Source* source); Source* lovrSourceClone(Source* source);
void lovrSourceDestroy(void* ref); void lovrSourceDestroy(void* ref);
struct Sound* lovrSourceGetSound(Source* source); struct Sound* lovrSourceGetSound(Source* source);