diff --git a/src/api/l_audio.c b/src/api/l_audio.c index 77b40dd5..cd64c800 100644 --- a/src/api/l_audio.c +++ b/src/api/l_audio.c @@ -202,6 +202,11 @@ static int l_lovrAudioGetSpatializer(lua_State *L) { return 1; } +static int l_lovrAudioGetSampleRate(lua_State *L) { + lua_pushnumber(L, lovrAudioGetSampleRate()); + return 1; +} + static int l_lovrAudioGetAbsorption(lua_State* L) { float absorption[3]; lovrAudioGetAbsorption(absorption); @@ -290,6 +295,7 @@ static const luaL_Reg lovrAudio[] = { { "setPose", l_lovrAudioSetPose }, { "setGeometry", l_lovrAudioSetGeometry }, { "getSpatializer", l_lovrAudioGetSpatializer }, + { "getSampleRate", l_lovrAudioGetSampleRate }, { "getAbsorption", l_lovrAudioGetAbsorption }, { "setAbsorption", l_lovrAudioSetAbsorption }, { "newSource", l_lovrAudioNewSource }, @@ -305,6 +311,7 @@ int luaopen_lovr_audio(lua_State* L) { bool start = true; const char *spatializer = NULL; + int sampleRate = DEFAULT_SAMPLE_RATE; luax_pushconf(L); lua_getfield(L, -1, "audio"); if (lua_istable(L, -1)) { @@ -312,13 +319,19 @@ int luaopen_lovr_audio(lua_State* L) { spatializer = lua_tostring(L, -1); lua_pop(L, 1); + lua_getfield(L, -1, "sampleRate"); + int userSampleRate = luaL_optnumber(L, -1, 0); + if (userSampleRate > 0) + sampleRate = userSampleRate; + lua_pop(L, 1); + lua_getfield(L, -1, "start"); start = lua_isnil(L, -1) || lua_toboolean(L, -1); lua_pop(L, 1); } lua_pop(L, 2); - if (lovrAudioInit(spatializer)) { + if (lovrAudioInit(spatializer, sampleRate)) { luax_atexit(L, lovrAudioDestroy); if (start) { lovrAudioSetDevice(AUDIO_PLAYBACK, NULL, 0, NULL, AUDIO_SHARED); diff --git a/src/modules/audio/audio.c b/src/modules/audio/audio.c index 24e02e88..5d276072 100644 --- a/src/modules/audio/audio.c +++ b/src/modules/audio/audio.c @@ -52,6 +52,7 @@ static struct { float leftovers[BUFFER_SIZE * 2]; float absorption[3]; ma_data_converter playbackConverter; + int sampleRate; } state; static const ma_format miniaudioFormats[] = { @@ -226,9 +227,11 @@ static Spatializer* spatializers[] = { // Entry -bool lovrAudioInit(const char* spatializer) { +bool lovrAudioInit(const char* spatializer, int sampleRate) { if (state.initialized) return false; + state.sampleRate = sampleRate; + ma_result result = ma_context_init(NULL, 0, NULL, &state.context); lovrAssert(result == MA_SUCCESS, "Failed to initialize miniaudio"); @@ -295,7 +298,7 @@ bool lovrAudioSetDevice(AudioType type, void* id, size_t size, Sound* sink, Audi // If no sink is provided for a capture device, one is created internally if (type == AUDIO_CAPTURE && !sink) { - sink = lovrSoundCreateStream(SAMPLE_RATE * 1., SAMPLE_F32, CHANNEL_MONO, SAMPLE_RATE); + sink = lovrSoundCreateStream(state.sampleRate * 1., SAMPLE_F32, CHANNEL_MONO, state.sampleRate); } else { lovrRetain(sink); } @@ -327,7 +330,7 @@ bool lovrAudioSetDevice(AudioType type, void* id, size_t size, Sound* sink, Audi config.playback.shareMode = shareModes[shareMode]; config.playback.format = ma_format_f32; config.playback.channels = OUTPUT_CHANNELS; - config.sampleRate = SAMPLE_RATE; + config.sampleRate = state.sampleRate; if (sink) { ma_data_converter_config converterConfig = ma_data_converter_config_init_default(); converterConfig.formatIn = config.playback.format; @@ -403,6 +406,10 @@ const char* lovrAudioGetSpatializer() { return state.spatializer->name; } +int lovrAudioGetSampleRate() { + return state.sampleRate; +} + void lovrAudioGetAbsorption(float absorption[3]) { memcpy(absorption, state.absorption, 3 * sizeof(float)); } @@ -434,7 +441,7 @@ Source* lovrSourceCreate(Sound* sound, uint32_t effects) { config.channelsIn = lovrSoundGetChannelCount(sound); config.channelsOut = lovrSourceUsesSpatializer(source) ? 1 : 2; // See onPlayback config.sampleRateIn = lovrSoundGetSampleRate(sound); - config.sampleRateOut = SAMPLE_RATE; + config.sampleRateOut = state.sampleRate; if (config.formatIn != config.formatOut || config.channelsIn != config.channelsOut || config.sampleRateIn != config.sampleRateOut) { source->converter = malloc(sizeof(ma_data_converter)); diff --git a/src/modules/audio/audio.h b/src/modules/audio/audio.h index 5f7412ff..4877d586 100644 --- a/src/modules/audio/audio.h +++ b/src/modules/audio/audio.h @@ -4,7 +4,7 @@ #pragma once -#define SAMPLE_RATE 48000 +#define DEFAULT_SAMPLE_RATE 48000 #define BUFFER_SIZE 256 #define MAX_SOURCES 64 @@ -59,7 +59,7 @@ typedef enum { typedef void AudioDeviceCallback(const void* id, size_t size, const char* name, bool isDefault, void* userdata); -bool lovrAudioInit(const char* spatializer); +bool lovrAudioInit(const char* spatializer, int sampleRate); void lovrAudioDestroy(void); void lovrAudioEnumerateDevices(AudioType type, AudioDeviceCallback* callback, void* userdata); bool lovrAudioSetDevice(AudioType type, void* id, size_t size, struct Sound* sink, AudioShareMode shareMode); @@ -72,6 +72,7 @@ void lovrAudioGetPose(float position[4], float orientation[4]); void lovrAudioSetPose(float position[4], float orientation[4]); bool lovrAudioSetGeometry(float* vertices, uint32_t* indices, uint32_t vertexCount, uint32_t indexCount, AudioMaterial material); const char* lovrAudioGetSpatializer(void); +int lovrAudioGetSampleRate(); void lovrAudioGetAbsorption(float absorption[3]); void lovrAudioSetAbsorption(float absorption[3]); diff --git a/src/modules/audio/spatializer_oculus.c b/src/modules/audio/spatializer_oculus.c index 25c2f125..3f4289c9 100644 --- a/src/modules/audio/spatializer_oculus.c +++ b/src/modules/audio/spatializer_oculus.c @@ -106,7 +106,7 @@ static bool oculus_init(void) { config.acc_Size = sizeof(config); config.acc_MaxNumSources = MAX_SOURCES; - config.acc_SampleRate = SAMPLE_RATE; + config.acc_SampleRate = lovrAudioGetSampleRate(); config.acc_BufferLength = BUFFER_SIZE; // Stereo if (ovrAudio_CreateContext(&state.context, &config) != ovrSuccess) { diff --git a/src/modules/audio/spatializer_phonon.c b/src/modules/audio/spatializer_phonon.c index 46dc4ddf..7aa8d9ba 100644 --- a/src/modules/audio/spatializer_phonon.c +++ b/src/modules/audio/spatializer_phonon.c @@ -146,7 +146,7 @@ bool phonon_init() { status = phonon_iplCreateEnvironment(state.context, NULL, simulationSettings, NULL, NULL, &state.environment); if (status != IPL_STATUS_SUCCESS) return phonon_destroy(), false; - state.renderingSettings.samplingRate = SAMPLE_RATE; + state.renderingSettings.samplingRate = lovrAudioGetSampleRate(); state.renderingSettings.frameSize = BUFFER_SIZE; state.renderingSettings.convolutionType = IPL_CONVOLUTIONTYPE_PHONON; diff --git a/src/modules/audio/spatializer_simple.c b/src/modules/audio/spatializer_simple.c index 1ede8219..42190062 100644 --- a/src/modules/audio/spatializer_simple.c +++ b/src/modules/audio/spatializer_simple.c @@ -60,7 +60,7 @@ uint32_t simple_apply(Source* source, const float* input, float* output, uint32_ float* gain = state.gain[index]; float lerpDuration = .05f; - float lerpFrames = SAMPLE_RATE * lerpDuration; + float lerpFrames = lovrAudioGetSampleRate() * lerpDuration; float lerpRate = 1.f / lerpFrames; for (uint32_t c = 0; c < 2; c++) {