Allow the creation of a (potentially infinite-length) Sound created by a dynamically run callback

This commit is contained in:
mcc 2021-02-19 23:06:21 -05:00 committed by Bjorn
parent 57a215a0aa
commit ffa63e9912
2 changed files with 34 additions and 2 deletions

View File

@ -16,7 +16,7 @@ static const ma_format miniaudioFormats[] = {
struct Sound {
uint32_t ref;
uint32_t (*read)(Sound* sound, uint32_t offset, uint32_t count, void* data);
SoundCallback* read;
struct Blob* blob;
void* decoder;
void* stream;
@ -25,13 +25,15 @@ struct Sound {
uint32_t sampleRate;
uint32_t frames;
uint32_t cursor;
void* callbackMemo; // When using lovrSoundCreateFromCallback, any state the read callback uses should be stored here
SoundDestroyCallback* callbackMemoDestroy; // This should be used to free the callbackMemo pointer (if appropriate)
};
// 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);
uint32_t n = sound->frames == LOVR_SOUND_ENDLESS ? count : MIN(count, sound->frames - offset);
size_t stride = lovrSoundGetStride(sound);
memcpy(data, p + offset * stride, n * stride);
return n;
@ -255,8 +257,23 @@ Sound* lovrSoundCreateFromFile(struct Blob* blob, bool decode) {
return NULL;
}
Sound* lovrSoundCreateFromCallback(SoundCallback read, void *callbackMemo, SoundDestroyCallback callbackMemoDestroy, SampleFormat format, uint32_t sampleRate, ChannelLayout channels, uint32_t maxFrames) {
Sound* sound = calloc(1, sizeof(Sound));
lovrAssert(sound, "Out of memory");
sound->ref = 1;
sound->read = read;
sound->format = format;
sound->sampleRate = sampleRate;
sound->channels = channels;
sound->frames = maxFrames;
sound->callbackMemo = callbackMemo;
sound->callbackMemoDestroy = callbackMemoDestroy;
return sound;
}
void lovrSoundDestroy(void* ref) {
Sound* sound = (Sound*) ref;
if (sound->callbackMemoDestroy) sound->callbackMemoDestroy(sound);
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);
@ -307,6 +324,7 @@ 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) {
lovrAssert(!sound->decoder, "Compressed Sound can not be written to");
lovrAssert(sound->stream || sound->blob, "Live-generated sound can not be written to");
size_t stride = lovrSoundGetStride(sound);
uint32_t frames = 0;
@ -333,6 +351,7 @@ uint32_t lovrSoundWrite(Sound* sound, uint32_t offset, uint32_t count, const voi
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(dst->stream || dst->blob, "Live-generated 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");
@ -362,3 +381,7 @@ uint32_t lovrSoundCopy(Sound* src, Sound* dst, uint32_t count, uint32_t srcOffse
return frames;
}
void *lovrSoundGetCallbackMemo(Sound *sound) {
return sound->callbackMemo;
}

View File

@ -18,9 +18,17 @@ typedef enum {
} ChannelLayout;
typedef struct Sound Sound;
typedef uint32_t (SoundCallback)(Sound* sound, uint32_t offset, uint32_t count, void* data);
typedef void (SoundDestroyCallback)(Sound* sound);
// Can pass as the maxFrames argument to lovrSoundCreateFromCallback
#define LOVR_SOUND_ENDLESS 0xFFFFFFFF
Sound* lovrSoundCreateRaw(uint32_t frames, SampleFormat format, ChannelLayout channels, uint32_t sampleRate, struct Blob* data);
Sound* lovrSoundCreateStream(uint32_t frames, SampleFormat format, ChannelLayout channels, uint32_t sampleRate);
Sound* lovrSoundCreateFromFile(struct Blob* blob, bool decode);
Sound* lovrSoundCreateFromCallback(SoundCallback read, void *callbackMemo, SoundDestroyCallback callbackDataDestroy, SampleFormat format, uint32_t sampleRate, ChannelLayout channels, uint32_t maxFrames);
void lovrSoundDestroy(void* ref);
struct Blob* lovrSoundGetBlob(Sound* sound);
SampleFormat lovrSoundGetFormat(Sound* sound);
@ -34,3 +42,4 @@ 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);
void *lovrSoundGetCallbackMemo(Sound *sound);