From d8c23bacec733482afbf56fd57749132de14aa8d Mon Sep 17 00:00:00 2001 From: bjorn Date: Sun, 11 Sep 2022 20:41:58 -0700 Subject: [PATCH] Source:setPitch; Co-authored-by: Nevyn Bengtsson --- src/api/l_audio.c | 7 ++++++- src/api/l_audio_source.c | 14 ++++++++++++++ src/modules/audio/audio.c | 29 +++++++++++++++++++++++++++-- src/modules/audio/audio.h | 5 ++++- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/api/l_audio.c b/src/api/l_audio.c index 8849107c..fc5afe08 100644 --- a/src/api/l_audio.c +++ b/src/api/l_audio.c @@ -229,6 +229,7 @@ static int l_lovrAudioNewSource(lua_State* L) { Sound* sound = luax_totype(L, 1, Sound); bool decode = false; + bool pitchable = false; bool spatial = true; uint32_t effects = ~0u; if (lua_gettop(L) >= 2) { @@ -238,6 +239,10 @@ static int l_lovrAudioNewSource(lua_State* L) { decode = lua_toboolean(L, -1); lua_pop(L, 1); + lua_getfield(L, 2, "pitchable"); + pitchable = lua_toboolean(L, -1); + lua_pop(L, 1); + lua_getfield(L, 2, "effects"); if (!lua_isnil(L, -1)) { effects = 0; @@ -270,7 +275,7 @@ static int l_lovrAudioNewSource(lua_State* L) { lovrRetain(sound); } - Source* source = lovrSourceCreate(sound, spatial, effects); + Source* source = lovrSourceCreate(sound, pitchable, 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 0c9bc9d4..6a21df85 100644 --- a/src/api/l_audio_source.c +++ b/src/api/l_audio_source.c @@ -57,6 +57,18 @@ static int l_lovrSourceSetLooping(lua_State* L) { return 0; } +static int l_lovrSourceGetPitch(lua_State* L) { + Source* source = luax_checktype(L, 1, Source); + lua_pushnumber(L, lovrSourceGetPitch(source)); + return 1; +} + +static int l_lovrSourceSetPitch(lua_State* L) { + Source* source = luax_checktype(L, 1, Source); + lovrSourceSetPitch(source, luax_checkfloat(L, 2)); + return 0; +} + static int l_lovrSourceGetVolume(lua_State* L) { Source* source = luax_checktype(L, 1, Source); VolumeUnit units = luax_checkenum(L, 2, VolumeUnit, "linear"); @@ -224,6 +236,8 @@ const luaL_Reg lovrSource[] = { { "isPlaying", l_lovrSourceIsPlaying }, { "isLooping", l_lovrSourceIsLooping }, { "setLooping", l_lovrSourceSetLooping }, + { "getPitch", l_lovrSourceGetPitch }, + { "setPitch", l_lovrSourceSetPitch }, { "getVolume", l_lovrSourceGetVolume }, { "setVolume", l_lovrSourceSetVolume }, { "seek", l_lovrSourceSeek }, diff --git a/src/modules/audio/audio.c b/src/modules/audio/audio.c index bd638ce1..0f95283e 100644 --- a/src/modules/audio/audio.c +++ b/src/modules/audio/audio.c @@ -25,6 +25,7 @@ struct Source { ma_data_converter* converter; intptr_t spatializerMemo; uint32_t offset; + float pitch; float volume; float position[4]; float orientation[4]; @@ -34,6 +35,7 @@ struct Source { uint8_t effects; bool playing; bool looping; + bool pitchable; bool spatial; }; @@ -379,7 +381,7 @@ void lovrAudioSetAbsorption(float absorption[3]) { // Source -Source* lovrSourceCreate(Sound* sound, bool spatial, uint32_t effects) { +Source* lovrSourceCreate(Sound* sound, bool pitchable, 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,7 +390,9 @@ Source* lovrSourceCreate(Sound* sound, bool spatial, uint32_t effects) { source->sound = sound; lovrRetain(source->sound); + source->pitch = 1.f; source->volume = 1.f; + source->pitchable = pitchable; source->spatial = spatial; source->effects = spatial ? effects : 0; quat_identity(source->orientation); @@ -400,8 +404,9 @@ Source* lovrSourceCreate(Sound* sound, bool spatial, uint32_t effects) { config.channelsOut = spatial ? 1 : 2; config.sampleRateIn = lovrSoundGetSampleRate(sound); config.sampleRateOut = state.sampleRate; + config.allowDynamicSampleRate = pitchable; - if (config.formatIn != config.formatOut || config.channelsIn != config.channelsOut || config.sampleRateIn != config.sampleRateOut) { + if (pitchable || config.formatIn != config.formatOut || config.channelsIn != config.channelsOut || config.sampleRateIn != config.sampleRateOut) { source->converter = malloc(sizeof(ma_data_converter)); lovrAssert(source->converter, "Out of memory"); ma_result status = ma_data_converter_init(&config, NULL, source->converter); @@ -418,6 +423,7 @@ Source* lovrSourceClone(Source* source) { clone->index = ~0u; clone->sound = source->sound; lovrRetain(clone->sound); + clone->pitch = source->pitch; clone->volume = source->volume; memcpy(clone->position, source->position, 4 * sizeof(float)); memcpy(clone->orientation, source->orientation, 4 * sizeof(float)); @@ -426,6 +432,7 @@ Source* lovrSourceClone(Source* source) { clone->dipolePower = source->dipolePower; clone->effects = source->effects; clone->looping = source->looping; + clone->pitchable = source->pitchable; clone->spatial = source->spatial; if (source->converter) { clone->converter = malloc(sizeof(ma_data_converter)); @@ -437,6 +444,7 @@ Source* lovrSourceClone(Source* source) { config.channelsOut = source->converter->channelsOut; config.sampleRateIn = source->converter->sampleRateIn; config.sampleRateOut = source->converter->sampleRateOut; + config.allowDynamicSampleRate = clone->pitchable; ma_result status = ma_data_converter_init(&config, NULL, clone->converter); lovrAssert(status == MA_SUCCESS, "Problem creating Source data converter: %s (%d)", ma_result_description(status), status); } @@ -500,6 +508,23 @@ void lovrSourceSetLooping(Source* source, bool loop) { source->looping = loop; } +float lovrSourceGetPitch(Source* source) { + return source->pitch; +} + +void lovrSourceSetPitch(Source* source, float pitch) { + lovrCheck(pitch > 0.f, "Source pitch must be positive"); + lovrCheck(source->pitchable, "Source must be created with the 'pitchable' flag to change its pitch"); + + if (source->pitch != pitch) { + source->pitch = pitch; + ma_mutex_lock(&state.lock); + float ratio = (float) lovrSoundGetSampleRate(source->sound) / state.sampleRate; + ma_data_converter_set_rate_ratio(source->converter, pitch * ratio); + ma_mutex_unlock(&state.lock); + } +} + float lovrSourceGetVolume(Source* source, VolumeUnit units) { return units == UNIT_LINEAR ? source->volume : linearToDb(source->volume); } diff --git a/src/modules/audio/audio.h b/src/modules/audio/audio.h index 89987b77..fec344ea 100644 --- a/src/modules/audio/audio.h +++ b/src/modules/audio/audio.h @@ -75,7 +75,7 @@ void lovrAudioSetAbsorption(float absorption[3]); // Source -Source* lovrSourceCreate(struct Sound* sound, bool spatial, uint32_t effects); +Source* lovrSourceCreate(struct Sound* sound, bool pitch, bool spatial, uint32_t effects); Source* lovrSourceClone(Source* source); void lovrSourceDestroy(void* ref); struct Sound* lovrSourceGetSound(Source* source); @@ -85,11 +85,14 @@ void lovrSourceStop(Source* source); bool lovrSourceIsPlaying(Source* source); bool lovrSourceIsLooping(Source* source); void lovrSourceSetLooping(Source* source, bool loop); +float lovrSourceGetPitch(Source* source); +void lovrSourceSetPitch(Source* source, float pitch); float lovrSourceGetVolume(Source* source, VolumeUnit units); 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 lovrSourceIsPitchable(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]);