lovr/src/api/l_audio.c

193 lines
5.1 KiB
C
Raw Normal View History

2017-12-10 20:40:37 +00:00
#include "api.h"
2017-01-03 03:09:33 +00:00
#include "audio/audio.h"
2019-05-18 00:11:22 +00:00
#include "data/blob.h"
2019-04-05 11:16:34 +00:00
#include "data/soundData.h"
2021-02-02 16:20:06 +00:00
#include "core/maf.h"
#include "core/ref.h"
2020-12-25 19:50:26 +00:00
#include "core/util.h"
2019-05-13 10:53:17 +00:00
#include <stdlib.h>
2017-01-03 03:09:33 +00:00
2020-05-10 08:48:01 +00:00
StringEntry lovrAudioType[] = {
[AUDIO_PLAYBACK] = ENTRY("playback"),
[AUDIO_CAPTURE] = ENTRY("capture"),
{ 0 }
2018-07-06 05:08:14 +00:00
};
2021-02-04 18:25:06 +00:00
StringEntry lovrTimeUnit[] = {
[UNIT_SECONDS] = ENTRY("seconds"),
[UNIT_FRAMES] = ENTRY("frames"),
{ 0 }
};
static void onDevice(AudioDevice* device, void* userdata) {
lua_State* L = userdata;
lua_createtable(L, 0, 3);
void* id = lua_newuserdata(L, device->idSize);
memcpy(id, device->id, device->idSize);
lua_setfield(L, -2, "id");
lua_pushstring(L, device->name);
lua_setfield(L, -2, "name");
lua_pushboolean(L, device->isDefault);
lua_setfield(L, -2, "default");
lua_rawseti(L, -2, luax_len(L, -2) + 1);
}
static int l_lovrAudioGetDevices(lua_State *L) {
AudioType type = luax_checkenum(L, 1, AudioType, "playback");
lua_newtable(L);
lovrAudioEnumerateDevices(type, onDevice, L);
return 1;
}
static int l_lovrAudioSetDevice(lua_State *L) {
AudioType type = luax_checkenum(L, 1, AudioType, "playback");
luaL_checkany(L, 2);
2021-02-04 18:25:06 +00:00
void* id = lua_touserdata(L, 2);
size_t size = luax_len(L, 2);
2021-02-05 05:25:50 +00:00
uint32_t sampleRate = lua_tointeger(L, 3);
SampleFormat format = luax_checkenum(L, 4, SampleFormat, "f32");
bool exclusive = lua_toboolean(L, 5);
bool success = lovrAudioSetDevice(type, id, size, sampleRate, format, exclusive);
2021-02-04 18:25:06 +00:00
lua_pushboolean(L, success);
return 1;
}
2020-05-10 08:48:01 +00:00
static int l_lovrAudioStart(lua_State* L) {
2020-11-21 03:47:59 +00:00
AudioType type = luax_checkenum(L, 1, AudioType, "playback");
2021-01-30 02:24:32 +00:00
bool started = lovrAudioStart(type);
2020-12-02 15:56:06 +00:00
lua_pushboolean(L, started);
return 1;
}
2020-05-10 08:48:01 +00:00
static int l_lovrAudioStop(lua_State* L) {
2020-11-21 03:47:59 +00:00
AudioType type = luax_checkenum(L, 1, AudioType, "playback");
2020-05-10 08:48:01 +00:00
lovrAudioStop(type);
return 0;
}
2021-02-02 16:20:06 +00:00
static int l_lovrAudioIsStarted(lua_State* L) {
2020-12-17 10:41:46 +00:00
AudioType type = luax_checkenum(L, 1, AudioType, "playback");
2021-02-02 16:20:06 +00:00
bool started = lovrAudioIsStarted(type);
lua_pushboolean(L, started);
2020-12-17 10:41:46 +00:00
return 1;
}
2018-09-27 01:27:38 +00:00
static int l_lovrAudioGetVolume(lua_State* L) {
lua_pushnumber(L, lovrAudioGetVolume());
return 1;
}
2020-05-10 08:48:01 +00:00
static int l_lovrAudioSetVolume(lua_State* L) {
float volume = luax_checkfloat(L, 1);
lovrAudioSetVolume(volume);
return 0;
}
2021-02-02 16:20:06 +00:00
static int l_lovrAudioGetPose(lua_State *L) {
float position[4], orientation[4], angle, ax, ay, az;
lovrAudioGetPose(position, orientation);
quat_getAngleAxis(orientation, &angle, &ax, &ay, &az);
lua_pushnumber(L, position[0]);
lua_pushnumber(L, position[1]);
lua_pushnumber(L, position[2]);
lua_pushnumber(L, angle);
lua_pushnumber(L, ax);
lua_pushnumber(L, ay);
lua_pushnumber(L, az);
return 7;
}
static int l_lovrAudioSetPose(lua_State *L) {
2020-11-25 21:28:43 +00:00
int index = 1;
2021-02-04 18:25:06 +00:00
float position[4], orientation[4];
2020-11-25 21:28:43 +00:00
index = luax_readvec3(L, index, position, NULL);
index = luax_readquat(L, index, orientation, NULL);
2021-02-02 16:20:06 +00:00
lovrAudioSetPose(position, orientation);
2020-11-25 21:28:43 +00:00
return 0;
}
static int l_lovrAudioGetCaptureStream(lua_State* L) {
SoundData* soundData = lovrAudioGetCaptureStream();
2020-11-26 12:46:55 +00:00
luax_pushtype(L, SoundData, soundData);
return 1;
}
2021-02-02 16:20:06 +00:00
static int l_lovrAudioGetSpatializer(lua_State *L) {
lua_pushstring(L, lovrAudioGetSpatializer());
LOVR_USE_OCULUS_AUDIO This is a large patch which adds a new Oculus Audio spatializer. Oculus Audio is slightly different from the dummy spatializer in a few ways: - It *must* receive fixed-size input buffers, every time, always. - It can only handle a fixed number of spatialized sound sources at a time. - It has a concept of "tails"; the spatialization of a sound can continue after the sound itself ends (eg echo). Changes to audio.c were needed to support Oculus Audio's quirks: - audio.c now supports a "fixedBuffer" mode which invokes the generator/spatializer in fixed size chunks - Each source now has an intptr_t "memo" field that the spatializer may use to store whatever (Oculus spatializer uses this to handle the sound source limit). - The spatializer interface got a couple new methods: A "tail" method which returns a sound buffer after all sources are processed; and "create" and "destroy" methods that are called when a sound source is created or destroyed (Oculus spatializer uses this to populate/clear the "memo" field). Along the way some other miscellaneous changes got made: - lovr.audio.getSpatializerName() returns the current spatializer - Spatializer init now takes in "config in" and "config out" structs (Spatializer changes fields in config out to request things, currently fixed buffer mode). - lovr.conf now takes t.audio.spatializer (string name of desired spatializer) and t.audio.spatializerMaxSourcesHint (Spatializers with max sources limits like Oculus will use this as the limit). - audio.c went back to tracking position/orientation as vectors rather than a matrix - A file oculus_spatializer_math_shim.h was added containing a minimal copypaste of OVR_CAPI.h from Oculus SDK to support a ovrPoseStatef the spatializer API needs. This may have license consequences but we are probably OK via a combination of fair use and the fact that a user cannot use this header file without accepting Oculus's license through other means. Some work remains to be done, in particular there is an entire reverb feature I did not touch and LOVR_USE_OCULUS_AUDIO cannot be activated from tup. Oculus Spatializer works better when it has velocity and time information but this patch does not supply it.
2020-12-19 22:17:16 +00:00
return 1;
}
2021-01-30 02:24:32 +00:00
static int l_lovrAudioNewSource(lua_State* L) {
Source* source = NULL;
SoundData* soundData = luax_totype(L, 1, SoundData);
bool spatial = true;
if (lua_istable(L, 2)) {
lua_getfield(L, 2, "spatial");
spatial = lua_isnil(L, -1) || lua_toboolean(L, -1);
lua_pop(L, 1);
}
if (soundData) {
source = lovrSourceCreate(soundData, spatial);
} else {
Blob* blob = luax_readblob(L, 1, "Source");
soundData = lovrSoundDataCreateFromFile(blob, false);
lovrRelease(Blob, blob);
source = lovrSourceCreate(soundData, spatial);
lovrRelease(SoundData, soundData);
}
luax_pushtype(L, Source, source);
lovrRelease(Source, source);
return 1;
}
2018-09-27 01:27:38 +00:00
static const luaL_Reg lovrAudio[] = {
2021-02-04 18:25:06 +00:00
{ "getDevices", l_lovrAudioGetDevices },
{ "setDevice", l_lovrAudioSetDevice },
2020-05-10 08:48:01 +00:00
{ "start", l_lovrAudioStart },
{ "stop", l_lovrAudioStop },
2021-02-02 16:20:06 +00:00
{ "isStarted", l_lovrAudioIsStarted },
2017-03-11 11:08:07 +00:00
{ "getVolume", l_lovrAudioGetVolume },
{ "setVolume", l_lovrAudioSetVolume },
2021-02-02 16:20:06 +00:00
{ "getPose", l_lovrAudioGetPose },
{ "setPose", l_lovrAudioSetPose },
{ "getCaptureStream", l_lovrAudioGetCaptureStream },
2021-02-02 16:20:06 +00:00
{ "getSpatializer", l_lovrAudioGetSpatializer },
2021-01-30 02:24:32 +00:00
{ "newSource", l_lovrAudioNewSource },
2017-03-11 11:08:07 +00:00
{ NULL, NULL }
};
2018-09-27 01:27:38 +00:00
int luaopen_lovr_audio(lua_State* L) {
2018-09-27 01:27:38 +00:00
lua_newtable(L);
2020-08-19 19:12:06 +00:00
luax_register(L, lovrAudio);
luax_registertype(L, Source);
LOVR_USE_OCULUS_AUDIO This is a large patch which adds a new Oculus Audio spatializer. Oculus Audio is slightly different from the dummy spatializer in a few ways: - It *must* receive fixed-size input buffers, every time, always. - It can only handle a fixed number of spatialized sound sources at a time. - It has a concept of "tails"; the spatialization of a sound can continue after the sound itself ends (eg echo). Changes to audio.c were needed to support Oculus Audio's quirks: - audio.c now supports a "fixedBuffer" mode which invokes the generator/spatializer in fixed size chunks - Each source now has an intptr_t "memo" field that the spatializer may use to store whatever (Oculus spatializer uses this to handle the sound source limit). - The spatializer interface got a couple new methods: A "tail" method which returns a sound buffer after all sources are processed; and "create" and "destroy" methods that are called when a sound source is created or destroyed (Oculus spatializer uses this to populate/clear the "memo" field). Along the way some other miscellaneous changes got made: - lovr.audio.getSpatializerName() returns the current spatializer - Spatializer init now takes in "config in" and "config out" structs (Spatializer changes fields in config out to request things, currently fixed buffer mode). - lovr.conf now takes t.audio.spatializer (string name of desired spatializer) and t.audio.spatializerMaxSourcesHint (Spatializers with max sources limits like Oculus will use this as the limit). - audio.c went back to tracking position/orientation as vectors rather than a matrix - A file oculus_spatializer_math_shim.h was added containing a minimal copypaste of OVR_CAPI.h from Oculus SDK to support a ovrPoseStatef the spatializer API needs. This may have license consequences but we are probably OK via a combination of fair use and the fact that a user cannot use this header file without accepting Oculus's license through other means. Some work remains to be done, in particular there is an entire reverb feature I did not touch and LOVR_USE_OCULUS_AUDIO cannot be activated from tup. Oculus Spatializer works better when it has velocity and time information but this patch does not supply it.
2020-12-19 22:17:16 +00:00
bool start = true;
const char *spatializer = NULL;
LOVR_USE_OCULUS_AUDIO This is a large patch which adds a new Oculus Audio spatializer. Oculus Audio is slightly different from the dummy spatializer in a few ways: - It *must* receive fixed-size input buffers, every time, always. - It can only handle a fixed number of spatialized sound sources at a time. - It has a concept of "tails"; the spatialization of a sound can continue after the sound itself ends (eg echo). Changes to audio.c were needed to support Oculus Audio's quirks: - audio.c now supports a "fixedBuffer" mode which invokes the generator/spatializer in fixed size chunks - Each source now has an intptr_t "memo" field that the spatializer may use to store whatever (Oculus spatializer uses this to handle the sound source limit). - The spatializer interface got a couple new methods: A "tail" method which returns a sound buffer after all sources are processed; and "create" and "destroy" methods that are called when a sound source is created or destroyed (Oculus spatializer uses this to populate/clear the "memo" field). Along the way some other miscellaneous changes got made: - lovr.audio.getSpatializerName() returns the current spatializer - Spatializer init now takes in "config in" and "config out" structs (Spatializer changes fields in config out to request things, currently fixed buffer mode). - lovr.conf now takes t.audio.spatializer (string name of desired spatializer) and t.audio.spatializerMaxSourcesHint (Spatializers with max sources limits like Oculus will use this as the limit). - audio.c went back to tracking position/orientation as vectors rather than a matrix - A file oculus_spatializer_math_shim.h was added containing a minimal copypaste of OVR_CAPI.h from Oculus SDK to support a ovrPoseStatef the spatializer API needs. This may have license consequences but we are probably OK via a combination of fair use and the fact that a user cannot use this header file without accepting Oculus's license through other means. Some work remains to be done, in particular there is an entire reverb feature I did not touch and LOVR_USE_OCULUS_AUDIO cannot be activated from tup. Oculus Spatializer works better when it has velocity and time information but this patch does not supply it.
2020-12-19 22:17:16 +00:00
luax_pushconf(L);
lua_getfield(L, -1, "audio");
if (lua_istable(L, -1)) {
lua_getfield(L, -1, "spatializer");
2021-02-04 18:25:06 +00:00
spatializer = lua_tostring(L, -1);
LOVR_USE_OCULUS_AUDIO This is a large patch which adds a new Oculus Audio spatializer. Oculus Audio is slightly different from the dummy spatializer in a few ways: - It *must* receive fixed-size input buffers, every time, always. - It can only handle a fixed number of spatialized sound sources at a time. - It has a concept of "tails"; the spatialization of a sound can continue after the sound itself ends (eg echo). Changes to audio.c were needed to support Oculus Audio's quirks: - audio.c now supports a "fixedBuffer" mode which invokes the generator/spatializer in fixed size chunks - Each source now has an intptr_t "memo" field that the spatializer may use to store whatever (Oculus spatializer uses this to handle the sound source limit). - The spatializer interface got a couple new methods: A "tail" method which returns a sound buffer after all sources are processed; and "create" and "destroy" methods that are called when a sound source is created or destroyed (Oculus spatializer uses this to populate/clear the "memo" field). Along the way some other miscellaneous changes got made: - lovr.audio.getSpatializerName() returns the current spatializer - Spatializer init now takes in "config in" and "config out" structs (Spatializer changes fields in config out to request things, currently fixed buffer mode). - lovr.conf now takes t.audio.spatializer (string name of desired spatializer) and t.audio.spatializerMaxSourcesHint (Spatializers with max sources limits like Oculus will use this as the limit). - audio.c went back to tracking position/orientation as vectors rather than a matrix - A file oculus_spatializer_math_shim.h was added containing a minimal copypaste of OVR_CAPI.h from Oculus SDK to support a ovrPoseStatef the spatializer API needs. This may have license consequences but we are probably OK via a combination of fair use and the fact that a user cannot use this header file without accepting Oculus's license through other means. Some work remains to be done, in particular there is an entire reverb feature I did not touch and LOVR_USE_OCULUS_AUDIO cannot be activated from tup. Oculus Spatializer works better when it has velocity and time information but this patch does not supply it.
2020-12-19 22:17:16 +00:00
lua_pop(L, 1);
lua_getfield(L, -1, "start");
start = lua_isnil(L, -1) || lua_toboolean(L, -1);
lua_pop(L, 1);
LOVR_USE_OCULUS_AUDIO This is a large patch which adds a new Oculus Audio spatializer. Oculus Audio is slightly different from the dummy spatializer in a few ways: - It *must* receive fixed-size input buffers, every time, always. - It can only handle a fixed number of spatialized sound sources at a time. - It has a concept of "tails"; the spatialization of a sound can continue after the sound itself ends (eg echo). Changes to audio.c were needed to support Oculus Audio's quirks: - audio.c now supports a "fixedBuffer" mode which invokes the generator/spatializer in fixed size chunks - Each source now has an intptr_t "memo" field that the spatializer may use to store whatever (Oculus spatializer uses this to handle the sound source limit). - The spatializer interface got a couple new methods: A "tail" method which returns a sound buffer after all sources are processed; and "create" and "destroy" methods that are called when a sound source is created or destroyed (Oculus spatializer uses this to populate/clear the "memo" field). Along the way some other miscellaneous changes got made: - lovr.audio.getSpatializerName() returns the current spatializer - Spatializer init now takes in "config in" and "config out" structs (Spatializer changes fields in config out to request things, currently fixed buffer mode). - lovr.conf now takes t.audio.spatializer (string name of desired spatializer) and t.audio.spatializerMaxSourcesHint (Spatializers with max sources limits like Oculus will use this as the limit). - audio.c went back to tracking position/orientation as vectors rather than a matrix - A file oculus_spatializer_math_shim.h was added containing a minimal copypaste of OVR_CAPI.h from Oculus SDK to support a ovrPoseStatef the spatializer API needs. This may have license consequences but we are probably OK via a combination of fair use and the fact that a user cannot use this header file without accepting Oculus's license through other means. Some work remains to be done, in particular there is an entire reverb feature I did not touch and LOVR_USE_OCULUS_AUDIO cannot be activated from tup. Oculus Spatializer works better when it has velocity and time information but this patch does not supply it.
2020-12-19 22:17:16 +00:00
}
lua_pop(L, 2);
2021-02-04 18:25:06 +00:00
if (lovrAudioInit(spatializer)) {
luax_atexit(L, lovrAudioDestroy);
if (start) {
lovrAudioSetDevice(AUDIO_PLAYBACK, NULL, 0, PLAYBACK_SAMPLE_RATE, SAMPLE_F32, false);
lovrAudioStart(AUDIO_PLAYBACK);
}
}
2021-01-30 02:24:32 +00:00
2018-09-27 01:27:38 +00:00
return 1;
}