From 97fcc429bf0606e627c8f27ee94e6f62e370329d Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 22 Aug 2021 09:31:46 +1000 Subject: [PATCH] WIP on adding speed/rate argument when playing sounds instead --- src/Audio.c | 103 +++++++++++++++++++++++++++---------------------- src/Audio.h | 16 +++++--- src/LBackend.c | 2 +- 3 files changed, 69 insertions(+), 52 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index 92c070e4d..e15d4bc1b 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -54,8 +54,8 @@ static void AudioWarn(cc_result res, const char* action) { Logger_Warn(res, action, Audio_DescribeError); } static void AudioBase_Clear(struct AudioContext* ctx); -static void* AudioBase_AdjustSound(struct AudioContext* ctx, struct Sound* snd, int volume); -static cc_result AudioBase_PlaySound(struct AudioContext* ctx, struct Sound* snd, void* data); +static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, struct AudioData* data); +static cc_result AudioBase_PlaySound(struct AudioContext* ctx, struct AudioData* data); #if defined CC_BUILD_OPENAL @@ -289,14 +289,14 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { *inUse = ctx->count - ctx->free; return 0; } -cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { +cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { /* Channels/Sample rate is per buffer, not a per source property */ return true; } -cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) { - void* data = AudioBase_AdjustSound(ctx, snd, volume); - if (data) return AudioBase_PlaySound(ctx, snd, data); +cc_result Audio_PlayData(struct AudioContext* ctx, struct Sound* snd, int volume) { + cc_book ok = AudioBase_AdjustSound(ctx, snd, volume); + if (ok) return AudioBase_PlaySound(ctx, snd, data); return ERR_OUT_OF_MEMORY; } @@ -477,15 +477,21 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { *inUse = count; return res; } +/* achieve higher speed by playing samples at higher sample rate */ +#define Audio_AdjustSampleRate(data) ((data->sampleRate * data->rate) / 100) -cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { +cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { + int channels = data->channels; + int sampleRate = Audio_AdjustSampleRate(data); return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate); } -cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) { - void* data = AudioBase_AdjustSound(ctx, snd, volume); - if (data) return AudioBase_PlaySound(ctx, snd, data); - return ERR_OUT_OF_MEMORY; +cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { + cc_bool ok = AudioBase_AdjustSound(ctx, data); + if (!ok) return ERR_OUT_OF_MEMORY; + + data->sampleRate = Audio_AdjustSampleRate(data); + return AudioBase_PlaySound(ctx, data); } cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { @@ -684,9 +690,9 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate); } -cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) { - void* data = AudioBase_AdjustSound(ctx, snd, volume); - if (data) return AudioBase_PlaySound(ctx, snd, data); +cc_result Audio_PlayData(struct AudioContext* ctx, struct Sound* snd, int volume) { + cc_bool ok = AudioBase_AdjustSound(ctx, snd, volume); + if (ok) return AudioBase_PlaySound(ctx, snd, data); return ERR_OUT_OF_MEMORY; } @@ -756,12 +762,12 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { *inUse = 0; return 0; } -cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { +cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { /* Channels/Sample rate is per buffer, not a per source property */ return true; } -cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) { +cc_result Audio_PlayData(struct AudioContext* ctx, struct Sound* snd, int volume) { if (!ctx->contextID) ctx->contextID = interop_AudioCreate(); return interop_AudioPlay(ctx->contextID, snd, volume); @@ -792,34 +798,35 @@ static void AudioBase_Clear(struct AudioContext* ctx) { ctx->_tmpSize = 0; } -static void* AudioBase_AdjustSound(struct AudioContext* ctx, struct Sound* snd, int volume) { - void* data; - if (volume >= 100) return snd->data; +static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, struct AudioData* data) { + void* audio; + if (data->volume >= 100) return true; /* copy to temp buffer to apply volume */ - if (ctx->_tmpSize < snd->size) { + if (ctx->_tmpSize < data->size) { /* TODO: check if we can realloc NULL without a problem */ if (ctx->_tmpData) { - data = Mem_TryRealloc(ctx->_tmpData, snd->size, 1); + audio = Mem_TryRealloc(ctx->_tmpData, data->size, 1); } else { - data = Mem_TryAlloc(snd->size, 1); + audio = Mem_TryAlloc(data->size, 1); } - if (!data) return NULL; - ctx->_tmpData = data; - ctx->_tmpSize = snd->size; + if (!data) return false; + ctx->_tmpData = audio; + ctx->_tmpSize = data->size; } - data = ctx->_tmpData; - Mem_Copy(data, snd->data, snd->size); - ApplyVolume((cc_int16*)data, snd->size / 2, volume); - return data; + audio = ctx->_tmpData; + Mem_Copy(audio, data->data, data->size); + ApplyVolume((cc_int16*)audio, data->size / 2, data->volume); + data->data = audio; + return true; } -static cc_result AudioBase_PlaySound(struct AudioContext* ctx, struct Sound* snd, void* data) { +static cc_result AudioBase_PlaySound(struct AudioContext* ctx, struct AudioData* data) { cc_result res; - if ((res = Audio_SetFormat(ctx, snd->channels, snd->sampleRate))) return res; - if ((res = Audio_QueueData(ctx, data, snd->size))) return res; + if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate))) return res; + if ((res = Audio_QueueData(ctx, data->data, data->size))) return res; if ((res = Audio_Play(ctx))) return res; return 0; } @@ -980,27 +987,31 @@ CC_NOINLINE static void Sounds_Fail(cc_result res) { } static void Sounds_Play(cc_uint8 type, struct Soundboard* board) { - const struct Sound* snd_; - struct Sound snd; + struct AudioData data; + const struct Sound* snd; struct AudioContext* ctx; - int inUse, i, volume; + int inUse, i; cc_result res; if (type == SOUND_NONE || !Audio_SoundsVolume) return; - snd_ = Soundboard_PickRandom(board, type); - if (!snd_) return; + snd = Soundboard_PickRandom(board, type); + if (!snd) return; - snd = *snd_; - volume = Audio_SoundsVolume; + data.data = snd->data; + data.size = snd->size; + data.channels = snd->channels; + data.sampleRate = snd->sampleRate; + data.rate = 100; + data.volume = Audio_SoundsVolume; /* https://minecraft.fandom.com/wiki/Block_of_Gold#Sounds */ /* https://minecraft.fandom.com/wiki/Grass#Sounds */ if (board == &digBoard) { - if (type == SOUND_METAL) snd.sampleRate = (snd.sampleRate * 6) / 5; - else snd.sampleRate = (snd.sampleRate * 4) / 5; + if (type == SOUND_METAL) data.rate = 120; + else data.rate = 80; } else { - volume /= 2; - if (type == SOUND_METAL) snd.sampleRate = (snd.sampleRate * 7) / 5; + data.volume /= 2; + if (type == SOUND_METAL) data.rate = 140; } /* Try to play on a context that doesn't need to be recreated */ @@ -1010,9 +1021,9 @@ static void Sounds_Play(cc_uint8 type, struct Soundboard* board) { if (res) { Sounds_Fail(res); return; } if (inUse > 0) continue; - if (!Audio_FastPlay(ctx, snd.channels, snd.sampleRate)) continue; + if (!Audio_FastPlay(ctx, &data)) continue; - res = Audio_PlaySound(ctx, &snd, volume); + res = Audio_PlayData(ctx, &data); if (res) Sounds_Fail(res); return; } @@ -1025,7 +1036,7 @@ static void Sounds_Play(cc_uint8 type, struct Soundboard* board) { if (res) { Sounds_Fail(res); return; } if (inUse > 0) continue; - res = Audio_PlaySound(ctx, &snd, volume); + res = Audio_PlayData(ctx, &data); if (res) Sounds_Fail(res); return; } diff --git a/src/Audio.h b/src/Audio.h index 6ba1ce8e5..a89ca299e 100644 --- a/src/Audio.h +++ b/src/Audio.h @@ -12,6 +12,13 @@ struct Sound { int channels, sampleRate; void* data; cc_uint32 size; }; +struct AudioData { + void* data; cc_uint32 size; /* the raw 16 bit integer samples */ + int channels; + int sampleRate; /* frequency / sample rate */ + int volume; /* volume data played at (100 = normal volume) */ + int rate; /* speed/pitch played at (100 = normal speed) */ +}; /* Volume sounds are played at, from 0-100. */ /* NOTE: Use Audio_SetSounds, don't change this directly. */ @@ -44,11 +51,10 @@ cc_result Audio_Play(struct AudioContext* ctx); /* (e.g. if inUse is 0, no audio buffers are being played or queued) */ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse); -/* Plays the given audio data at the given volume */ -cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume); -/* Whether the given audio context can play audio data in the given format, */ -/* without recreating the underlying audio device */ -cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate); +/* Plays the given audio data */ +cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data); +/* Whether the given audio data can be played without recreating the underlying audio device */ +cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data); /* Outputs more detailed information about errors with audio. */ cc_bool Audio_DescribeError(cc_result res, cc_string* dst); #endif diff --git a/src/LBackend.c b/src/LBackend.c index 208481ccb..04bb63cd0 100644 --- a/src/LBackend.c +++ b/src/LBackend.c @@ -206,7 +206,7 @@ static const cc_uint8 checkbox_indices[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static PackedCol checkbox_palette[] = { +static const PackedCol checkbox_palette[] = { PackedCol_Make( 0, 0, 0, 0), PackedCol_Make(144, 144, 144, 255), PackedCol_Make( 61, 61, 61, 255), PackedCol_Make( 94, 94, 94, 255), PackedCol_Make(197, 196, 197, 255), PackedCol_Make( 57, 57, 57, 255),