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"
|
2021-02-09 02:52:56 +00:00
|
|
|
#include "data/sound.h"
|
2021-02-02 16:20:06 +00:00
|
|
|
#include "core/maf.h"
|
2020-12-25 19:50:26 +00:00
|
|
|
#include "core/util.h"
|
2021-03-16 00:54:27 +00:00
|
|
|
#include <lua.h>
|
|
|
|
#include <lauxlib.h>
|
2019-05-13 10:53:17 +00:00
|
|
|
#include <stdlib.h>
|
2017-01-03 03:09:33 +00:00
|
|
|
|
2021-03-03 22:25:03 +00:00
|
|
|
StringEntry lovrEffect[] = {
|
|
|
|
[EFFECT_ABSORPTION] = ENTRY("absorption"),
|
2021-03-22 17:58:08 +00:00
|
|
|
[EFFECT_ATTENUATION] = ENTRY("attenuation"),
|
2021-03-03 22:25:03 +00:00
|
|
|
[EFFECT_OCCLUSION] = ENTRY("occlusion"),
|
|
|
|
[EFFECT_REVERB] = ENTRY("reverb"),
|
|
|
|
[EFFECT_SPATIALIZATION] = ENTRY("spatialization"),
|
|
|
|
[EFFECT_TRANSMISSION] = ENTRY("transmission"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2021-02-28 22:27:20 +00:00
|
|
|
StringEntry lovrAudioMaterial[] = {
|
|
|
|
[MATERIAL_GENERIC] = ENTRY("generic"),
|
|
|
|
[MATERIAL_BRICK] = ENTRY("brick"),
|
|
|
|
[MATERIAL_CARPET] = ENTRY("carpet"),
|
|
|
|
[MATERIAL_CERAMIC] = ENTRY("ceramic"),
|
|
|
|
[MATERIAL_CONCRETE] = ENTRY("concrete"),
|
|
|
|
[MATERIAL_GLASS] = ENTRY("glass"),
|
|
|
|
[MATERIAL_GRAVEL] = ENTRY("gravel"),
|
|
|
|
[MATERIAL_METAL] = ENTRY("metal"),
|
|
|
|
[MATERIAL_PLASTER] = ENTRY("plaster"),
|
|
|
|
[MATERIAL_ROCK] = ENTRY("rock"),
|
|
|
|
[MATERIAL_WOOD] = ENTRY("wood"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2021-03-04 03:01:56 +00:00
|
|
|
StringEntry lovrAudioShareMode[] = {
|
|
|
|
[AUDIO_SHARED] = ENTRY("shared"),
|
|
|
|
[AUDIO_EXCLUSIVE] = ENTRY("exclusive"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2020-05-10 08:48:01 +00:00
|
|
|
StringEntry lovrAudioType[] = {
|
|
|
|
[AUDIO_PLAYBACK] = ENTRY("playback"),
|
|
|
|
[AUDIO_CAPTURE] = ENTRY("capture"),
|
2020-02-17 02:31:02 +00:00
|
|
|
{ 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 }
|
|
|
|
};
|
|
|
|
|
2021-03-19 23:20:21 +00:00
|
|
|
StringEntry lovrVolumeUnit[] = {
|
|
|
|
[UNIT_LINEAR] = ENTRY("linear"),
|
|
|
|
[UNIT_DECIBELS] = ENTRY("db"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2021-02-06 05:26:38 +00:00
|
|
|
static void onDevice(const void* id, size_t size, const char* name, bool isDefault, void* userdata) {
|
2021-02-04 18:25:06 +00:00
|
|
|
lua_State* L = userdata;
|
|
|
|
lua_createtable(L, 0, 3);
|
2021-02-06 05:26:38 +00:00
|
|
|
void* p = lua_newuserdata(L, size);
|
|
|
|
memcpy(p, id, size);
|
2021-02-04 18:25:06 +00:00
|
|
|
lua_setfield(L, -2, "id");
|
2021-02-06 05:26:38 +00:00
|
|
|
lua_pushstring(L, name);
|
2021-02-04 18:25:06 +00:00
|
|
|
lua_setfield(L, -2, "name");
|
2021-02-06 05:26:38 +00:00
|
|
|
lua_pushboolean(L, isDefault);
|
2021-02-04 18:25:06 +00:00
|
|
|
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");
|
|
|
|
void* id = lua_touserdata(L, 2);
|
2021-03-05 01:19:05 +00:00
|
|
|
size_t size = id ? luax_len(L, 2) : 0;
|
2021-03-04 03:01:56 +00:00
|
|
|
Sound* sink = lua_isnoneornil(L, 3) ? NULL : luax_checktype(L, 3, Sound);
|
|
|
|
AudioShareMode shareMode = luax_checkenum(L, 4, AudioShareMode, "shared");
|
|
|
|
bool success = lovrAudioSetDevice(type, id, size, sink, shareMode);
|
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);
|
2020-11-30 16:27:30 +00:00
|
|
|
return 1;
|
2017-01-06 05:36:38 +00:00
|
|
|
}
|
|
|
|
|
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");
|
2021-03-20 17:57:46 +00:00
|
|
|
bool stopped = lovrAudioStop(type);
|
|
|
|
lua_pushboolean(L, stopped);
|
|
|
|
return 1;
|
2017-02-26 20:57:56 +00:00
|
|
|
}
|
|
|
|
|
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) {
|
2021-03-19 23:20:21 +00:00
|
|
|
VolumeUnit units = luax_checkenum(L, 1, VolumeUnit, "linear");
|
|
|
|
lua_pushnumber(L, lovrAudioGetVolume(units));
|
2017-01-06 08:41:08 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-05-10 08:48:01 +00:00
|
|
|
static int l_lovrAudioSetVolume(lua_State* L) {
|
|
|
|
float volume = luax_checkfloat(L, 1);
|
2021-03-19 23:20:21 +00:00
|
|
|
VolumeUnit units = luax_checkenum(L, 2, VolumeUnit, "linear");
|
|
|
|
lovrAudioSetVolume(volume, units);
|
2020-05-10 08:48:01 +00:00
|
|
|
return 0;
|
2018-07-07 00:55:19 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 20:05:23 +00:00
|
|
|
static int l_lovrAudioGetPosition(lua_State* L) {
|
|
|
|
float position[4], orientation[4];
|
|
|
|
lovrAudioGetPose(position, orientation);
|
|
|
|
lua_pushnumber(L, position[0]);
|
|
|
|
lua_pushnumber(L, position[1]);
|
|
|
|
lua_pushnumber(L, position[2]);
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_lovrAudioSetPosition(lua_State* L) {
|
|
|
|
float position[4], orientation[4];
|
|
|
|
lovrAudioGetPose(position, orientation);
|
|
|
|
luax_readvec3(L, 1, position, NULL);
|
|
|
|
lovrAudioSetPose(position, orientation);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_lovrAudioGetOrientation(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, angle);
|
|
|
|
lua_pushnumber(L, ax);
|
|
|
|
lua_pushnumber(L, ay);
|
|
|
|
lua_pushnumber(L, az);
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_lovrAudioSetOrientation(lua_State* L) {
|
|
|
|
float position[4], orientation[4];
|
|
|
|
lovrAudioGetPose(position, orientation);
|
|
|
|
luax_readquat(L, 1, orientation, NULL);
|
|
|
|
lovrAudioSetPose(position, orientation);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-02-19 03:46:14 +00:00
|
|
|
static int l_lovrAudioSetGeometry(lua_State* L) {
|
|
|
|
float* vertices;
|
|
|
|
uint32_t* indices;
|
|
|
|
uint32_t vertexCount, indexCount;
|
|
|
|
bool shouldFree;
|
2021-02-28 21:58:15 +00:00
|
|
|
int index = luax_readmesh(L, 1, &vertices, &vertexCount, &indices, &indexCount, &shouldFree);
|
2021-02-28 22:27:20 +00:00
|
|
|
AudioMaterial material = luax_checkenum(L, index, AudioMaterial, "generic");
|
|
|
|
bool success = lovrAudioSetGeometry(vertices, indices, vertexCount, indexCount, material);
|
2021-02-19 03:46:14 +00:00
|
|
|
if (shouldFree) {
|
|
|
|
free(vertices);
|
|
|
|
free(indices);
|
|
|
|
}
|
|
|
|
lua_pushboolean(L, success);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-02-08 14:49:25 +00:00
|
|
|
static int l_lovrAudioGetSpatializer(lua_State *L) {
|
|
|
|
lua_pushstring(L, lovrAudioGetSpatializer());
|
2020-11-26 12:46:55 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-03-03 22:40:27 +00:00
|
|
|
static int l_lovrAudioGetAbsorption(lua_State* L) {
|
|
|
|
float absorption[3];
|
|
|
|
lovrAudioGetAbsorption(absorption);
|
|
|
|
lua_pushnumber(L, absorption[0]);
|
|
|
|
lua_pushnumber(L, absorption[1]);
|
|
|
|
lua_pushnumber(L, absorption[2]);
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_lovrAudioSetAbsorption(lua_State* L) {
|
|
|
|
float absorption[3];
|
|
|
|
absorption[0] = luax_checkfloat(L, 1);
|
|
|
|
absorption[1] = luax_checkfloat(L, 2);
|
|
|
|
absorption[2] = luax_checkfloat(L, 3);
|
|
|
|
lovrAudioSetAbsorption(absorption);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-01-30 02:24:32 +00:00
|
|
|
static int l_lovrAudioNewSource(lua_State* L) {
|
2021-02-09 02:52:56 +00:00
|
|
|
Sound* sound = luax_totype(L, 1, Sound);
|
2021-01-30 02:24:32 +00:00
|
|
|
|
|
|
|
bool spatial = true;
|
2021-02-22 20:24:09 +00:00
|
|
|
bool decode = false;
|
2021-03-18 19:00:23 +00:00
|
|
|
if (lua_gettop(L) >= 2) {
|
|
|
|
luaL_checktype(L, 2, LUA_TTABLE);
|
|
|
|
|
2021-01-30 02:24:32 +00:00
|
|
|
lua_getfield(L, 2, "spatial");
|
|
|
|
spatial = lua_isnil(L, -1) || lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1);
|
2021-02-22 20:24:09 +00:00
|
|
|
|
|
|
|
lua_getfield(L, 2, "decode");
|
|
|
|
decode = lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sound) {
|
|
|
|
Blob* blob = luax_readblob(L, 1, "Source");
|
|
|
|
sound = lovrSoundCreateFromFile(blob, decode);
|
|
|
|
lovrRelease(blob, lovrBlobDestroy);
|
|
|
|
} else {
|
|
|
|
lovrRetain(sound);
|
2021-01-30 02:24:32 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 00:40:58 +00:00
|
|
|
Source* source = lovrSourceCreate(sound, spatial);
|
2021-01-30 02:24:32 +00:00
|
|
|
luax_pushtype(L, Source, source);
|
2021-02-09 02:52:56 +00:00
|
|
|
lovrRelease(sound, lovrSoundDestroy);
|
2021-02-09 00:52:26 +00:00
|
|
|
lovrRelease(source, lovrSourceDestroy);
|
2021-01-30 02:24:32 +00:00
|
|
|
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-26 20:05:23 +00:00
|
|
|
{ "getPosition", l_lovrAudioGetPosition },
|
|
|
|
{ "setPosition", l_lovrAudioSetPosition },
|
|
|
|
{ "getOrientation", l_lovrAudioGetOrientation },
|
|
|
|
{ "setOrientation", l_lovrAudioSetOrientation },
|
2021-02-02 16:20:06 +00:00
|
|
|
{ "getPose", l_lovrAudioGetPose },
|
|
|
|
{ "setPose", l_lovrAudioSetPose },
|
2021-02-19 03:46:14 +00:00
|
|
|
{ "setGeometry", l_lovrAudioSetGeometry },
|
2021-02-02 16:20:06 +00:00
|
|
|
{ "getSpatializer", l_lovrAudioGetSpatializer },
|
2021-03-03 22:40:27 +00:00
|
|
|
{ "getAbsorption", l_lovrAudioGetAbsorption },
|
|
|
|
{ "setAbsorption", l_lovrAudioSetAbsorption },
|
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
|
|
|
|
2021-03-16 00:54:27 +00:00
|
|
|
extern const luaL_Reg lovrSource[];
|
|
|
|
|
2019-08-26 22:53:10 +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);
|
2019-04-05 10:48:36 +00:00
|
|
|
luax_registertype(L, Source);
|
2020-12-19 22:17:16 +00:00
|
|
|
|
2021-02-05 11:48:18 +00:00
|
|
|
bool start = true;
|
2020-12-21 17:28:39 +00:00
|
|
|
const char *spatializer = NULL;
|
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);
|
2020-12-19 22:17:16 +00:00
|
|
|
lua_pop(L, 1);
|
2021-02-05 11:48:18 +00:00
|
|
|
|
|
|
|
lua_getfield(L, -1, "start");
|
|
|
|
start = lua_isnil(L, -1) || lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1);
|
2020-12-19 22:17:16 +00:00
|
|
|
}
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
2021-02-04 18:25:06 +00:00
|
|
|
if (lovrAudioInit(spatializer)) {
|
2018-11-19 16:08:56 +00:00
|
|
|
luax_atexit(L, lovrAudioDestroy);
|
2021-02-05 11:48:18 +00:00
|
|
|
if (start) {
|
2021-03-04 03:01:56 +00:00
|
|
|
lovrAudioSetDevice(AUDIO_PLAYBACK, NULL, 0, NULL, AUDIO_SHARED);
|
2021-02-05 11:48:18 +00:00
|
|
|
lovrAudioStart(AUDIO_PLAYBACK);
|
|
|
|
}
|
2018-11-19 16:08:56 +00:00
|
|
|
}
|
2021-01-30 02:24:32 +00:00
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
return 1;
|
|
|
|
}
|