diff --git a/src/api.h b/src/api.h index 99f1d830..6bb2b28f 100644 --- a/src/api.h +++ b/src/api.h @@ -56,6 +56,7 @@ extern const luaL_Reg lovrRasterizer[]; extern const luaL_Reg lovrShader[]; extern const luaL_Reg lovrShape[]; extern const luaL_Reg lovrSliderJoint[]; +extern const luaL_Reg lovrSoundData[]; extern const luaL_Reg lovrSource[]; extern const luaL_Reg lovrSphereShape[]; extern const luaL_Reg lovrTexture[]; diff --git a/src/api/data.c b/src/api/data.c index 13cef7ee..3a3f565f 100644 --- a/src/api/data.c +++ b/src/api/data.c @@ -2,7 +2,9 @@ #include "data/audioStream.h" #include "data/modelData.h" #include "data/rasterizer.h" +#include "data/soundData.h" #include "data/textureData.h" +#include "data/vertexData.h" int l_lovrDataInit(lua_State* L) { lua_newtable(L); @@ -11,6 +13,7 @@ int l_lovrDataInit(lua_State* L) { luax_registertype(L, "AudioStream", lovrAudioStream); luax_registertype(L, "ModelData", lovrModelData); luax_registertype(L, "Rasterizer", lovrRasterizer); + luax_extendtype(L, "Blob", "SoundData", lovrBlob, lovrSoundData); luax_extendtype(L, "Blob", "TextureData", lovrBlob, lovrTextureData); luax_extendtype(L, "Blob", "VertexData", lovrBlob, lovrVertexData); return 1; @@ -41,7 +44,7 @@ int l_lovrDataNewBlob(lua_State* L) { } int l_lovrDataNewAudioStream(lua_State* L) { - Blob* blob = luax_readblob(L, 1, "Sound"); + Blob* blob = luax_readblob(L, 1, "AudioStream"); size_t bufferSize = luaL_optinteger(L, 2, 4096); AudioStream* stream = lovrAudioStreamCreate(blob, bufferSize); luax_pushtype(L, AudioStream, stream); @@ -77,6 +80,32 @@ int l_lovrDataNewRasterizer(lua_State* L) { return 1; } +int l_lovrDataNewSoundData(lua_State* L) { + if (lua_type(L, 1) == LUA_TNUMBER) { + int samples = luaL_checkinteger(L, 1); + int sampleRate = luaL_optinteger(L, 2, 44100); + int bitDepth = luaL_optinteger(L, 3, 16); + int channelCount = luaL_optinteger(L, 4, 2); + SoundData* soundData = lovrSoundDataCreate(samples, sampleRate, bitDepth, channelCount); + luax_pushtype(L, SoundData, soundData); + return 1; + } + + AudioStream** audioStream; + if ((audioStream = luax_totype(L, 1, AudioStream)) != NULL) { + SoundData* soundData = lovrSoundDataCreateFromAudioStream(*audioStream); + luax_pushtype(L, SoundData, soundData); + return 1; + } + + Blob* blob = luax_readblob(L, 1, "SoundData"); + SoundData* soundData = lovrSoundDataCreateFromBlob(blob); + luax_pushtype(L, SoundData, soundData); + lovrRelease(blob); + lovrRelease(soundData); + return 1; +} + int l_lovrDataNewTextureData(lua_State* L) { TextureData* textureData = NULL; if (lua_type(L, 1) == LUA_TNUMBER) { @@ -135,6 +164,7 @@ const luaL_Reg lovrData[] = { { "newAudioStream", l_lovrDataNewAudioStream }, { "newModelData", l_lovrDataNewModelData }, { "newRasterizer", l_lovrDataNewRasterizer }, + { "newSoundData", l_lovrDataNewSoundData }, { "newTextureData", l_lovrDataNewTextureData }, { "newVertexData", l_lovrDataNewVertexData }, { NULL, NULL } diff --git a/src/api/types/soundData.c b/src/api/types/soundData.c new file mode 100644 index 00000000..87914941 --- /dev/null +++ b/src/api/types/soundData.c @@ -0,0 +1,41 @@ +#include "api.h" +#include "data/soundData.h" + +int l_lovrSoundDataGetBitDepth(lua_State* L) { + SoundData* soundData = luax_checktype(L, 1, SoundData); + lua_pushinteger(L, soundData->bitDepth); + return 1; +} + +int l_lovrSoundDataGetChannelCount(lua_State* L) { + SoundData* soundData = luax_checktype(L, 1, SoundData); + lua_pushinteger(L, soundData->channelCount); + return 1; +} + +int l_lovrSoundDataGetDuration(lua_State* L) { + SoundData* soundData = luax_checktype(L, 1, SoundData); + lua_pushnumber(L, soundData->samples / (float) soundData->sampleRate); + return 1; +} + +int l_lovrSoundDataGetSampleCount(lua_State* L) { + SoundData* soundData = luax_checktype(L, 1, SoundData); + lua_pushinteger(L, soundData->samples); + return 1; +} + +int l_lovrSoundDataGetSampleRate(lua_State* L) { + SoundData* soundData = luax_checktype(L, 1, SoundData); + lua_pushinteger(L, soundData->sampleRate); + return 1; +} + +const luaL_Reg lovrSoundData[] = { + { "getBitDepth", l_lovrSoundDataGetBitDepth }, + { "getChannelCount", l_lovrSoundDataGetChannelCount }, + { "getDuration", l_lovrSoundDataGetDuration }, + { "getSampleCount", l_lovrSoundDataGetSampleCount }, + { "getSampleRate", l_lovrSoundDataGetSampleRate }, + { NULL, NULL } +}; diff --git a/src/audio/source.c b/src/audio/source.c index 39a677f2..3980d2d8 100644 --- a/src/audio/source.c +++ b/src/audio/source.c @@ -262,7 +262,7 @@ void lovrSourceStream(Source* source, ALuint* buffers, int count) { int n = 0; // Keep decoding until there is nothing left to decode or all the buffers are filled - while (n < count && (samples = lovrAudioStreamDecode(stream)) != 0) { + while (n < count && (samples = lovrAudioStreamDecode(stream, NULL, 0)) != 0) { alBufferData(buffers[n++], format, stream->buffer, samples * sizeof(ALshort), frequency); } diff --git a/src/data/audioStream.c b/src/data/audioStream.c index a1f29bd9..1ac16521 100644 --- a/src/data/audioStream.c +++ b/src/data/audioStream.c @@ -37,11 +37,11 @@ void lovrAudioStreamDestroy(void* ref) { free(stream); } -int lovrAudioStreamDecode(AudioStream* stream) { +int lovrAudioStreamDecode(AudioStream* stream, short* destination, size_t size) { stb_vorbis* decoder = (stb_vorbis*) stream->decoder; - short* buffer = (short*) stream->buffer; + short* buffer = destination ? destination : (short*) stream->buffer; + int capacity = destination ? size : (stream->bufferSize / sizeof(short)); int channelCount = stream->channelCount; - int capacity = stream->bufferSize / sizeof(short); int samples = 0; while (samples < capacity) { diff --git a/src/data/audioStream.h b/src/data/audioStream.h index 60360e83..083c741c 100644 --- a/src/data/audioStream.h +++ b/src/data/audioStream.h @@ -17,7 +17,7 @@ typedef struct { AudioStream* lovrAudioStreamCreate(Blob* blob, size_t bufferSize); void lovrAudioStreamDestroy(void* ref); -int lovrAudioStreamDecode(AudioStream* stream); +int lovrAudioStreamDecode(AudioStream* stream, short* destination, size_t size); void lovrAudioStreamRewind(AudioStream* stream); void lovrAudioStreamSeek(AudioStream* stream, int sample); int lovrAudioStreamTell(AudioStream* stream); diff --git a/src/data/soundData.c b/src/data/soundData.c new file mode 100644 index 00000000..4cb8432b --- /dev/null +++ b/src/data/soundData.c @@ -0,0 +1,52 @@ +#include "data/soundData.h" +#include "lib/stb/stb_vorbis.h" + +SoundData* lovrSoundDataCreate(int samples, int sampleRate, int bitDepth, int channelCount) { + SoundData* soundData = lovrAlloc(sizeof(SoundData), lovrSoundDataDestroy); + if (!soundData) return NULL; + + soundData->samples = samples; + soundData->sampleRate = sampleRate; + soundData->bitDepth = bitDepth; + soundData->channelCount = channelCount; + soundData->blob.size = samples * channelCount * (bitDepth / 8); + soundData->blob.data = calloc(1, soundData->blob.size); + + return soundData; +} + +SoundData* lovrSoundDataCreateFromAudioStream(AudioStream* audioStream) { + SoundData* soundData = lovrAlloc(sizeof(SoundData), lovrSoundDataDestroy); + if (!soundData) return NULL; + + soundData->samples = audioStream->samples; + soundData->sampleRate = audioStream->sampleRate; + soundData->bitDepth = audioStream->bitDepth; + soundData->channelCount = audioStream->channelCount; + soundData->blob.size = audioStream->samples * audioStream->channelCount * (audioStream->bitDepth / 8); + soundData->blob.data = calloc(1, soundData->blob.size); + + int samples; + short* buffer = soundData->blob.data; + size_t offset = 0; + lovrAudioStreamRewind(audioStream); + while ((samples = lovrAudioStreamDecode(audioStream, buffer + offset, soundData->blob.size - (offset * sizeof(short)))) != 0) { + offset += samples; + } + + return soundData; +} + +SoundData* lovrSoundDataCreateFromBlob(Blob* blob) { + SoundData* soundData = lovrAlloc(sizeof(SoundData), lovrSoundDataDestroy); + if (!soundData) return NULL; + + soundData->samples = stb_vorbis_decode_memory(blob->data, blob->size, &soundData->channelCount, &soundData->sampleRate, (short**) &soundData->blob.data); + soundData->bitDepth = 16; + + return soundData; +} + +void lovrSoundDataDestroy(void* ref) { + lovrBlobDestroy(ref); +} diff --git a/src/data/soundData.h b/src/data/soundData.h new file mode 100644 index 00000000..1de1912d --- /dev/null +++ b/src/data/soundData.h @@ -0,0 +1,17 @@ +#include "data/blob.h" +#include "data/audioStream.h" + +#pragma once + +typedef struct { + Blob blob; + int channelCount; + int sampleRate; + int samples; + int bitDepth; +} SoundData; + +SoundData* lovrSoundDataCreate(int samples, int sampleRate, int bitDepth, int channels); +SoundData* lovrSoundDataCreateFromAudioStream(AudioStream* audioStream); +SoundData* lovrSoundDataCreateFromBlob(Blob* blob); +void lovrSoundDataDestroy(void* ref);