Add Microphone objects for audio capture;

This commit is contained in:
bjorn 2018-07-06 17:55:19 -07:00
parent 889144cc45
commit b650f2b770
9 changed files with 260 additions and 19 deletions

View File

@ -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

View File

@ -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[];

View File

@ -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 },

View File

@ -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 }
};

View File

@ -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);
}

View File

@ -1,4 +1,5 @@
#include "audio/source.h"
#include "audio/microphone.h"
#include "lib/vec/vec.h"
#include <AL/al.h>
#include <AL/alc.h>
@ -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);

90
src/audio/microphone.c Normal file
View File

@ -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;
}

29
src/audio/microphone.h Normal file
View File

@ -0,0 +1,29 @@
#include "util.h"
#include "data/soundData.h"
#include <AL/al.h>
#include <AL/alc.h>
#include <stdbool.h>
#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);

View File

@ -1,26 +1,10 @@
#include "audio/source.h"
#include "audio/audio.h"
#include "data/audioStream.h"
#define _USE_MATH_DEFINES
#include <math.h>
#include <stdlib.h>
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;