SoundData is now named Sound!;

This commit is contained in:
bjorn 2021-02-08 19:52:56 -07:00
parent 8c714c45b0
commit dca79f83f0
12 changed files with 492 additions and 493 deletions

View File

@ -353,13 +353,13 @@ if(LOVR_ENABLE_DATA)
src/modules/data/modelData_gltf.c
src/modules/data/modelData_obj.c
src/modules/data/rasterizer.c
src/modules/data/soundData.c
src/modules/data/sound.c
src/modules/data/textureData.c
src/api/l_data.c
src/api/l_data_blob.c
src/api/l_data_modelData.c
src/api/l_data_rasterizer.c
src/api/l_data_soundData.c
src/api/l_data_sound.c
src/api/l_data_textureData.c
src/lib/minimp3/minimp3.c
src/lib/stb/stb_image.c

View File

@ -53,7 +53,7 @@ extern const luaL_Reg lovrRasterizer[];
extern const luaL_Reg lovrShader[];
extern const luaL_Reg lovrShaderBlock[];
extern const luaL_Reg lovrSliderJoint[];
extern const luaL_Reg lovrSoundData[];
extern const luaL_Reg lovrSound[];
extern const luaL_Reg lovrSource[];
extern const luaL_Reg lovrSphereShape[];
extern const luaL_Reg lovrMeshShape[];

View File

@ -1,7 +1,7 @@
#include "api.h"
#include "audio/audio.h"
#include "data/blob.h"
#include "data/soundData.h"
#include "data/sound.h"
#include "core/maf.h"
#include "core/util.h"
#include <stdlib.h>
@ -111,20 +111,20 @@ static int l_lovrAudioGetSpatializer(lua_State *L) {
}
static int l_lovrAudioGetCaptureStream(lua_State* L) {
SoundData* soundData = lovrAudioGetCaptureStream();
luax_pushtype(L, SoundData, soundData);
Sound* sound = lovrAudioGetCaptureStream();
luax_pushtype(L, Sound, sound);
return 1;
}
static int l_lovrAudioNewSource(lua_State* L) {
SoundData* soundData = luax_totype(L, 1, SoundData);
Sound* sound = luax_totype(L, 1, Sound);
if (!soundData) {
if (!sound) {
Blob* blob = luax_readblob(L, 1, "Source");
soundData = lovrSoundDataCreateFromFile(blob, false);
sound = lovrSoundCreateFromFile(blob, false);
lovrRelease(blob, lovrBlobDestroy);
} else {
lovrRetain(soundData);
lovrRetain(sound);
}
bool spatial = true;
@ -134,9 +134,9 @@ static int l_lovrAudioNewSource(lua_State* L) {
lua_pop(L, 1);
}
Source* source = lovrSourceCreate(soundData, spatial);
Source* source = lovrSourceCreate(sound, spatial);
luax_pushtype(L, Source, source);
lovrRelease(soundData, lovrSoundDataDestroy);
lovrRelease(sound, lovrSoundDestroy);
lovrRelease(source, lovrSourceDestroy);
return 1;
}

View File

@ -1,6 +1,5 @@
#include "api.h"
#include "audio/audio.h"
#include "data/soundData.h"
#include "core/maf.h"
#include "core/util.h"

View File

@ -2,7 +2,7 @@
#include "data/blob.h"
#include "data/modelData.h"
#include "data/rasterizer.h"
#include "data/soundData.h"
#include "data/sound.h"
#include "data/textureData.h"
#include <stdlib.h>
#include <string.h>
@ -64,7 +64,7 @@ static int l_lovrDataNewRasterizer(lua_State* L) {
return 1;
}
static int l_lovrDataNewSoundData(lua_State* L) {
static int l_lovrDataNewSound(lua_State* L) {
if (lua_type(L, 1) == LUA_TNUMBER) {
uint64_t frames = luaL_checkinteger(L, 1);
SampleFormat format = luax_checkenum(L, 2, SampleFormat, "f32");
@ -73,20 +73,20 @@ static int l_lovrDataNewSoundData(lua_State* L) {
Blob* blob = luax_totype(L, 5, Blob);
const char* other = lua_tostring(L, 5);
bool stream = other && !strcmp(other, "stream");
SoundData* soundData = stream ?
lovrSoundDataCreateStream(frames, format, channels, sampleRate) :
lovrSoundDataCreateRaw(frames, format, channels, sampleRate, blob);
luax_pushtype(L, SoundData, soundData);
lovrRelease(soundData, lovrSoundDataDestroy);
Sound* sound = stream ?
lovrSoundCreateStream(frames, format, channels, sampleRate) :
lovrSoundCreateRaw(frames, format, channels, sampleRate, blob);
luax_pushtype(L, Sound, sound);
lovrRelease(sound, lovrSoundDestroy);
return 1;
}
Blob* blob = luax_readblob(L, 1, "SoundData");
Blob* blob = luax_readblob(L, 1, "Sound");
bool decode = lua_toboolean(L, 2);
SoundData* soundData = lovrSoundDataCreateFromFile(blob, decode);
luax_pushtype(L, SoundData, soundData);
Sound* sound = lovrSoundCreateFromFile(blob, decode);
luax_pushtype(L, Sound, sound);
lovrRelease(blob, lovrBlobDestroy);
lovrRelease(soundData, lovrSoundDataDestroy);
lovrRelease(sound, lovrSoundDestroy);
return 1;
}
@ -119,7 +119,7 @@ static const luaL_Reg lovrData[] = {
{ "newBlob", l_lovrDataNewBlob },
{ "newModelData", l_lovrDataNewModelData },
{ "newRasterizer", l_lovrDataNewRasterizer },
{ "newSoundData", l_lovrDataNewSoundData },
{ "newSound", l_lovrDataNewSound },
{ "newTextureData", l_lovrDataNewTextureData },
{ NULL, NULL }
};
@ -130,7 +130,7 @@ int luaopen_lovr_data(lua_State* L) {
luax_registertype(L, Blob);
luax_registertype(L, ModelData);
luax_registertype(L, Rasterizer);
luax_registertype(L, SoundData);
luax_registertype(L, Sound);
luax_registertype(L, TextureData);
return 1;
}

View File

@ -1,5 +1,5 @@
#include "api.h"
#include "data/soundData.h"
#include "data/sound.h"
#include "data/blob.h"
#include "core/util.h"
@ -9,74 +9,74 @@ StringEntry lovrSampleFormat[] = {
{ 0 }
};
static int l_lovrSoundDataGetBlob(lua_State* L) {
SoundData* soundData = luax_checktype(L, 1, SoundData);
Blob* blob = lovrSoundDataGetBlob(soundData);
static int l_lovrSoundGetBlob(lua_State* L) {
Sound* sound = luax_checktype(L, 1, Sound);
Blob* blob = lovrSoundGetBlob(sound);
luax_pushtype(L, Blob, blob);
return 1;
}
static int l_lovrSoundDataGetFormat(lua_State* L) {
SoundData* soundData = luax_checktype(L, 1, SoundData);
luax_pushenum(L, SampleFormat, lovrSoundDataGetFormat(soundData));
static int l_lovrSoundGetFormat(lua_State* L) {
Sound* sound = luax_checktype(L, 1, Sound);
luax_pushenum(L, SampleFormat, lovrSoundGetFormat(sound));
return 1;
}
static int l_lovrSoundDataGetChannelCount(lua_State* L) {
SoundData* soundData = luax_checktype(L, 1, SoundData);
lua_pushinteger(L, lovrSoundDataGetChannelCount(soundData));
static int l_lovrSoundGetChannelCount(lua_State* L) {
Sound* sound = luax_checktype(L, 1, Sound);
lua_pushinteger(L, lovrSoundGetChannelCount(sound));
return 1;
}
static int l_lovrSoundDataGetSampleRate(lua_State* L) {
SoundData* soundData = luax_checktype(L, 1, SoundData);
lua_pushinteger(L, lovrSoundDataGetSampleRate(soundData));
static int l_lovrSoundGetSampleRate(lua_State* L) {
Sound* sound = luax_checktype(L, 1, Sound);
lua_pushinteger(L, lovrSoundGetSampleRate(sound));
return 1;
}
static int l_lovrSoundDataGetFrameCount(lua_State* L) {
SoundData* soundData = luax_checktype(L, 1, SoundData);
uint32_t frames = lovrSoundDataGetFrameCount(soundData);
static int l_lovrSoundGetFrameCount(lua_State* L) {
Sound* sound = luax_checktype(L, 1, Sound);
uint32_t frames = lovrSoundGetFrameCount(sound);
lua_pushinteger(L, frames);
return 1;
}
static int l_lovrSoundDataGetSampleCount(lua_State* L) {
SoundData* soundData = luax_checktype(L, 1, SoundData);
uint32_t frames = lovrSoundDataGetFrameCount(soundData);
uint32_t channels = lovrSoundDataGetChannelCount(soundData);
static int l_lovrSoundGetSampleCount(lua_State* L) {
Sound* sound = luax_checktype(L, 1, Sound);
uint32_t frames = lovrSoundGetFrameCount(sound);
uint32_t channels = lovrSoundGetChannelCount(sound);
lua_pushinteger(L, frames * channels);
return 1;
}
static int l_lovrSoundDataGetDuration(lua_State* L) {
SoundData* soundData = luax_checktype(L, 1, SoundData);
uint32_t frames = lovrSoundDataGetFrameCount(soundData);
uint32_t rate = lovrSoundDataGetSampleRate(soundData);
static int l_lovrSoundGetDuration(lua_State* L) {
Sound* sound = luax_checktype(L, 1, Sound);
uint32_t frames = lovrSoundGetFrameCount(sound);
uint32_t rate = lovrSoundGetSampleRate(sound);
lua_pushnumber(L, (double) frames / rate);
return 1;
}
static int l_lovrSoundDataIsCompressed(lua_State* L) {
SoundData* soundData = luax_checktype(L, 1, SoundData);
bool compressed = lovrSoundDataIsCompressed(soundData);
static int l_lovrSoundIsCompressed(lua_State* L) {
Sound* sound = luax_checktype(L, 1, Sound);
bool compressed = lovrSoundIsCompressed(sound);
lua_pushboolean(L, compressed);
return 1;
}
static int l_lovrSoundDataIsStream(lua_State* L) {
SoundData* soundData = luax_checktype(L, 1, SoundData);
bool stream = lovrSoundDataIsStream(soundData);
static int l_lovrSoundIsStream(lua_State* L) {
Sound* sound = luax_checktype(L, 1, Sound);
bool stream = lovrSoundIsStream(sound);
lua_pushboolean(L, stream);
return 1;
}
static int l_lovrSoundDataGetFrames(lua_State* L) {
SoundData* soundData = luax_checktype(L, 1, SoundData);
size_t stride = lovrSoundDataGetStride(soundData);
SampleFormat format = lovrSoundDataGetFormat(soundData);
uint32_t channels = lovrSoundDataGetChannelCount(soundData);
uint32_t frameCount = lovrSoundDataGetFrameCount(soundData);
static int l_lovrSoundGetFrames(lua_State* L) {
Sound* sound = luax_checktype(L, 1, Sound);
size_t stride = lovrSoundGetStride(sound);
SampleFormat format = lovrSoundGetFormat(sound);
uint32_t channels = lovrSoundGetChannelCount(sound);
uint32_t frameCount = lovrSoundGetFrameCount(sound);
uint32_t count = frameCount;
uint32_t offset = 0;
uint32_t dstOffset = 0;
@ -91,13 +91,13 @@ static int l_lovrSoundDataGetFrames(lua_State* L) {
}
}
lovrAssert(offset + count <= frameCount, "Tried to read samples past the end of the SoundData");
lovrAssert(offset + count <= frameCount, "Tried to read samples past the end of the Sound");
switch (lua_type(L, index)) {
case LUA_TNIL:
case LUA_TNONE:
lua_settop(L, index - 1);
lua_createtable(L, count * lovrSoundDataGetChannelCount(soundData), 0);
lua_createtable(L, count * lovrSoundGetChannelCount(sound), 0);
// fallthrough;
case LUA_TTABLE:
dstOffset = luaL_optinteger(L, index + 1, 1);
@ -106,7 +106,7 @@ static int l_lovrSoundDataGetFrames(lua_State* L) {
while (frames < count) {
char buffer[4096];
uint32_t chunk = MIN(sizeof(buffer) / stride, count - frames);
uint32_t read = lovrSoundDataRead(soundData, offset + frames, chunk, buffer);
uint32_t read = lovrSoundRead(sound, offset + frames, chunk, buffer);
uint32_t samples = read * channels;
if (read == 0) break;
@ -131,36 +131,36 @@ static int l_lovrSoundDataGetFrames(lua_State* L) {
case LUA_TUSERDATA:
dstOffset = luaL_optinteger(L, index + 1, 0);
lua_settop(L, index);
SoundData* other = luax_totype(L, index, SoundData);
Sound* other = luax_totype(L, index, Sound);
Blob* blob = luax_totype(L, index, Blob);
if (blob) {
lovrAssert(dstOffset + count * stride <= blob->size, "Tried to write samples past the end of the Blob");
char* data = (char*) blob->data + dstOffset;
uint32_t frames = 0;
while (frames < count) {
uint32_t read = lovrSoundDataRead(soundData, offset + frames, count - frames, data);
uint32_t read = lovrSoundRead(sound, offset + frames, count - frames, data);
data += read * stride;
if (read == 0) break;
}
lua_pushinteger(L, frames);
return 2;
} else if (other) {
uint32_t frames = lovrSoundDataCopy(soundData, other, count, offset, dstOffset);
uint32_t frames = lovrSoundCopy(sound, other, count, offset, dstOffset);
lua_pushinteger(L, frames);
return 2;
}
// fallthrough;
default:
return luax_typeerror(L, index, "nil, table, Blob, or SoundData");
return luax_typeerror(L, index, "nil, table, Blob, or Sound");
}
}
static int l_lovrSoundDataSetFrames(lua_State* L) {
SoundData* soundData = luax_checktype(L, 1, SoundData);
size_t stride = lovrSoundDataGetStride(soundData);
SampleFormat format = lovrSoundDataGetFormat(soundData);
uint32_t frameCount = lovrSoundDataGetFrameCount(soundData);
uint32_t channels = lovrSoundDataGetChannelCount(soundData);
static int l_lovrSoundSetFrames(lua_State* L) {
Sound* sound = luax_checktype(L, 1, Sound);
size_t stride = lovrSoundGetStride(sound);
SampleFormat format = lovrSoundGetFormat(sound);
uint32_t frameCount = lovrSoundGetFrameCount(sound);
uint32_t channels = lovrSoundGetChannelCount(sound);
if (lua_isuserdata(L, 2)) {
Blob* blob = luax_totype(L, 2, Blob);
@ -169,25 +169,25 @@ static int l_lovrSoundDataSetFrames(lua_State* L) {
uint32_t srcOffset = luaL_optinteger(L, 5, 0);
uint32_t dstOffset = luaL_optinteger(L, 4, 0);
uint32_t count = luaL_optinteger(L, 3, (blob->size - srcOffset) / stride);
uint32_t frames = lovrSoundDataWrite(soundData, dstOffset, count, (char*) blob->data + srcOffset);
uint32_t frames = lovrSoundWrite(sound, dstOffset, count, (char*) blob->data + srcOffset);
lua_pushinteger(L, frames);
return 1;
}
SoundData* other = luax_totype(L, 2, SoundData);
Sound* other = luax_totype(L, 2, Sound);
if (other) {
uint32_t srcOffset = luaL_optinteger(L, 5, 0);
uint32_t dstOffset = luaL_optinteger(L, 4, 0);
uint32_t count = luaL_optinteger(L, 3, lovrSoundDataGetFrameCount(other) - srcOffset);
uint32_t frames = lovrSoundDataCopy(other, soundData, count, srcOffset, dstOffset);
uint32_t count = luaL_optinteger(L, 3, lovrSoundGetFrameCount(other) - srcOffset);
uint32_t frames = lovrSoundCopy(other, sound, count, srcOffset, dstOffset);
lua_pushinteger(L, frames);
return 1;
}
}
if (!lua_istable(L, 2)) {
return luax_typeerror(L, 2, "table, Blob, or SoundData");
return luax_typeerror(L, 2, "table, Blob, or Sound");
}
int length = luax_len(L, 2);
@ -219,7 +219,7 @@ static int l_lovrSoundDataSetFrames(lua_State* L) {
}
}
uint32_t written = lovrSoundDataWrite(soundData, srcOffset + frames, chunk, buffer);
uint32_t written = lovrSoundWrite(sound, srcOffset + frames, chunk, buffer);
if (written == 0) break;
frames += written;
}
@ -227,17 +227,17 @@ static int l_lovrSoundDataSetFrames(lua_State* L) {
return 1;
}
const luaL_Reg lovrSoundData[] = {
{ "getBlob", l_lovrSoundDataGetBlob },
{ "getFormat", l_lovrSoundDataGetFormat },
{ "getChannelCount", l_lovrSoundDataGetChannelCount },
{ "getSampleRate", l_lovrSoundDataGetSampleRate },
{ "getFrameCount", l_lovrSoundDataGetFrameCount },
{ "getSampleCount", l_lovrSoundDataGetSampleCount },
{ "getDuration", l_lovrSoundDataGetDuration },
{ "isCompressed", l_lovrSoundDataIsCompressed },
{ "isStream", l_lovrSoundDataIsStream },
{ "getFrames", l_lovrSoundDataGetFrames },
{ "setFrames", l_lovrSoundDataSetFrames },
const luaL_Reg lovrSound[] = {
{ "getBlob", l_lovrSoundGetBlob },
{ "getFormat", l_lovrSoundGetFormat },
{ "getChannelCount", l_lovrSoundGetChannelCount },
{ "getSampleRate", l_lovrSoundGetSampleRate },
{ "getFrameCount", l_lovrSoundGetFrameCount },
{ "getSampleCount", l_lovrSoundGetSampleCount },
{ "getDuration", l_lovrSoundGetDuration },
{ "isCompressed", l_lovrSoundIsCompressed },
{ "isStream", l_lovrSoundIsStream },
{ "getFrames", l_lovrSoundGetFrames },
{ "setFrames", l_lovrSoundSetFrames },
{ NULL, NULL }
};

View File

@ -1,6 +1,6 @@
#include "audio/audio.h"
#include "audio/spatializer.h"
#include "data/soundData.h"
#include "data/sound.h"
#include "core/os.h"
#include "core/util.h"
#include "lib/miniaudio/miniaudio.h"
@ -21,7 +21,7 @@ static const ma_format miniaudioFormats[] = {
struct Source {
ref_t ref;
Source* next;
SoundData* sound;
Sound* sound;
ma_data_converter* converter;
intptr_t spatializerMemo;
uint32_t offset;
@ -40,7 +40,7 @@ static struct {
ma_device devices[2];
ma_mutex lock;
Source* sources;
SoundData* captureStream;
Sound* captureStream;
arr_t(ma_data_converter*) converters;
float position[4];
float orientation[4];
@ -92,13 +92,13 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co
// Read and convert raw frames until there's BUFFER_SIZE converted frames
uint32_t channels = source->spatial ? 1 : 2;
uint64_t frameLimit = sizeof(raw) / lovrSoundDataGetChannelCount(source->sound) / sizeof(float);
uint64_t frameLimit = sizeof(raw) / lovrSoundGetChannelCount(source->sound) / sizeof(float);
uint32_t framesToConvert = BUFFER_SIZE;
uint32_t framesConverted = 0;
while (framesToConvert > 0) {
src = raw;
uint64_t framesToRead = source->converter ? MIN(ma_data_converter_get_required_input_frame_count(source->converter, framesToConvert), frameLimit) : framesToConvert;
uint64_t framesRead = lovrSoundDataRead(source->sound, source->offset, framesToRead, src);
uint64_t framesRead = lovrSoundRead(source->sound, source->offset, framesToRead, src);
ma_uint64 framesIn = framesRead;
ma_uint64 framesOut = framesToConvert;
@ -160,7 +160,7 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co
}
static void onCapture(ma_device* device, void* output, const void* input, uint32_t count) {
lovrSoundDataWrite(state.captureStream, 0, count, input);
lovrSoundWrite(state.captureStream, 0, count, input);
}
static const ma_device_callback_proc callbacks[] = { onPlayback, onCapture };
@ -213,7 +213,7 @@ void lovrAudioDestroy() {
}
ma_mutex_uninit(&state.lock);
ma_context_uninit(&state.context);
lovrRelease(state.captureStream, lovrSoundDataDestroy);
lovrRelease(state.captureStream, lovrSoundDestroy);
if (state.spatializer) state.spatializer->destroy();
for (size_t i = 0; i < state.converters.length; i++) {
ma_data_converter_uninit(state.converters.data[i]);
@ -268,8 +268,8 @@ bool lovrAudioSetDevice(AudioType type, void* id, size_t size, uint32_t sampleRa
config.capture.format = miniaudioFormats[format];
config.capture.channels = CAPTURE_CHANNELS;
config.capture.shareMode = exclusive ? ma_share_mode_exclusive : ma_share_mode_shared;
lovrRelease(state.captureStream, lovrSoundDataDestroy);
state.captureStream = lovrSoundDataCreateStream(sampleRate * 1., format, CAPTURE_CHANNELS, sampleRate);
lovrRelease(state.captureStream, lovrSoundDestroy);
state.captureStream = lovrSoundCreateStream(sampleRate * 1., format, CAPTURE_CHANNELS, sampleRate);
}
config.sampleRate = sampleRate;
@ -316,13 +316,13 @@ const char* lovrAudioGetSpatializer() {
return state.spatializer->name;
}
struct SoundData* lovrAudioGetCaptureStream() {
Sound* lovrAudioGetCaptureStream() {
return state.captureStream;
}
// Source
Source* lovrSourceCreate(SoundData* sound, bool spatial) {
Source* lovrSourceCreate(Sound* sound, bool spatial) {
Source* source = calloc(1, sizeof(Source));
lovrAssert(source, "Out of memory");
source->ref = 1;
@ -333,11 +333,11 @@ Source* lovrSourceCreate(SoundData* sound, bool spatial) {
source->spatial = spatial;
ma_data_converter_config config = ma_data_converter_config_init_default();
config.formatIn = miniaudioFormats[lovrSoundDataGetFormat(sound)];
config.formatIn = miniaudioFormats[lovrSoundGetFormat(sound)];
config.formatOut = miniaudioFormats[OUTPUT_FORMAT];
config.channelsIn = lovrSoundDataGetChannelCount(sound);
config.channelsIn = lovrSoundGetChannelCount(sound);
config.channelsOut = spatial ? 1 : 2;
config.sampleRateIn = lovrSoundDataGetSampleRate(sound);
config.sampleRateIn = lovrSoundGetSampleRate(sound);
config.sampleRateOut = PLAYBACK_SAMPLE_RATE;
if (config.formatIn != config.formatOut || config.channelsIn == config.channelsOut || config.sampleRateIn != config.sampleRateOut) {
@ -368,7 +368,7 @@ Source* lovrSourceCreate(SoundData* sound, bool spatial) {
void lovrSourceDestroy(void* ref) {
Source* source = ref;
state.spatializer->sourceDestroy(source);
lovrRelease(source->sound, lovrSoundDataDestroy);
lovrRelease(source->sound, lovrSoundDestroy);
free(source);
}
@ -406,7 +406,7 @@ bool lovrSourceIsLooping(Source* source) {
}
void lovrSourceSetLooping(Source* source, bool loop) {
lovrAssert(loop == false || lovrSoundDataIsStream(source->sound) == false, "Can't loop streams");
lovrAssert(loop == false || lovrSoundIsStream(source->sound) == false, "Can't loop streams");
source->looping = loop;
}
@ -437,17 +437,17 @@ void lovrSourceSetPose(Source *source, float position[4], float orientation[4])
}
double lovrSourceGetDuration(Source* source, TimeUnit units) {
uint32_t frames = lovrSoundDataGetFrameCount(source->sound);
return units == UNIT_SECONDS ? (double) frames / lovrSoundDataGetSampleRate(source->sound) : frames;
uint32_t frames = lovrSoundGetFrameCount(source->sound);
return units == UNIT_SECONDS ? (double) frames / lovrSoundGetSampleRate(source->sound) : frames;
}
double lovrSourceGetTime(Source* source, TimeUnit units) {
return units == UNIT_SECONDS ? (double) source->offset / lovrSoundDataGetSampleRate(source->sound) : source->offset;
return units == UNIT_SECONDS ? (double) source->offset / lovrSoundGetSampleRate(source->sound) : source->offset;
}
void lovrSourceSetTime(Source* source, double time, TimeUnit units) {
ma_mutex_lock(&state.lock);
source->offset = units == UNIT_SECONDS ? (uint32_t) (time * lovrSoundDataGetSampleRate(source->sound) + .5) : (uint32_t) time;
source->offset = units == UNIT_SECONDS ? (uint32_t) (time * lovrSoundGetSampleRate(source->sound) + .5) : (uint32_t) time;
ma_mutex_unlock(&state.lock);
}

View File

@ -6,7 +6,7 @@
#define PLAYBACK_SAMPLE_RATE 48000
struct SoundData;
struct Sound;
typedef struct Source Source;
@ -34,11 +34,11 @@ void lovrAudioSetVolume(float volume);
void lovrAudioGetPose(float position[4], float orientation[4]);
void lovrAudioSetPose(float position[4], float orientation[4]);
const char* lovrAudioGetSpatializer(void);
struct SoundData* lovrAudioGetCaptureStream(void);
struct Sound* lovrAudioGetCaptureStream(void);
// Source
Source* lovrSourceCreate(struct SoundData* soundData, bool spatial);
Source* lovrSourceCreate(struct Sound* sound, bool spatial);
void lovrSourceDestroy(void* ref);
bool lovrSourcePlay(Source* source);
void lovrSourcePause(Source* source);

348
src/modules/data/sound.c Normal file
View File

@ -0,0 +1,348 @@
#include "data/sound.h"
#include "data/blob.h"
#include "core/util.h"
#include "lib/stb/stb_vorbis.h"
#include "lib/miniaudio/miniaudio.h"
#define MINIMP3_FLOAT_OUTPUT
#define MINIMP3_NO_STDIO
#include "lib/minimp3/minimp3_ex.h"
#include <stdlib.h>
#include <string.h>
static const ma_format miniaudioFormats[] = {
[SAMPLE_I16] = ma_format_s16,
[SAMPLE_F32] = ma_format_f32
};
struct Sound {
ref_t ref;
uint32_t (*read)(Sound* sound, uint32_t offset, uint32_t count, void* data);
struct Blob* blob;
void* decoder;
void* stream;
SampleFormat format;
uint32_t sampleRate;
uint32_t channels;
uint32_t frames;
uint32_t cursor;
};
// Readers
static uint32_t lovrSoundReadRaw(Sound* sound, uint32_t offset, uint32_t count, void* data) {
uint8_t* p = sound->blob->data;
uint32_t n = MIN(count, sound->frames - offset);
size_t stride = lovrSoundGetStride(sound);
memcpy(data, p + offset * stride, n * stride);
return n;
}
static uint32_t lovrSoundReadStream(Sound* sound, uint32_t offset, uint32_t count, void* data) {
void* p = NULL;
uint32_t frames = count;
ma_pcm_rb_acquire_read(sound->stream, &frames, &p);
memcpy(data, p, frames * lovrSoundGetStride(sound));
ma_pcm_rb_commit_read(sound->stream, frames, p);
return frames;
}
static uint32_t lovrSoundReadOgg(Sound* sound, uint32_t offset, uint32_t count, void* data) {
if (sound->cursor != offset) {
stb_vorbis_seek(sound->decoder, (int) offset);
sound->cursor = offset;
}
uint32_t channels = sound->channels;
uint32_t n = stb_vorbis_get_samples_float_interleaved(sound->decoder, channels, data, count * channels);
sound->cursor += n;
return n;
}
static uint32_t lovrSoundReadMp3(Sound* sound, uint32_t offset, uint32_t count, void* data) {
if (sound->cursor != offset) {
mp3dec_ex_seek(sound->decoder, offset);
sound->cursor = offset;
}
size_t samples = mp3dec_ex_read(sound->decoder, data, count * sound->channels);
uint32_t frames = samples / sound->channels;
sound->cursor += frames;
return frames;
}
// Sound
Sound* lovrSoundCreateRaw(uint32_t frames, SampleFormat format, uint32_t channels, uint32_t sampleRate, struct Blob* blob) {
Sound* sound = calloc(1, sizeof(Sound));
lovrAssert(sound, "Out of memory");
sound->ref = 1;
sound->frames = frames;
sound->format = format;
sound->channels = channels;
sound->sampleRate = sampleRate;
sound->read = lovrSoundReadRaw;
size_t size = frames * lovrSoundGetStride(sound);
void* data = calloc(1, size);
lovrAssert(data, "Out of memory");
sound->blob = lovrBlobCreate(data, size, "Sound");
if (blob) {
memcpy(sound->blob->data, blob->data, MIN(size, blob->size));
}
return sound;
}
Sound* lovrSoundCreateStream(uint32_t frames, SampleFormat format, uint32_t channels, uint32_t sampleRate) {
Sound* sound = calloc(1, sizeof(Sound));
lovrAssert(sound, "Out of memory");
sound->ref = 1;
sound->frames = frames;
sound->format = format;
sound->channels = channels;
sound->sampleRate = sampleRate;
sound->read = lovrSoundReadStream;
sound->stream = malloc(sizeof(ma_pcm_rb));
lovrAssert(sound->stream, "Out of memory");
size_t size = frames * lovrSoundGetStride(sound);
void* data = malloc(size);
lovrAssert(data, "Out of memory");
sound->blob = lovrBlobCreate(data, size, NULL);
ma_result status = ma_pcm_rb_init(miniaudioFormats[format], channels, frames, data, NULL, sound->stream);
lovrAssert(status == MA_SUCCESS, "Failed to create ring buffer for streamed Sound: %s (%d)", ma_result_description(status), status);
return sound;
}
Sound* lovrSoundCreateFromFile(struct Blob* blob, bool decode) {
Sound* sound = calloc(1, sizeof(Sound));
lovrAssert(sound, "Out of memory");
sound->ref = 1;
if (blob->size >= 4 && !memcmp(blob->data, "OggS", 4)) {
sound->decoder = stb_vorbis_open_memory(blob->data, (int) blob->size, NULL, NULL);
lovrAssert(sound->decoder, "Could not load sound from '%s'", blob->name);
stb_vorbis_info info = stb_vorbis_get_info(sound->decoder);
sound->format = SAMPLE_F32;
sound->channels = info.channels;
sound->sampleRate = info.sample_rate;
sound->frames = stb_vorbis_stream_length_in_samples(sound->decoder);
if (decode) {
sound->read = lovrSoundReadRaw;
size_t size = sound->frames * lovrSoundGetStride(sound);
void* data = calloc(1, size);
lovrAssert(data, "Out of memory");
sound->blob = lovrBlobCreate(data, size, "Sound");
if (stb_vorbis_get_samples_float_interleaved(sound->decoder, info.channels, data, size / 4) < (int) sound->frames) {
lovrThrow("Could not decode vorbis from '%s'", blob->name);
}
stb_vorbis_close(sound->decoder);
sound->decoder = NULL;
} else {
sound->read = lovrSoundReadOgg;
sound->blob = blob;
lovrRetain(blob);
}
return sound;
} else if (blob->size >= 64 && !memcmp(blob->data, "RIFF", 4)) {
typedef struct {
uint32_t id;
uint32_t size;
uint32_t fileFormat;
uint32_t fmtId;
uint32_t fmtSize;
uint16_t format;
uint16_t channels;
uint32_t sampleRate;
uint32_t byteRate;
uint16_t frameSize;
uint16_t sampleSize;
uint16_t extSize;
uint16_t validBitsPerSample;
uint32_t channelMask;
char guid[16];
} wavHeader;
char guidi16[16] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 };
char guidf32[16] = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 };
wavHeader* wav = blob->data;
lovrAssert(wav->size == blob->size - 8, "Invalid WAV");
lovrAssert(!memcmp(&wav->fileFormat, "WAVE", 4), "Invalid WAV");
lovrAssert(!memcmp(&wav->fmtId, "fmt ", 4), "Invalid WAV");
if (wav->fmtSize == 16 && wav->format == 1 && wav->sampleSize == 16) {
sound->format = SAMPLE_I16;
} else if (wav->fmtSize == 16 && wav->format == 3 && wav->sampleSize == 32) {
sound->format = SAMPLE_F32;
} else if (wav->fmtSize == 40 && wav->format == 65534 && wav->extSize == 22 && wav->validBitsPerSample == 16 && !memcmp(wav->guid, guidi16, 16)) {
sound->format = SAMPLE_I16;
} else if (wav->fmtSize == 40 && wav->format == 65534 && wav->extSize == 22 && wav->validBitsPerSample == 32 && !memcmp(wav->guid, guidf32, 16)) {
sound->format = SAMPLE_F32;
} else {
lovrThrow("Unsupported WAV format");
}
sound->channels = wav->channels;
sound->sampleRate = wav->sampleRate;
lovrAssert(wav->frameSize == lovrSoundGetStride(sound), "Invalid WAV");
size_t offset = 12 + 8 + wav->fmtSize;
char* data = (char*) blob->data + offset;
while (offset < blob->size - 8) {
uint32_t chunkSize = *((uint32_t*) data + 1);
if (!memcmp(data, "data", 4)) {
offset += 8;
data += 8;
lovrAssert(chunkSize == blob->size - offset, "Invalid WAV");
size_t size = blob->size - offset;
void* samples = malloc(size); // TODO Blob views
lovrAssert(samples, "Out of memory");
memcpy(samples, data, size);
sound->blob = lovrBlobCreate(samples, size, blob->name);
sound->read = lovrSoundReadRaw;
sound->frames = size / wav->frameSize;
return sound;
} else {
offset += chunkSize + 8;
data += chunkSize + 8;
}
}
} else if (!mp3dec_detect_buf(blob->data, blob->size)) {
if (decode) {
mp3dec_t decoder;
mp3dec_file_info_t info;
int status = mp3dec_load_buf(&decoder, blob->data, blob->size, &info, NULL, NULL);
lovrAssert(!status, "Could not decode mp3 from '%s'", blob->name);
sound->blob = lovrBlobCreate(info.buffer, info.samples * sizeof(float), blob->name);
sound->format = SAMPLE_F32;
sound->sampleRate = info.hz;
sound->channels = info.channels;
sound->frames = info.samples / info.channels;
sound->read = lovrSoundReadRaw;
return sound;
} else {
mp3dec_ex_t* decoder = sound->decoder = malloc(sizeof(mp3dec_ex_t));
lovrAssert(decoder, "Out of memory");
if (mp3dec_ex_open_buf(sound->decoder, blob->data, blob->size, MP3D_SEEK_TO_SAMPLE)) {
free(sound->decoder);
lovrThrow("Could not load mp3 from '%s'", blob->name);
}
sound->format = SAMPLE_F32;
sound->sampleRate = decoder->info.hz;
sound->channels = decoder->info.channels;
sound->frames = decoder->samples / sound->channels;
sound->read = lovrSoundReadMp3;
sound->blob = blob;
lovrRetain(blob);
return sound;
}
}
lovrThrow("Could not load sound from '%s': Audio format not recognized", blob->name);
return NULL;
}
void lovrSoundDestroy(void* ref) {
Sound* sound = (Sound*) ref;
lovrRelease(sound->blob, lovrBlobDestroy);
if (sound->read == lovrSoundReadOgg) stb_vorbis_close(sound->decoder);
if (sound->read == lovrSoundReadMp3) mp3dec_ex_close(sound->decoder), free(sound->decoder);
ma_pcm_rb_uninit(sound->stream);
free(sound->stream);
free(sound);
}
Blob* lovrSoundGetBlob(Sound* sound) {
return sound->blob;
}
SampleFormat lovrSoundGetFormat(Sound* sound) {
return sound->format;
}
uint32_t lovrSoundGetChannelCount(Sound* sound) {
return sound->channels;
}
uint32_t lovrSoundGetSampleRate(Sound* sound) {
return sound->sampleRate;
}
uint32_t lovrSoundGetFrameCount(Sound* sound) {
return sound->stream ? ma_pcm_rb_available_read(sound->stream) : sound->frames;
}
size_t lovrSoundGetStride(Sound* sound) {
return sound->channels * (sound->format == SAMPLE_I16 ? sizeof(short) : sizeof(float));
}
bool lovrSoundIsCompressed(Sound* sound) {
return sound->decoder;
}
bool lovrSoundIsStream(Sound* sound) {
return sound->stream;
}
uint32_t lovrSoundRead(Sound* sound, uint32_t offset, uint32_t count, void* data) {
return sound->read(sound, offset, count, data);
}
uint32_t lovrSoundWrite(Sound* sound, uint32_t offset, uint32_t count, const void* data) {
lovrAssert(!sound->decoder, "Compressed Sound can not be written to");
size_t stride = lovrSoundGetStride(sound);
uint32_t frames = 0;
if (sound->stream) {
const char* bytes = data;
while (frames < count) {
void* pointer;
uint32_t chunk = count - frames;
ma_pcm_rb_acquire_write(sound->stream, &chunk, &pointer);
memcpy(pointer, bytes, chunk * stride);
ma_pcm_rb_commit_write(sound->stream, chunk, pointer);
if (chunk == 0) break;
bytes += chunk * stride;
frames += chunk;
}
} else {
count = MIN(count, sound->frames - offset);
memcpy((char*) sound->blob->data + offset * stride, data, count * stride);
frames = count;
}
return frames;
}
uint32_t lovrSoundCopy(Sound* src, Sound* dst, uint32_t count, uint32_t srcOffset, uint32_t dstOffset) {
lovrAssert(!dst->decoder, "Compressed Sound can not be written to");
lovrAssert(src != dst, "Can not copy a Sound to itself");
lovrAssert(src->format == dst->format, "Sound formats need to match");
lovrAssert(src->channels == dst->channels, "Sound channel layouts need to match");
uint32_t frames = 0;
if (dst->stream) {
while (frames < count) {
void* data;
uint32_t available = count - frames;
ma_pcm_rb_acquire_write(dst->stream, &available, &data);
uint32_t read = src->read(src, srcOffset + frames, available, data);
ma_pcm_rb_commit_write(dst->stream, read, data);
if (read == 0) break;
frames += read;
}
} else {
count = MIN(count, dst->frames - dstOffset);
size_t stride = lovrSoundGetStride(src);
char* data = (char*) dst->blob->data + dstOffset * stride;
while (frames < count) {
uint32_t read = src->read(src, srcOffset + frames, count - frames, data);
if (read == 0) break;
data += read * stride;
frames += read;
}
}
return frames;
}

29
src/modules/data/sound.h Normal file
View File

@ -0,0 +1,29 @@
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#pragma once
struct Blob;
typedef enum {
SAMPLE_F32,
SAMPLE_I16
} SampleFormat;
typedef struct Sound Sound;
Sound* lovrSoundCreateRaw(uint32_t frames, SampleFormat format, uint32_t channels, uint32_t sampleRate, struct Blob* data);
Sound* lovrSoundCreateStream(uint32_t frames, SampleFormat format, uint32_t channels, uint32_t sampleRate);
Sound* lovrSoundCreateFromFile(struct Blob* blob, bool decode);
void lovrSoundDestroy(void* ref);
struct Blob* lovrSoundGetBlob(Sound* sound);
SampleFormat lovrSoundGetFormat(Sound* sound);
uint32_t lovrSoundGetChannelCount(Sound* sound);
uint32_t lovrSoundGetSampleRate(Sound* sound);
uint32_t lovrSoundGetFrameCount(Sound* sound);
size_t lovrSoundGetStride(Sound* sound);
bool lovrSoundIsCompressed(Sound* sound);
bool lovrSoundIsStream(Sound* sound);
uint32_t lovrSoundRead(Sound* sound, uint32_t offset, uint32_t count, void* data);
uint32_t lovrSoundWrite(Sound* sound, uint32_t offset, uint32_t count, const void* data);
uint32_t lovrSoundCopy(Sound* src, Sound* dst, uint32_t frames, uint32_t srcOffset, uint32_t dstOffset);

View File

@ -1,348 +0,0 @@
#include "data/soundData.h"
#include "data/blob.h"
#include "core/util.h"
#include "lib/stb/stb_vorbis.h"
#include "lib/miniaudio/miniaudio.h"
#define MINIMP3_FLOAT_OUTPUT
#define MINIMP3_NO_STDIO
#include "lib/minimp3/minimp3_ex.h"
#include <stdlib.h>
#include <string.h>
static const ma_format miniaudioFormats[] = {
[SAMPLE_I16] = ma_format_s16,
[SAMPLE_F32] = ma_format_f32
};
struct SoundData {
ref_t ref;
uint32_t (*read)(SoundData* soundData, uint32_t offset, uint32_t count, void* data);
struct Blob* blob;
void* decoder;
void* stream;
SampleFormat format;
uint32_t sampleRate;
uint32_t channels;
uint32_t frames;
uint32_t cursor;
};
// Readers
static uint32_t lovrSoundDataReadRaw(SoundData* soundData, uint32_t offset, uint32_t count, void* data) {
uint8_t* p = soundData->blob->data;
uint32_t n = MIN(count, soundData->frames - offset);
size_t stride = lovrSoundDataGetStride(soundData);
memcpy(data, p + offset * stride, n * stride);
return n;
}
static uint32_t lovrSoundDataReadStream(SoundData* soundData, uint32_t offset, uint32_t count, void* data) {
void* p = NULL;
uint32_t frames = count;
ma_pcm_rb_acquire_read(soundData->stream, &frames, &p);
memcpy(data, p, frames * lovrSoundDataGetStride(soundData));
ma_pcm_rb_commit_read(soundData->stream, frames, p);
return frames;
}
static uint32_t lovrSoundDataReadOgg(SoundData* soundData, uint32_t offset, uint32_t count, void* data) {
if (soundData->cursor != offset) {
stb_vorbis_seek(soundData->decoder, (int) offset);
soundData->cursor = offset;
}
uint32_t channels = soundData->channels;
uint32_t n = stb_vorbis_get_samples_float_interleaved(soundData->decoder, channels, data, count * channels);
soundData->cursor += n;
return n;
}
static uint32_t lovrSoundDataReadMp3(SoundData* soundData, uint32_t offset, uint32_t count, void* data) {
if (soundData->cursor != offset) {
mp3dec_ex_seek(soundData->decoder, offset);
soundData->cursor = offset;
}
size_t samples = mp3dec_ex_read(soundData->decoder, data, count * soundData->channels);
uint32_t frames = samples / soundData->channels;
soundData->cursor += frames;
return frames;
}
// SoundData
SoundData* lovrSoundDataCreateRaw(uint32_t frames, SampleFormat format, uint32_t channels, uint32_t sampleRate, struct Blob* blob) {
SoundData* soundData = calloc(1, sizeof(SoundData));
lovrAssert(soundData, "Out of memory");
soundData->ref = 1;
soundData->frames = frames;
soundData->format = format;
soundData->channels = channels;
soundData->sampleRate = sampleRate;
soundData->read = lovrSoundDataReadRaw;
size_t size = frames * lovrSoundDataGetStride(soundData);
void* data = calloc(1, size);
lovrAssert(data, "Out of memory");
soundData->blob = lovrBlobCreate(data, size, "SoundData");
if (blob) {
memcpy(soundData->blob->data, blob->data, MIN(size, blob->size));
}
return soundData;
}
SoundData* lovrSoundDataCreateStream(uint32_t frames, SampleFormat format, uint32_t channels, uint32_t sampleRate) {
SoundData* soundData = calloc(1, sizeof(SoundData));
lovrAssert(soundData, "Out of memory");
soundData->ref = 1;
soundData->frames = frames;
soundData->format = format;
soundData->channels = channels;
soundData->sampleRate = sampleRate;
soundData->read = lovrSoundDataReadStream;
soundData->stream = malloc(sizeof(ma_pcm_rb));
lovrAssert(soundData->stream, "Out of memory");
size_t size = frames * lovrSoundDataGetStride(soundData);
void* data = malloc(size);
lovrAssert(data, "Out of memory");
soundData->blob = lovrBlobCreate(data, size, NULL);
ma_result status = ma_pcm_rb_init(miniaudioFormats[format], channels, frames, data, NULL, soundData->stream);
lovrAssert(status == MA_SUCCESS, "Failed to create ring buffer for streamed SoundData: %s (%d)", ma_result_description(status), status);
return soundData;
}
SoundData* lovrSoundDataCreateFromFile(struct Blob* blob, bool decode) {
SoundData* soundData = calloc(1, sizeof(SoundData));
lovrAssert(soundData, "Out of memory");
soundData->ref = 1;
if (blob->size >= 4 && !memcmp(blob->data, "OggS", 4)) {
soundData->decoder = stb_vorbis_open_memory(blob->data, (int) blob->size, NULL, NULL);
lovrAssert(soundData->decoder, "Could not load sound from '%s'", blob->name);
stb_vorbis_info info = stb_vorbis_get_info(soundData->decoder);
soundData->format = SAMPLE_F32;
soundData->channels = info.channels;
soundData->sampleRate = info.sample_rate;
soundData->frames = stb_vorbis_stream_length_in_samples(soundData->decoder);
if (decode) {
soundData->read = lovrSoundDataReadRaw;
size_t size = soundData->frames * lovrSoundDataGetStride(soundData);
void* data = calloc(1, size);
lovrAssert(data, "Out of memory");
soundData->blob = lovrBlobCreate(data, size, "SoundData");
if (stb_vorbis_get_samples_float_interleaved(soundData->decoder, info.channels, data, size / 4) < (int) soundData->frames) {
lovrThrow("Could not decode vorbis from '%s'", blob->name);
}
stb_vorbis_close(soundData->decoder);
soundData->decoder = NULL;
} else {
soundData->read = lovrSoundDataReadOgg;
soundData->blob = blob;
lovrRetain(blob);
}
return soundData;
} else if (blob->size >= 64 && !memcmp(blob->data, "RIFF", 4)) {
typedef struct {
uint32_t id;
uint32_t size;
uint32_t fileFormat;
uint32_t fmtId;
uint32_t fmtSize;
uint16_t format;
uint16_t channels;
uint32_t sampleRate;
uint32_t byteRate;
uint16_t frameSize;
uint16_t sampleSize;
uint16_t extSize;
uint16_t validBitsPerSample;
uint32_t channelMask;
char guid[16];
} wavHeader;
char guidi16[16] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 };
char guidf32[16] = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 };
wavHeader* wav = blob->data;
lovrAssert(wav->size == blob->size - 8, "Invalid WAV");
lovrAssert(!memcmp(&wav->fileFormat, "WAVE", 4), "Invalid WAV");
lovrAssert(!memcmp(&wav->fmtId, "fmt ", 4), "Invalid WAV");
if (wav->fmtSize == 16 && wav->format == 1 && wav->sampleSize == 16) {
soundData->format = SAMPLE_I16;
} else if (wav->fmtSize == 16 && wav->format == 3 && wav->sampleSize == 32) {
soundData->format = SAMPLE_F32;
} else if (wav->fmtSize == 40 && wav->format == 65534 && wav->extSize == 22 && wav->validBitsPerSample == 16 && !memcmp(wav->guid, guidi16, 16)) {
soundData->format = SAMPLE_I16;
} else if (wav->fmtSize == 40 && wav->format == 65534 && wav->extSize == 22 && wav->validBitsPerSample == 32 && !memcmp(wav->guid, guidf32, 16)) {
soundData->format = SAMPLE_F32;
} else {
lovrThrow("Unsupported WAV format");
}
soundData->channels = wav->channels;
soundData->sampleRate = wav->sampleRate;
lovrAssert(wav->frameSize == lovrSoundDataGetStride(soundData), "Invalid WAV");
size_t offset = 12 + 8 + wav->fmtSize;
char* data = (char*) blob->data + offset;
while (offset < blob->size - 8) {
uint32_t chunkSize = *((uint32_t*) data + 1);
if (!memcmp(data, "data", 4)) {
offset += 8;
data += 8;
lovrAssert(chunkSize == blob->size - offset, "Invalid WAV");
size_t size = blob->size - offset;
void* samples = malloc(size); // TODO Blob views
lovrAssert(samples, "Out of memory");
memcpy(samples, data, size);
soundData->blob = lovrBlobCreate(samples, size, blob->name);
soundData->read = lovrSoundDataReadRaw;
soundData->frames = size / wav->frameSize;
return soundData;
} else {
offset += chunkSize + 8;
data += chunkSize + 8;
}
}
} else if (!mp3dec_detect_buf(blob->data, blob->size)) {
if (decode) {
mp3dec_t decoder;
mp3dec_file_info_t info;
int status = mp3dec_load_buf(&decoder, blob->data, blob->size, &info, NULL, NULL);
lovrAssert(!status, "Could not decode mp3 from '%s'", blob->name);
soundData->blob = lovrBlobCreate(info.buffer, info.samples * sizeof(float), blob->name);
soundData->format = SAMPLE_F32;
soundData->sampleRate = info.hz;
soundData->channels = info.channels;
soundData->frames = info.samples / info.channels;
soundData->read = lovrSoundDataReadRaw;
return soundData;
} else {
mp3dec_ex_t* decoder = soundData->decoder = malloc(sizeof(mp3dec_ex_t));
lovrAssert(decoder, "Out of memory");
if (mp3dec_ex_open_buf(soundData->decoder, blob->data, blob->size, MP3D_SEEK_TO_SAMPLE)) {
free(soundData->decoder);
lovrThrow("Could not load mp3 from '%s'", blob->name);
}
soundData->format = SAMPLE_F32;
soundData->sampleRate = decoder->info.hz;
soundData->channels = decoder->info.channels;
soundData->frames = decoder->samples / soundData->channels;
soundData->read = lovrSoundDataReadMp3;
soundData->blob = blob;
lovrRetain(blob);
return soundData;
}
}
lovrThrow("Could not load sound from '%s': Audio format not recognized", blob->name);
return NULL;
}
void lovrSoundDataDestroy(void* ref) {
SoundData* soundData = (SoundData*) ref;
lovrRelease(soundData->blob, lovrBlobDestroy);
if (soundData->read == lovrSoundDataReadOgg) stb_vorbis_close(soundData->decoder);
if (soundData->read == lovrSoundDataReadMp3) mp3dec_ex_close(soundData->decoder), free(soundData->decoder);
ma_pcm_rb_uninit(soundData->stream);
free(soundData->stream);
free(soundData);
}
Blob* lovrSoundDataGetBlob(SoundData* soundData) {
return soundData->blob;
}
SampleFormat lovrSoundDataGetFormat(SoundData* soundData) {
return soundData->format;
}
uint32_t lovrSoundDataGetChannelCount(SoundData* soundData) {
return soundData->channels;
}
uint32_t lovrSoundDataGetSampleRate(SoundData* soundData) {
return soundData->sampleRate;
}
uint32_t lovrSoundDataGetFrameCount(SoundData* soundData) {
return soundData->stream ? ma_pcm_rb_available_read(soundData->stream) : soundData->frames;
}
size_t lovrSoundDataGetStride(SoundData* soundData) {
return soundData->channels * (soundData->format == SAMPLE_I16 ? sizeof(short) : sizeof(float));
}
bool lovrSoundDataIsCompressed(SoundData* soundData) {
return soundData->decoder;
}
bool lovrSoundDataIsStream(SoundData* soundData) {
return soundData->stream;
}
uint32_t lovrSoundDataRead(SoundData* soundData, uint32_t offset, uint32_t count, void* data) {
return soundData->read(soundData, offset, count, data);
}
uint32_t lovrSoundDataWrite(SoundData* soundData, uint32_t offset, uint32_t count, const void* data) {
lovrAssert(!soundData->decoder, "Compressed SoundData can not be written to");
size_t stride = lovrSoundDataGetStride(soundData);
uint32_t frames = 0;
if (soundData->stream) {
const char* bytes = data;
while (frames < count) {
void* pointer;
uint32_t chunk = count - frames;
ma_pcm_rb_acquire_write(soundData->stream, &chunk, &pointer);
memcpy(pointer, bytes, chunk * stride);
ma_pcm_rb_commit_write(soundData->stream, chunk, pointer);
if (chunk == 0) break;
bytes += chunk * stride;
frames += chunk;
}
} else {
count = MIN(count, soundData->frames - offset);
memcpy((char*) soundData->blob->data + offset * stride, data, count * stride);
frames = count;
}
return frames;
}
uint32_t lovrSoundDataCopy(SoundData* src, SoundData* dst, uint32_t count, uint32_t srcOffset, uint32_t dstOffset) {
lovrAssert(!dst->decoder, "Compressed SoundData can not be written to");
lovrAssert(src != dst, "Can not copy a SoundData to itself");
lovrAssert(src->format == dst->format, "SoundData formats need to match");
lovrAssert(src->channels == dst->channels, "SoundData channel layouts need to match");
uint32_t frames = 0;
if (dst->stream) {
while (frames < count) {
void* data;
uint32_t available = count - frames;
ma_pcm_rb_acquire_write(dst->stream, &available, &data);
uint32_t read = src->read(src, srcOffset + frames, available, data);
ma_pcm_rb_commit_write(dst->stream, read, data);
if (read == 0) break;
frames += read;
}
} else {
count = MIN(count, dst->frames - dstOffset);
size_t stride = lovrSoundDataGetStride(src);
char* data = (char*) dst->blob->data + dstOffset * stride;
while (frames < count) {
uint32_t read = src->read(src, srcOffset + frames, count - frames, data);
if (read == 0) break;
data += read * stride;
frames += read;
}
}
return frames;
}

View File

@ -1,29 +0,0 @@
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#pragma once
struct Blob;
typedef enum {
SAMPLE_F32,
SAMPLE_I16
} SampleFormat;
typedef struct SoundData SoundData;
SoundData* lovrSoundDataCreateRaw(uint32_t frames, SampleFormat format, uint32_t channels, uint32_t sampleRate, struct Blob* data);
SoundData* lovrSoundDataCreateStream(uint32_t frames, SampleFormat format, uint32_t channels, uint32_t sampleRate);
SoundData* lovrSoundDataCreateFromFile(struct Blob* blob, bool decode);
void lovrSoundDataDestroy(void* ref);
struct Blob* lovrSoundDataGetBlob(SoundData* soundData);
SampleFormat lovrSoundDataGetFormat(SoundData* soundData);
uint32_t lovrSoundDataGetChannelCount(SoundData* soundData);
uint32_t lovrSoundDataGetSampleRate(SoundData* soundData);
uint32_t lovrSoundDataGetFrameCount(SoundData* soundData);
size_t lovrSoundDataGetStride(SoundData* soundData);
bool lovrSoundDataIsCompressed(SoundData* soundData);
bool lovrSoundDataIsStream(SoundData* soundData);
uint32_t lovrSoundDataRead(SoundData* soundData, uint32_t offset, uint32_t count, void* data);
uint32_t lovrSoundDataWrite(SoundData* soundData, uint32_t offset, uint32_t count, const void* data);
uint32_t lovrSoundDataCopy(SoundData* src, SoundData* dst, uint32_t frames, uint32_t srcOffset, uint32_t dstOffset);