From b650f2b770beed1eb95a7170ae82e99420ac3a02 Mon Sep 17 00:00:00 2001 From: bjorn Date: Fri, 6 Jul 2018 17:55:19 -0700 Subject: [PATCH] Add Microphone objects for audio capture; --- CMakeLists.txt | 2 + src/api.h | 1 + src/api/audio.c | 35 +++++++++++++++ src/api/types/microphone.c | 70 +++++++++++++++++++++++++++++ src/audio/audio.c | 23 ++++++++++ src/audio/audio.h | 6 +++ src/audio/microphone.c | 90 ++++++++++++++++++++++++++++++++++++++ src/audio/microphone.h | 29 ++++++++++++ src/audio/source.c | 23 ++-------- 9 files changed, 260 insertions(+), 19 deletions(-) create mode 100644 src/api/types/microphone.c create mode 100644 src/audio/microphone.c create mode 100644 src/audio/microphone.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5870f5a1..f949fbe3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,6 +255,7 @@ set(LOVR_SRC src/api/types/joints.c src/api/types/material.c src/api/types/mesh.c + src/api/types/microphone.c src/api/types/model.c src/api/types/modelData.c src/api/types/randomGenerator.c @@ -269,6 +270,7 @@ set(LOVR_SRC src/api/types/vertexData.c src/api/types/world.c src/audio/audio.c + src/audio/microphone.c src/audio/source.c src/data/audioStream.c src/data/blob.c diff --git a/src/api.h b/src/api.h index 5825236e..ace84db2 100644 --- a/src/api.h +++ b/src/api.h @@ -49,6 +49,7 @@ extern const luaL_Reg lovrHingeJoint[]; extern const luaL_Reg lovrJoint[]; extern const luaL_Reg lovrMaterial[]; extern const luaL_Reg lovrMesh[]; +extern const luaL_Reg lovrMicrophone[]; extern const luaL_Reg lovrModel[]; extern const luaL_Reg lovrModelData[]; extern const luaL_Reg lovrRandomGenerator[]; diff --git a/src/api/audio.c b/src/api/audio.c index 519352a0..8ce50bdb 100644 --- a/src/api/audio.c +++ b/src/api/audio.c @@ -18,6 +18,7 @@ const char* TimeUnits[] = { int l_lovrAudioInit(lua_State* L) { lua_newtable(L); luaL_register(L, NULL, lovrAudio); + luax_registertype(L, "Microphone", lovrMicrophone); luax_registertype(L, "Source", lovrSource); lovrAudioInit(); return 1; @@ -36,6 +37,26 @@ int l_lovrAudioGetDopplerEffect(lua_State* L) { return 2; } +int l_lovrAudioGetMicrophoneNames(lua_State* L) { + const char* names[MAX_MICROPHONES]; + uint8_t count; + lovrAudioGetMicrophoneNames(names, &count); + + if (lua_istable(L, 1)) { + lua_settop(L, 1); + } else { + lua_settop(L, 0); + lua_createtable(L, count, 0); + } + + for (int i = 0; i < count; i++) { + lua_pushstring(L, names[i]); + lua_rawseti(L, -2, i + 1); + } + + return 1; +} + int l_lovrAudioGetOrientation(lua_State* L) { float angle, ax, ay, az; lovrAudioGetOrientation(&angle, &ax, &ay, &az); @@ -74,6 +95,18 @@ int l_lovrAudioIsSpatialized(lua_State* L) { return 1; } +int l_lovrAudioNewMicrophone(lua_State* L) { + const char* name = luaL_optstring(L, 1, NULL); + int samples = luaL_optinteger(L, 2, 1024); + int sampleRate = luaL_optinteger(L, 3, 8000); + int bitDepth = luaL_optinteger(L, 4, 16); + int channelCount = luaL_optinteger(L, 5, 1); + Microphone* microphone = lovrMicrophoneCreate(name, samples, sampleRate, bitDepth, channelCount); + luax_pushtype(L, Microphone, microphone); + lovrRelease(microphone); + return 1; +} + int l_lovrAudioNewSource(lua_State* L) { Source* source = NULL; SoundData** soundDataRef = luax_totype(L, 1, SoundData); @@ -177,11 +210,13 @@ int l_lovrAudioStop(lua_State* L) { const luaL_Reg lovrAudio[] = { { "update", l_lovrAudioUpdate }, { "getDopplerEffect", l_lovrAudioGetDopplerEffect }, + { "getMicrophoneNames", l_lovrAudioGetMicrophoneNames }, { "getOrientation", l_lovrAudioGetOrientation }, { "getPosition", l_lovrAudioGetPosition }, { "getVelocity", l_lovrAudioGetVelocity }, { "getVolume", l_lovrAudioGetVolume }, { "isSpatialized", l_lovrAudioIsSpatialized }, + { "newMicrophone", l_lovrAudioNewMicrophone }, { "newSource", l_lovrAudioNewSource }, { "pause", l_lovrAudioPause }, { "resume", l_lovrAudioResume }, diff --git a/src/api/types/microphone.c b/src/api/types/microphone.c new file mode 100644 index 00000000..bb54fc4b --- /dev/null +++ b/src/api/types/microphone.c @@ -0,0 +1,70 @@ +#include "api.h" +#include "audio/microphone.h" + +int l_lovrMicrophoneGetBitDepth(lua_State* L) { + Microphone* microphone = luax_checktype(L, 1, Microphone); + lua_pushinteger(L, lovrMicrophoneGetBitDepth(microphone)); + return 1; +} + +int l_lovrMicrophoneGetChannelCount(lua_State* L) { + Microphone* microphone = luax_checktype(L, 1, Microphone); + lua_pushinteger(L, lovrMicrophoneGetChannelCount(microphone)); + return 1; +} + +int l_lovrMicrophoneGetData(lua_State* L) { + Microphone* microphone = luax_checktype(L, 1, Microphone); + SoundData* soundData = lovrMicrophoneGetData(microphone); + luax_pushtype(L, SoundData, soundData); + return 1; +} + +int l_lovrMicrophoneGetName(lua_State* L) { + Microphone* microphone = luax_checktype(L, 1, Microphone); + lua_pushstring(L, lovrMicrophoneGetName(microphone)); + return 1; +} + +int l_lovrMicrophoneGetSampleCount(lua_State* L) { + Microphone* microphone = luax_checktype(L, 1, Microphone); + lua_pushinteger(L, lovrMicrophoneGetSampleCount(microphone)); + return 1; +} + +int l_lovrMicrophoneGetSampleRate(lua_State* L) { + Microphone* microphone = luax_checktype(L, 1, Microphone); + lua_pushinteger(L, lovrMicrophoneGetSampleRate(microphone)); + return 1; +} + +int l_lovrMicrophoneIsRecording(lua_State* L) { + Microphone* microphone = luax_checktype(L, 1, Microphone); + lua_pushboolean(L, lovrMicrophoneIsRecording(microphone)); + return 1; +} + +int l_lovrMicrophoneStartRecording(lua_State* L) { + Microphone* microphone = luax_checktype(L, 1, Microphone); + lovrMicrophoneStartRecording(microphone); + return 0; +} + +int l_lovrMicrophoneStopRecording(lua_State* L) { + Microphone* microphone = luax_checktype(L, 1, Microphone); + lovrMicrophoneStopRecording(microphone); + return 0; +} + +const luaL_Reg lovrMicrophone[] = { + { "getBitDepth", l_lovrMicrophoneGetBitDepth }, + { "getChannelCount", l_lovrMicrophoneGetChannelCount }, + { "getData", l_lovrMicrophoneGetData }, + { "getName", l_lovrMicrophoneGetName }, + { "getSampleCount", l_lovrMicrophoneGetSampleCount }, + { "getSampleRate", l_lovrMicrophoneGetSampleRate }, + { "isRecording", l_lovrMicrophoneIsRecording }, + { "startRecording", l_lovrMicrophoneStartRecording }, + { "stopRecording", l_lovrMicrophoneStopRecording }, + { NULL, NULL } +}; diff --git a/src/audio/audio.c b/src/audio/audio.c index a4d4cf2b..7a9b5fce 100644 --- a/src/audio/audio.c +++ b/src/audio/audio.c @@ -6,6 +6,20 @@ static AudioState state; +ALenum lovrAudioConvertFormat(int bitDepth, int channelCount) { + if (bitDepth == 8 && channelCount == 1) { + return AL_FORMAT_MONO8; + } else if (bitDepth == 8 && channelCount == 2) { + return AL_FORMAT_STEREO8; + } else if (bitDepth == 16 && channelCount == 1) { + return AL_FORMAT_MONO16; + } else if (bitDepth == 16 && channelCount == 2) { + return AL_FORMAT_STEREO16; + } + + return 0; +} + void lovrAudioInit() { if (state.initialized) return; @@ -84,6 +98,15 @@ void lovrAudioGetDopplerEffect(float* factor, float* speedOfSound) { alGetFloatv(AL_SPEED_OF_SOUND, speedOfSound); } +void lovrAudioGetMicrophoneNames(const char* names[MAX_MICROPHONES], uint8_t* count) { + const char* name = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); + *count = 0; + while (*name) { + names[(*count)++] = name; + name += strlen(name); + } +} + void lovrAudioGetOrientation(float* angle, float* ax, float* ay, float* az) { quat_getAngleAxis(state.orientation, angle, ax, ay, az); } diff --git a/src/audio/audio.h b/src/audio/audio.h index f2ffec09..e9c7181f 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -1,4 +1,5 @@ #include "audio/source.h" +#include "audio/microphone.h" #include "lib/vec/vec.h" #include #include @@ -7,6 +8,8 @@ #pragma once +#define MAX_MICROPHONES 8 + typedef struct { bool initialized; ALCdevice* device; @@ -18,11 +21,14 @@ typedef struct { float velocity[3]; } AudioState; +ALenum lovrAudioConvertFormat(int bitDepth, int channelCount); + void lovrAudioInit(); void lovrAudioDestroy(); void lovrAudioUpdate(); void lovrAudioAdd(Source* source); void lovrAudioGetDopplerEffect(float* factor, float* speedOfSound); +void lovrAudioGetMicrophoneNames(const char* names[MAX_MICROPHONES], uint8_t* count); void lovrAudioGetOrientation(float* angle, float* ax, float* ay, float* az); void lovrAudioGetPosition(float* x, float* y, float* z); void lovrAudioGetVelocity(float* x, float* y, float* z); diff --git a/src/audio/microphone.c b/src/audio/microphone.c new file mode 100644 index 00000000..0da3af02 --- /dev/null +++ b/src/audio/microphone.c @@ -0,0 +1,90 @@ +#include "audio/microphone.h" +#include "audio/audio.h" + +Microphone* lovrMicrophoneCreate(const char* name, int samples, int sampleRate, int bitDepth, int channelCount) { + Microphone* microphone = lovrAlloc(sizeof(Microphone), lovrMicrophoneDestroy); + if (!microphone) return NULL; + + ALCdevice* device = alcCaptureOpenDevice(name, sampleRate, lovrAudioConvertFormat(bitDepth, channelCount), samples); + + if (!device) { + free(microphone); + return NULL; + } + + microphone->device = device; + microphone->name = name ? name : alcGetString(device, ALC_CAPTURE_DEVICE_SPECIFIER); + microphone->sampleRate = sampleRate; + microphone->bitDepth = bitDepth; + microphone->channelCount = channelCount; + + return microphone; +} + +void lovrMicrophoneDestroy(void* ref) { + Microphone* microphone = ref; + alcCaptureCloseDevice(microphone->device); + free(microphone); +} + +int lovrMicrophoneGetBitDepth(Microphone* microphone) { + return microphone->bitDepth; +} + +int lovrMicrophoneGetChannelCount(Microphone* microphone) { + return microphone->channelCount; +} + +SoundData* lovrMicrophoneGetData(Microphone* microphone) { + if (!microphone->isRecording) { + return NULL; + } + + int samples = lovrMicrophoneGetSampleCount(microphone); + if (samples == 0) { + return NULL; + } + + SoundData* soundData = lovrSoundDataCreate(samples, microphone->sampleRate, microphone->bitDepth, microphone->channelCount); + alcCaptureSamples(microphone->device, soundData->blob.data, samples); + return soundData; +} + +const char* lovrMicrophoneGetName(Microphone* microphone) { + return microphone->name; +} + +int lovrMicrophoneGetSampleCount(Microphone* microphone) { + if (!microphone->isRecording) { + return 0; + } + + ALCint samples; + alcGetIntegerv(microphone->device, ALC_CAPTURE_SAMPLES, sizeof(ALCint), &samples); + return (int) samples; +} + +int lovrMicrophoneGetSampleRate(Microphone* microphone) { + return microphone->sampleRate; +} + +bool lovrMicrophoneIsRecording(Microphone* microphone) { + return microphone->isRecording; +} + +void lovrMicrophoneStartRecording(Microphone* microphone) { + if (microphone->isRecording) { + return; + } + + alcCaptureStart(microphone->device); + microphone->isRecording = true; +} + +void lovrMicrophoneStopRecording(Microphone* microphone) { + if (!microphone->isRecording) { + return; + } + + microphone->isRecording = false; +} diff --git a/src/audio/microphone.h b/src/audio/microphone.h new file mode 100644 index 00000000..79484d99 --- /dev/null +++ b/src/audio/microphone.h @@ -0,0 +1,29 @@ +#include "util.h" +#include "data/soundData.h" +#include +#include +#include + +#pragma once + +typedef struct { + Ref ref; + ALCdevice* device; + bool isRecording; + const char* name; + int sampleRate; + int bitDepth; + int channelCount; +} Microphone; + +Microphone* lovrMicrophoneCreate(const char* name, int samples, int sampleRate, int bitDepth, int channelCount); +void lovrMicrophoneDestroy(void* ref); +int lovrMicrophoneGetBitDepth(Microphone* microphone); +int lovrMicrophoneGetChannelCount(Microphone* microphone); +SoundData* lovrMicrophoneGetData(Microphone* microphone); +const char* lovrMicrophoneGetName(Microphone* microphone); +int lovrMicrophoneGetSampleCount(Microphone* microphone); +int lovrMicrophoneGetSampleRate(Microphone* microphone); +bool lovrMicrophoneIsRecording(Microphone* microphone); +void lovrMicrophoneStartRecording(Microphone* microphone); +void lovrMicrophoneStopRecording(Microphone* microphone); diff --git a/src/audio/source.c b/src/audio/source.c index 45d975fc..98581e02 100644 --- a/src/audio/source.c +++ b/src/audio/source.c @@ -1,26 +1,10 @@ #include "audio/source.h" +#include "audio/audio.h" #include "data/audioStream.h" #define _USE_MATH_DEFINES #include #include -static ALenum lovrSourceGetFormat(Source* source) { - int channelCount = source->type == SOURCE_STATIC ? source->soundData->channelCount : source->stream->channelCount; - int bitDepth = source->type == SOURCE_STATIC ? source->soundData->bitDepth : source->stream->bitDepth; - - if (bitDepth == 8 && channelCount == 1) { - return AL_FORMAT_MONO8; - } else if (bitDepth == 8 && channelCount == 2) { - return AL_FORMAT_STEREO8; - } else if (bitDepth == 16 && channelCount == 1) { - return AL_FORMAT_MONO16; - } else if (bitDepth == 16 && channelCount == 2) { - return AL_FORMAT_STEREO16; - } - - return 0; -} - static ALenum lovrSourceGetState(Source* source) { ALenum state; alGetSourcei(source->id, AL_SOURCE_STATE, &state); @@ -31,11 +15,12 @@ Source* lovrSourceCreateStatic(SoundData* soundData) { Source* source = lovrAlloc(sizeof(Source), lovrSourceDestroy); if (!source) return NULL; + ALenum format = lovrAudioConvertFormat(soundData->bitDepth, soundData->channelCount); source->type = SOURCE_STATIC; source->soundData = soundData; alGenSources(1, &source->id); alGenBuffers(1, source->buffers); - alBufferData(source->buffers[0], lovrSourceGetFormat(source), soundData->blob.data, soundData->blob.size, soundData->sampleRate); + alBufferData(source->buffers[0], format, soundData->blob.data, soundData->blob.size, soundData->sampleRate); alSourcei(source->id, AL_BUFFER, source->buffers[0]); lovrRetain(soundData); @@ -299,7 +284,7 @@ void lovrSourceStream(Source* source, ALuint* buffers, int count) { } AudioStream* stream = source->stream; - ALenum format = lovrSourceGetFormat(source); + ALenum format = lovrAudioConvertFormat(stream->bitDepth, stream->channelCount); int frequency = stream->sampleRate; int samples = 0; int n = 0;