From e22be93ab3f38c41aae2e19e417d82833a7b6793 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 25 Mar 2024 19:46:27 +1100 Subject: [PATCH 1/5] Refactor audio backends to allow explicitly setting volume --- src/Audio.c | 13 ++-- src/Audio.h | 3 +- src/AudioBackend.c | 151 ++++++++++++++++++++++++++++----------------- src/interop_web.js | 13 ++-- 4 files changed, 112 insertions(+), 68 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index 662fa4368..08b3b039d 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -329,7 +329,6 @@ static cc_result Music_Buffer(cc_int16* data, int maxSamples, struct VorbisState cur = &data[samples]; samples += Vorbis_OutputFrame(ctx, cur); } - if (Audio_MusicVolume < 100) { Audio_ApplyVolume(data, samples, Audio_MusicVolume); } res2 = Audio_QueueChunk(&music_ctx, data, samples * 2); if (res2) { music_stopping = true; return res2; } @@ -339,7 +338,7 @@ static cc_result Music_Buffer(cc_int16* data, int maxSamples, struct VorbisState static cc_result Music_PlayOgg(struct Stream* source) { struct OggState ogg; struct VorbisState vorbis = { 0 }; - int channels, sampleRate; + int channels, sampleRate, volume; int chunkSize, samplesPerSecond; void* chunks[AUDIO_MAX_BUFFERS] = { 0 }; @@ -366,7 +365,9 @@ static cc_result Music_PlayOgg(struct Stream* source) { res = ERR_OUT_OF_MEMORY; goto cleanup; } - + + volume = Audio_MusicVolume; + Audio_SetVolume(&music_ctx, volume); /* fill up with some samples before playing */ for (i = 0; i < AUDIO_MAX_BUFFERS && !res; i++) @@ -391,6 +392,10 @@ static cc_result Music_PlayOgg(struct Stream* source) { Audio_Play(&music_ctx); } #endif + if (volume != Audio_MusicVolume) { + volume = Audio_MusicVolume; + Audio_SetVolume(&music_ctx, volume); + } res = Audio_Poll(&music_ctx, &inUse); if (res) { music_stopping = true; break; } @@ -550,4 +555,4 @@ static void OnFree(void) { struct IGameComponent Audio_Component = { OnInit, /* Init */ OnFree /* Free */ -}; \ No newline at end of file +}; diff --git a/src/Audio.h b/src/Audio.h index a4a2b2123..1ec2a4ab3 100644 --- a/src/Audio.h +++ b/src/Audio.h @@ -52,6 +52,8 @@ void Audio_Close(struct AudioContext* ctx); /* Sets the format of the audio data to be played. */ /* NOTE: Changing the format can be expensive, depending on the backend. */ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate); +/* Sets the volume audio data is played at */ +void Audio_SetVolume(struct AudioContext* ctx, int volume); /* Queues the given audio chunk for playing. */ /* NOTE: You MUST ensure Audio_Poll indicates a buffer is free before calling this. */ /* NOTE: Some backends directly read from the data - therefore you MUST NOT modify it */ @@ -77,7 +79,6 @@ void Audio_AllocChunks(cc_uint32 size, void** chunks, int numChunks); void Audio_FreeChunks(void** chunks, int numChunks); extern struct AudioContext music_ctx; -void Audio_ApplyVolume(cc_int16* samples, int count, int volume); void Audio_Warn(cc_result res, const char* action); cc_result AudioPool_Play(struct AudioData* data); diff --git a/src/AudioBackend.c b/src/AudioBackend.c index c5ffde714..dc0e2107a 100644 --- a/src/AudioBackend.c +++ b/src/AudioBackend.c @@ -6,27 +6,6 @@ #include "Utils.h" #include "Platform.h" -void Audio_ApplyVolume(cc_int16* samples, int count, int volume) { - int i; - - for (i = 0; i < (count & ~0x07); i += 8, samples += 8) { - samples[0] = (samples[0] * volume / 100); - samples[1] = (samples[1] * volume / 100); - samples[2] = (samples[2] * volume / 100); - samples[3] = (samples[3] * volume / 100); - - samples[4] = (samples[4] * volume / 100); - samples[5] = (samples[5] * volume / 100); - samples[6] = (samples[6] * volume / 100); - samples[7] = (samples[7] * volume / 100); - } - - for (; i < count; i++, samples++) { - samples[0] = (samples[0] * volume / 100); - } -} - - void Audio_Warn(cc_result res, const char* action) { Logger_Warn(res, action, Audio_DescribeError); } @@ -239,6 +218,11 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate return 0; } +void Audio_SetVolume(struct AudioContext* ctx, int volume) { + _alSourcef(ctx->source, AL_GAIN, volume / 100.0f); + _alGetError(); /* Reset error state */ +} + cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size) { ALuint buffer; ALenum err; @@ -286,11 +270,8 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { } cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - cc_result res; - + cc_result res; data->sampleRate = Audio_AdjustSampleRate(data); - _alSourcef(ctx->source, AL_GAIN, data->volume / 100.0f); - _alGetError(); /* Reset error state */ if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate))) return res; if ((res = Audio_QueueChunk(ctx, data->data, data->size))) return res; @@ -384,7 +365,7 @@ WINMMAPI UINT WINAPI waveOutGetNumDevs(void); struct AudioContext { HWAVEOUT handle; WAVEHDR headers[AUDIO_MAX_BUFFERS]; - int count, channels, sampleRate; + int count, channels, sampleRate, volume; cc_uint32 _tmpSize; void* _tmpData; }; #define AUDIO_COMMON_VOLUME @@ -399,7 +380,8 @@ cc_result Audio_Init(struct AudioContext* ctx, int buffers) { for (i = 0; i < buffers; i++) { ctx->headers[i].dwFlags = WHDR_DONE; } - ctx->count = buffers; + ctx->count = buffers; + ctx->volume = 100; return 0; } @@ -454,6 +436,8 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate return res; } +void Audio_SetVolume(struct AudioContext* ctx, int volume) { ctx->volume = volume; } + cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) { cc_result res = 0; WAVEHDR* hdr; @@ -536,19 +520,19 @@ void Audio_FreeChunks(void** chunks, int numChunks) { *#########################################################################################################################*/ #include #include +#include "ExtMath.h" static SLObjectItf slEngineObject; static SLEngineItf slEngineEngine; static SLObjectItf slOutputObject; struct AudioContext { int count, channels, sampleRate; - SLObjectItf playerObject; - SLPlayItf playerPlayer; - SLBufferQueueItf playerQueue; + SLObjectItf playerObject; + SLPlayItf playerPlayer; + SLBufferQueueItf playerQueue; SLPlaybackRateItf playerRate; - cc_uint32 _tmpSize; void* _tmpData; + SLVolumeItf playerVolume; }; -#define AUDIO_COMMON_VOLUME #define AUDIO_COMMON_ALLOC static SLresult (SLAPIENTRY *_slCreateEngine)(SLObjectItf* engine, SLuint32 numOptions, const SLEngineOption* engineOptions, @@ -558,13 +542,15 @@ static SLInterfaceID* _SL_IID_PLAY; static SLInterfaceID* _SL_IID_ENGINE; static SLInterfaceID* _SL_IID_BUFFERQUEUE; static SLInterfaceID* _SL_IID_PLAYBACKRATE; +static SLInterfaceID* _SL_IID_VOLUME; static const cc_string slLib = String_FromConst("libOpenSLES.so"); static cc_bool LoadSLFuncs(void) { static const struct DynamicLibSym funcs[] = { DynamicLib_Sym(slCreateEngine), DynamicLib_Sym(SL_IID_NULL), DynamicLib_Sym(SL_IID_PLAY), DynamicLib_Sym(SL_IID_ENGINE), - DynamicLib_Sym(SL_IID_BUFFERQUEUE), DynamicLib_Sym(SL_IID_PLAYBACKRATE) + DynamicLib_Sym(SL_IID_BUFFERQUEUE), DynamicLib_Sym(SL_IID_PLAYBACKRATE), + DynamicLib_Sym(SL_IID_VOLUME) }; void* lib; @@ -581,8 +567,7 @@ cc_bool AudioBackend_Init(void) { if (!LoadSLFuncs()) { Logger_WarnFunc(&msg); return false; } /* mixer doesn't use any effects */ - ids[0] = *_SL_IID_NULL; - req[0] = SL_BOOLEAN_FALSE; + ids[0] = *_SL_IID_NULL; req[0] = SL_BOOLEAN_FALSE; res = _slCreateEngine(&slEngineObject, 0, NULL, 0, NULL, NULL); if (res) { Audio_Warn(res, "creating OpenSL ES engine"); return false; } @@ -637,12 +622,16 @@ static void Audio_Reset(struct AudioContext* ctx) { ctx->playerPlayer = NULL; ctx->playerQueue = NULL; ctx->playerRate = NULL; + ctx->playerVolume = NULL; } void Audio_Close(struct AudioContext* ctx) { Audio_Stop(ctx); Audio_Reset(ctx); - AudioBase_Clear(ctx); + + ctx->count = 0; + ctx->channels = 0; + ctx->sampleRate = 0; } cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { @@ -650,8 +639,8 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate SLDataLocator_OutputMix output; SLObjectItf playerObject; SLDataFormat_PCM fmt; - SLInterfaceID ids[3]; - SLboolean req[3]; + SLInterfaceID ids[4]; + SLboolean req[4]; SLDataSource src; SLDataSink dst; cc_result res; @@ -682,8 +671,9 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate ids[0] = *_SL_IID_BUFFERQUEUE; req[0] = SL_BOOLEAN_TRUE; ids[1] = *_SL_IID_PLAY; req[1] = SL_BOOLEAN_TRUE; ids[2] = *_SL_IID_PLAYBACKRATE; req[2] = SL_BOOLEAN_TRUE; + ids[3] = *_SL_IID_VOLUME; req[3] = SL_BOOLEAN_TRUE; - res = (*slEngineEngine)->CreateAudioPlayer(slEngineEngine, &playerObject, &src, &dst, 3, ids, req); + res = (*slEngineEngine)->CreateAudioPlayer(slEngineEngine, &playerObject, &src, &dst, 4, ids, req); ctx->playerObject = playerObject; if (res) return res; @@ -691,9 +681,19 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate if ((res = (*playerObject)->GetInterface(playerObject, *_SL_IID_PLAY, &ctx->playerPlayer))) return res; if ((res = (*playerObject)->GetInterface(playerObject, *_SL_IID_BUFFERQUEUE, &ctx->playerQueue))) return res; if ((res = (*playerObject)->GetInterface(playerObject, *_SL_IID_PLAYBACKRATE, &ctx->playerRate))) return res; + if ((res = (*playerObject)->GetInterface(playerObject, *_SL_IID_VOLUME, &ctx->playerVolume))) return res; return 0; } +static float Log10(float volume) { return Math_Log(volume) / Math_Log(10); } + +void Audio_SetVolume(struct AudioContext* ctx, int volume) { + // log of 0 is undefined + SLmillibel attenuation = volume == 0 ? SL_MILLIBEL_MIN : (2000 * Log10(volume / 100.0f)); + + (*ctx->playerVolume)->SetVolumeLevel(ctx->playerVolume, attenuation); +} + cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size) { return (*ctx->playerQueue)->Enqueue(ctx->playerQueue, chunk, size); } @@ -722,9 +722,7 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { } cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - cc_bool ok = AudioBase_AdjustSound(ctx, data); cc_result res; - if (!ok) return ERR_OUT_OF_MEMORY; if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate))) return res; /* rate is in milli, so 1000 = normal rate */ @@ -831,6 +829,14 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate return 0; } +void Audio_SetVolume(struct AudioContext* ctx, int volume) { + float mix[12] = { 0 }; + mix[0] = volume / 100.0f; + mix[1] = volume / 100.0f; + + ndspChnSetMix(ctx->chanID, mix); +} + cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) { ndspWaveBuf* buf; @@ -885,11 +891,6 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { } cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - float mix[12] = { 0 }; - mix[0] = data->volume / 100.0f; - mix[1] = data->volume / 100.0f; - - ndspChnSetMix(ctx->chanID, mix); data->sampleRate = Audio_AdjustSampleRate(data); cc_result res; @@ -1031,6 +1032,10 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate return 0; } +void Audio_SetVolume(struct AudioContext* ctx, int volume) { + audrvVoiceSetVolume(&drv, ctx->chanID, volume / 100.0f); +} + cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) { AudioDriverWaveBuf* buf; @@ -1090,7 +1095,6 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { return 0; } - cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return true; } @@ -1102,9 +1106,7 @@ cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate))) return res; if ((res = Audio_QueueChunk(ctx, data->data, data->size))) return res; - audrvVoiceSetVolume(&drv, ctx->chanID, data->volume/100.f); if ((res = Audio_Play(ctx))) return res; - return 0; } @@ -1233,6 +1235,10 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate return 0; } +void Audio_SetVolume(struct AudioContext* ctx, int volume) { + snd_stream_volume(ctx->hnd, volume); +} + cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) { struct AudioBuffer* buf; @@ -1274,7 +1280,6 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { } cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - snd_stream_volume(ctx->hnd, data->volume); data->sampleRate = Audio_AdjustSampleRate(data); cc_result res; @@ -1311,8 +1316,9 @@ struct AudioContext { int contextID, count; }; extern int interop_InitAudio(void); extern int interop_AudioCreate(void); extern void interop_AudioClose(int contextID); -extern int interop_AudioPlay(int contextID, const void* name, int volume, int rate); -extern int interop_AudioPoll(int contetID, int* inUse); +extern int interop_AudioPlay(int contextID, const void* name, int rate); +extern int interop_AudioPoll(int contextID, int* inUse); +extern int interop_AudioVolume(int contextID, int volume); extern int interop_AudioDescribe(int res, char* buffer, int bufferLen); cc_bool AudioBackend_Init(void) { @@ -1339,9 +1345,15 @@ void Audio_Close(struct AudioContext* ctx) { cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { return ERR_NOT_SUPPORTED; } + +void Audio_SetVolume(struct AudioContext* ctx, int volume) { + interop_AudioVolume(ctx->contextID, volume); +} + cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size) { return ERR_NOT_SUPPORTED; } + cc_result Audio_Play(struct AudioContext* ctx) { return ERR_NOT_SUPPORTED; } cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { @@ -1354,7 +1366,7 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { } cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - return interop_AudioPlay(ctx->contextID, data->data, data->volume, data->rate); + return interop_AudioPlay(ctx->contextID, data->data, data->rate); } cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { @@ -1403,6 +1415,26 @@ cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { return false; } *#########################################################################################################################*/ #ifdef AUDIO_COMMON_VOLUME +static void ApplyVolume(cc_int16* samples, int count, int volume) { + int i; + + for (i = 0; i < (count & ~0x07); i += 8, samples += 8) { + samples[0] = (samples[0] * volume / 100); + samples[1] = (samples[1] * volume / 100); + samples[2] = (samples[2] * volume / 100); + samples[3] = (samples[3] * volume / 100); + + samples[4] = (samples[4] * volume / 100); + samples[5] = (samples[5] * volume / 100); + samples[6] = (samples[6] * volume / 100); + samples[7] = (samples[7] * volume / 100); + } + + for (; i < count; i++, samples++) { + samples[0] = (samples[0] * volume / 100); + } +} + static void AudioBase_Clear(struct AudioContext* ctx) { ctx->count = 0; ctx->channels = 0; @@ -1414,7 +1446,7 @@ static void AudioBase_Clear(struct AudioContext* ctx) { static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, struct AudioData* data) { void* audio; - if (data->volume >= 100) return true; + if (ctx->volume >= 100) return true; /* copy to temp buffer to apply volume */ if (ctx->_tmpSize < data->size) { @@ -1432,7 +1464,7 @@ static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, struct AudioData* audio = ctx->_tmpData; Mem_Copy(audio, data->data, data->size); - Audio_ApplyVolume((cc_int16*)audio, data->size / 2, data->volume); + ApplyVolume((cc_int16*)audio, data->size / 2, ctx->volume); data->data = audio; return true; } @@ -1463,6 +1495,11 @@ struct AudioContext music_ctx; static struct AudioContext context_pool[POOL_MAX_CONTEXTS]; #ifndef CC_BUILD_NOSOUNDS +static cc_result PlayAudio(struct AudioContext* ctx, struct AudioData* data) { + Audio_SetVolume(ctx, data->volume); + return Audio_PlayData(ctx, data); +} + cc_result AudioPool_Play(struct AudioData* data) { struct AudioContext* ctx; int inUse, i; @@ -1477,7 +1514,7 @@ cc_result AudioPool_Play(struct AudioData* data) { if (inUse > 0) continue; if (!Audio_FastPlay(ctx, data)) continue; - return Audio_PlayData(ctx, data); + return PlayAudio(ctx, data); } /* Try again with all contexts, even if need to recreate one (expensive) */ @@ -1488,7 +1525,7 @@ cc_result AudioPool_Play(struct AudioData* data) { if (res) return res; if (inUse > 0) continue; - return Audio_PlayData(ctx, data); + return PlayAudio(ctx, data); } return 0; } diff --git a/src/interop_web.js b/src/interop_web.js index 5770b9a43..4d34ade3d 100644 --- a/src/interop_web.js +++ b/src/interop_web.js @@ -976,7 +976,7 @@ mergeInto(LibraryManager.library, { interop_AudioCreate: function() { var src = { source: null, - gain: null, + gain: AUDIO.context.createGain(), playing: false, }; AUDIO.sources.push(src); @@ -993,7 +993,11 @@ mergeInto(LibraryManager.library, { HEAP32[inUse >> 2] = src.playing; // only 1 buffer return 0; }, - interop_AudioPlay: function(ctxID, sndID, volume, rate) { + interop_AudioVolume: function(ctxID, volume) { + var src = AUDIO.sources[ctxID - 1|0]; + src.gain.gain.value = volume / 100; + }, + interop_AudioPlay: function(ctxID, sndID, rate) { var src = AUDIO.sources[ctxID - 1|0]; var name = UTF8ToString(sndID); @@ -1009,15 +1013,12 @@ mergeInto(LibraryManager.library, { if (!buffer) return 0; try { - if (!src.gain) src.gain = AUDIO.context.createGain(); - // AudioBufferSourceNode only allows the buffer property // to be assigned *ONCE* (throws InvalidStateError next time) // MDN says that these nodes are very inexpensive to create though // https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode src.source = AUDIO.context.createBufferSource(); src.source.buffer = buffer; - src.gain.gain.value = volume / 100; src.source.playbackRate.value = rate / 100; // source -> gain -> output @@ -1444,4 +1445,4 @@ mergeInto(LibraryManager.library, { CCFS.ensureErrnoError(); }, -}); \ No newline at end of file +}); From b2fdf80be1613eac0e406d76f8deafc492734d62 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 25 Mar 2024 20:33:25 +1100 Subject: [PATCH 2/5] Try to simplify audio backend code a bit --- src/Audio.c | 2 +- src/Audio.h | 4 +- src/AudioBackend.c | 155 ++++++++++++++++++--------------------------- 3 files changed, 64 insertions(+), 97 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index 08b3b039d..a982db7dd 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -351,7 +351,7 @@ static cc_result Music_PlayOgg(struct Stream* source) { channels = vorbis.channels; sampleRate = vorbis.sampleRate; - if ((res = Audio_SetFormat(&music_ctx, channels, sampleRate))) goto cleanup; + if ((res = Audio_SetFormat(&music_ctx, channels, sampleRate, 100))) goto cleanup; /* largest possible vorbis frame decodes to blocksize1 * channels samples, */ /* so can end up decoding slightly over a second of audio */ diff --git a/src/Audio.h b/src/Audio.h index 1ec2a4ab3..aa4fcc308 100644 --- a/src/Audio.h +++ b/src/Audio.h @@ -51,7 +51,7 @@ cc_result Audio_Init(struct AudioContext* ctx, int buffers); void Audio_Close(struct AudioContext* ctx); /* Sets the format of the audio data to be played. */ /* NOTE: Changing the format can be expensive, depending on the backend. */ -cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate); +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate); /* Sets the volume audio data is played at */ void Audio_SetVolume(struct AudioContext* ctx, int volume); /* Queues the given audio chunk for playing. */ @@ -66,8 +66,6 @@ cc_result Audio_Play(struct AudioContext* ctx); cc_result Audio_Poll(struct AudioContext* ctx, int* inUse); cc_result Audio_Pause(struct AudioContext* ctx); /* Only implemented with OpenSL ES backend */ -/* 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. */ diff --git a/src/AudioBackend.c b/src/AudioBackend.c index dc0e2107a..09c1768dd 100644 --- a/src/AudioBackend.c +++ b/src/AudioBackend.c @@ -12,12 +12,12 @@ void Audio_Warn(cc_result res, const char* action) { /* Common/Base methods */ static void AudioBase_Clear(struct AudioContext* ctx); -static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, struct AudioData* data); +static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, void* data, cc_uint32 size); static void AudioBase_AllocChunks(int size, void** chunks, int numChunks); static void AudioBase_FreeChunks(void** chunks, int numChunks); /* achieve higher speed by playing samples at higher sample rate */ -#define Audio_AdjustSampleRate(data) ((data->sampleRate * data->rate) / 100) +#define Audio_AdjustSampleRate(sampleRate, playbackRate) ((sampleRate * playbackRate) / 100) #if defined CC_BUILD_OPENAL /*########################################################################################################################* @@ -205,8 +205,8 @@ void Audio_Close(struct AudioContext* ctx) { ctx->count = 0; } -cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { - ctx->sampleRate = sampleRate; +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { + ctx->sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); if (channels == 1) { ctx->format = AL_FORMAT_MONO16; @@ -269,16 +269,6 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return true; } -cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - cc_result res; - data->sampleRate = Audio_AdjustSampleRate(data); - - if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate))) return res; - if ((res = Audio_QueueChunk(ctx, data->data, data->size))) return res; - if ((res = Audio_Play(ctx))) return res; - return 0; -} - static const char* GetError(cc_result res) { switch (res) { case AL_ERR_INIT_CONTEXT: return "Failed to init OpenAL context"; @@ -408,11 +398,12 @@ void Audio_Close(struct AudioContext* ctx) { AudioBase_Clear(ctx); } -cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { WAVEFORMATEX fmt; cc_result res; int sampleSize; + sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); if (ctx->channels == channels && ctx->sampleRate == sampleRate) return 0; ctx->channels = channels; ctx->sampleRate = sampleRate; @@ -443,13 +434,16 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 data WAVEHDR* hdr; int i; + cc_bool ok = AudioBase_AdjustSound(ctx, chunk, dataSize); + if (!ok) return ERR_OUT_OF_MEMORY; + for (i = 0; i < ctx->count; i++) { hdr = &ctx->headers[i]; if (!(hdr->dwFlags & WHDR_DONE)) continue; Mem_Set(hdr, 0, sizeof(WAVEHDR)); - hdr->lpData = (LPSTR)chunk; - hdr->dwBufferLength = dataSize; + hdr->lpData = (LPSTR)ctx->_tmpData; + hdr->dwBufferLength = ctx->_tmpSize; hdr->dwLoops = 1; if ((res = waveOutPrepareHeader(ctx->handle, hdr, sizeof(WAVEHDR)))) return res; @@ -483,21 +477,10 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { int channels = data->channels; - int sampleRate = Audio_AdjustSampleRate(data); + int sampleRate = Audio_AdjustSampleRate(data->sampleRate, data->rate); return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate); } -cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - cc_bool ok = AudioBase_AdjustSound(ctx, data); - cc_result res; - if (!ok) return ERR_OUT_OF_MEMORY; - data->sampleRate = Audio_AdjustSampleRate(data); - - if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate))) return res; - if ((res = Audio_QueueChunk(ctx, data->data, data->size))) return res; - return 0; -} - cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { char buffer[NATIVE_STR_LEN] = { 0 }; waveOutGetErrorTextA(res, buffer, NATIVE_STR_LEN); @@ -634,7 +617,7 @@ void Audio_Close(struct AudioContext* ctx) { ctx->sampleRate = 0; } -cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { SLDataLocator_AndroidSimpleBufferQueue input; SLDataLocator_OutputMix output; SLObjectItf playerObject; @@ -645,6 +628,9 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate SLDataSink dst; cc_result res; + /* rate is in milli, so 1000 = normal rate */ + if ((res = (*ctx->playerRate)->SetRate(ctx->playerRate, playbackRate * 10))) return res; + if (ctx->channels == channels && ctx->sampleRate == sampleRate) return 0; ctx->channels = channels; ctx->sampleRate = sampleRate; @@ -721,18 +707,6 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return !ctx->channels || (ctx->channels == data->channels && ctx->sampleRate == data->sampleRate); } -cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - cc_result res; - - if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate))) return res; - /* rate is in milli, so 1000 = normal rate */ - if ((res = (*ctx->playerRate)->SetRate(ctx->playerRate, data->rate * 10))) return res; - - if ((res = Audio_QueueChunk(ctx, data->data, data->size))) return res; - if ((res = Audio_Play(ctx))) return res; - return 0; -} - static const char* GetError(cc_result res) { switch (res) { case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; @@ -820,10 +794,11 @@ void Audio_Close(struct AudioContext* ctx) { ctx->count = 0; } -cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { ctx->stereo = (channels == 2); int fmt = ctx->stereo ? NDSP_FORMAT_STEREO_PCM16 : NDSP_FORMAT_MONO_PCM16; - + + sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); ndspChnSetFormat(ctx->chanID, fmt); ndspChnSetRate(ctx->chanID, sampleRate); return 0; @@ -890,15 +865,6 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return true; } -cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - data->sampleRate = Audio_AdjustSampleRate(data); - cc_result res; - - if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate))) return res; - if ((res = Audio_QueueChunk(ctx, data->data, data->size))) return res; - return 0; -} - cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { return false; } @@ -1008,7 +974,8 @@ void Audio_Close(struct AudioContext* ctx) { ctx->count = 0; } -cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { + sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); ctx->channels = channels; ctx->sampleRate = sampleRate; @@ -1020,8 +987,7 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate // mono audrvVoiceSetMixFactor(&drv, ctx->chanID, 1.0f, 0, 0); audrvVoiceSetMixFactor(&drv, ctx->chanID, 1.0f, 0, 1); - } - else { + } else { // stereo audrvVoiceSetMixFactor(&drv, ctx->chanID, 1.0f, 0, 0); audrvVoiceSetMixFactor(&drv, ctx->chanID, 0.0f, 0, 1); @@ -1099,17 +1065,6 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return true; } -cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - data->sampleRate = Audio_AdjustSampleRate(data); - cc_result res; - - if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate))) return res; - if ((res = Audio_QueueChunk(ctx, data->data, data->size))) return res; - - if ((res = Audio_Play(ctx))) return res; - return 0; -} - cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { return false; } @@ -1229,7 +1184,8 @@ void Audio_Close(struct AudioContext* ctx) { ctx->count = 0; } -cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { + sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); ctx->channels = channels; ctx->sampleRate = sampleRate; return 0; @@ -1279,16 +1235,6 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return true; } -cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - data->sampleRate = Audio_AdjustSampleRate(data); - cc_result res; - - if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate))) return res; - if ((res = Audio_QueueChunk(ctx, data->data, data->size))) return res; - if ((res = Audio_Play(ctx))) return res; - return 0; -} - cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { return false; } @@ -1310,7 +1256,7 @@ void Audio_FreeChunks(void** chunks, int numChunks) { /*########################################################################################################################* *-----------------------------------------------------WebAudio backend----------------------------------------------------* *#########################################################################################################################*/ -struct AudioContext { int contextID, count; }; +struct AudioContext { int contextID, count, rate; void* data; }; #define AUDIO_COMMON_ALLOC extern int interop_InitAudio(void); @@ -1333,6 +1279,8 @@ void AudioBackend_Free(void) { } cc_result Audio_Init(struct AudioContext* ctx, int buffers) { ctx->count = buffers; ctx->contextID = interop_AudioCreate(); + ctx->data = NULL; + ctx->rate = 100; return 0; } @@ -1342,8 +1290,8 @@ void Audio_Close(struct AudioContext* ctx) { ctx->count = 0; } -cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { - return ERR_NOT_SUPPORTED; +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { + ctx->rate = playbackRate; return 0; } void Audio_SetVolume(struct AudioContext* ctx, int volume) { @@ -1351,10 +1299,12 @@ void Audio_SetVolume(struct AudioContext* ctx, int volume) { } cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size) { - return ERR_NOT_SUPPORTED; + ctx->data = chunk; return 0; } -cc_result Audio_Play(struct AudioContext* ctx) { return ERR_NOT_SUPPORTED; } +cc_result Audio_Play(struct AudioContext* ctx) { + return interop_AudioPlay(ctx->contextID, ctx->data, ctx->rate); +} cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { return interop_AudioPoll(ctx->contextID, inUse); @@ -1365,10 +1315,6 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return true; } -cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { - return interop_AudioPlay(ctx->contextID, data->data, data->rate); -} - cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { char buffer[NATIVE_STR_LEN]; int len = interop_AudioDescribe(res, buffer, NATIVE_STR_LEN); @@ -1400,12 +1346,26 @@ cc_result Audio_Init(struct AudioContext* ctx, int buffers) { void Audio_Close(struct AudioContext* ctx) { } -cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return true; } - -cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) { +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { return ERR_NOT_SUPPORTED; } +void Audio_SetVolume(struct AudioContext* ctx, int volume) { } + +cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size) { + return ERR_NOT_SUPPORTED; +} + +cc_result Audio_Play(struct AudioContext* ctx) { + return ERR_NOT_SUPPORTED; +} + +cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { + return ERR_NOT_SUPPORTED; +} + +cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return false; } + cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { return false; } #endif @@ -1444,9 +1404,13 @@ static void AudioBase_Clear(struct AudioContext* ctx) { ctx->_tmpSize = 0; } -static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, struct AudioData* data) { +static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, void* data, cc_uint32 size) { void* audio; - if (ctx->volume >= 100) return true; + if (ctx->volume >= 100) { + ctx->_tmpData = data; + ctx->_tmpSize = size; + return true; + } /* copy to temp buffer to apply volume */ if (ctx->_tmpSize < data->size) { @@ -1496,8 +1460,13 @@ static struct AudioContext context_pool[POOL_MAX_CONTEXTS]; #ifndef CC_BUILD_NOSOUNDS static cc_result PlayAudio(struct AudioContext* ctx, struct AudioData* data) { + cc_result res; Audio_SetVolume(ctx, data->volume); - return Audio_PlayData(ctx, data); + + if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate, data->rate))) return res; + if ((res = Audio_QueueChunk(ctx, data->data, data->size))) return res; + if ((res = Audio_Play(ctx))) return res; + return 0; } cc_result AudioPool_Play(struct AudioData* data) { From 56177f94f5943a9cdeacaa5d3b225d8aabf7a8b7 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 25 Mar 2024 20:51:16 +1100 Subject: [PATCH 3/5] Fix non-working common audio code oops --- src/AudioBackend.c | 67 +++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/src/AudioBackend.c b/src/AudioBackend.c index 09c1768dd..8f8f0f041 100644 --- a/src/AudioBackend.c +++ b/src/AudioBackend.c @@ -12,7 +12,7 @@ void Audio_Warn(cc_result res, const char* action) { /* Common/Base methods */ static void AudioBase_Clear(struct AudioContext* ctx); -static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, void* data, cc_uint32 size); +static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, void** data, cc_uint32* size); static void AudioBase_AllocChunks(int size, void** chunks, int numChunks); static void AudioBase_FreeChunks(void** chunks, int numChunks); @@ -371,7 +371,7 @@ cc_result Audio_Init(struct AudioContext* ctx, int buffers) { ctx->headers[i].dwFlags = WHDR_DONE; } ctx->count = buffers; - ctx->volume = 100; + ctx->volume = 100; return 0; } @@ -403,7 +403,7 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate cc_result res; int sampleSize; - sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); + sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); if (ctx->channels == channels && ctx->sampleRate == sampleRate) return 0; ctx->channels = channels; ctx->sampleRate = sampleRate; @@ -434,7 +434,7 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 data WAVEHDR* hdr; int i; - cc_bool ok = AudioBase_AdjustSound(ctx, chunk, dataSize); + cc_bool ok = AudioBase_AdjustSound(ctx, &chunk, &dataSize); if (!ok) return ERR_OUT_OF_MEMORY; for (i = 0; i < ctx->count; i++) { @@ -533,7 +533,7 @@ static cc_bool LoadSLFuncs(void) { DynamicLib_Sym(slCreateEngine), DynamicLib_Sym(SL_IID_NULL), DynamicLib_Sym(SL_IID_PLAY), DynamicLib_Sym(SL_IID_ENGINE), DynamicLib_Sym(SL_IID_BUFFERQUEUE), DynamicLib_Sym(SL_IID_PLAYBACKRATE), - DynamicLib_Sym(SL_IID_VOLUME) + DynamicLib_Sym(SL_IID_VOLUME) }; void* lib; @@ -628,7 +628,7 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate SLDataSink dst; cc_result res; - /* rate is in milli, so 1000 = normal rate */ + /* rate is in milli, so 1000 = normal rate */ if ((res = (*ctx->playerRate)->SetRate(ctx->playerRate, playbackRate * 10))) return res; if (ctx->channels == channels && ctx->sampleRate == sampleRate) return 0; @@ -674,10 +674,10 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate static float Log10(float volume) { return Math_Log(volume) / Math_Log(10); } void Audio_SetVolume(struct AudioContext* ctx, int volume) { - // log of 0 is undefined - SLmillibel attenuation = volume == 0 ? SL_MILLIBEL_MIN : (2000 * Log10(volume / 100.0f)); + // log of 0 is undefined + SLmillibel attenuation = volume == 0 ? SL_MILLIBEL_MIN : (2000 * Log10(volume / 100.0f)); - (*ctx->playerVolume)->SetVolumeLevel(ctx->playerVolume, attenuation); + (*ctx->playerVolume)->SetVolumeLevel(ctx->playerVolume, attenuation); } cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size) { @@ -975,7 +975,7 @@ void Audio_Close(struct AudioContext* ctx) { } cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { - sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); + sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); ctx->channels = channels; ctx->sampleRate = sampleRate; @@ -999,7 +999,7 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate } void Audio_SetVolume(struct AudioContext* ctx, int volume) { - audrvVoiceSetVolume(&drv, ctx->chanID, volume / 100.0f); + audrvVoiceSetVolume(&drv, ctx->chanID, volume / 100.0f); } cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) { @@ -1128,9 +1128,9 @@ cc_bool AudioBackend_Init(void) { } void AudioBackend_Tick(void) { - // TODO is this really threadsafe with music? should this be done in Audio_Poll instead? - for (int i = 0; i < SND_STREAM_MAX; i++) - snd_stream_poll(i); + // TODO is this really threadsafe with music? should this be done in Audio_Poll instead? + for (int i = 0; i < SND_STREAM_MAX; i++) + snd_stream_poll(i); } void AudioBackend_Free(void) { @@ -1153,8 +1153,8 @@ static void* AudioCallback(snd_stream_hnd_t hnd, int smp_req, int *smp_recv) { buf->samples = NULL; buf->available = true; - // special case to fix sounds looping - if (samples == 0 && ptr == NULL) *smp_recv = smp_req; + // special case to fix sounds looping + if (samples == 0 && ptr == NULL) *smp_recv = smp_req; } return ptr; } @@ -1185,7 +1185,7 @@ void Audio_Close(struct AudioContext* ctx) { } cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { - sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); + sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); ctx->channels = channels; ctx->sampleRate = sampleRate; return 0; @@ -1279,8 +1279,8 @@ void AudioBackend_Free(void) { } cc_result Audio_Init(struct AudioContext* ctx, int buffers) { ctx->count = buffers; ctx->contextID = interop_AudioCreate(); - ctx->data = NULL; - ctx->rate = 100; + ctx->data = NULL; + ctx->rate = 100; return 0; } @@ -1303,7 +1303,7 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size } cc_result Audio_Play(struct AudioContext* ctx) { - return interop_AudioPlay(ctx->contextID, ctx->data, ctx->rate); + return interop_AudioPlay(ctx->contextID, ctx->data, ctx->rate); } cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { @@ -1357,7 +1357,7 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size } cc_result Audio_Play(struct AudioContext* ctx) { - return ERR_NOT_SUPPORTED; + return ERR_NOT_SUPPORTED; } cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { @@ -1404,32 +1404,31 @@ static void AudioBase_Clear(struct AudioContext* ctx) { ctx->_tmpSize = 0; } -static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, void* data, cc_uint32 size) { +static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, void** data, cc_uint32* size) { void* audio; - if (ctx->volume >= 100) { - ctx->_tmpData = data; - ctx->_tmpSize = size; - return true; - } + cc_uint32 src_size = *size; + if (ctx->volume >= 100) return true; /* copy to temp buffer to apply volume */ - if (ctx->_tmpSize < data->size) { + if (ctx->_tmpSize < src_size) { /* TODO: check if we can realloc NULL without a problem */ if (ctx->_tmpData) { - audio = Mem_TryRealloc(ctx->_tmpData, data->size, 1); + audio = Mem_TryRealloc(ctx->_tmpData, src_size, 1); } else { - audio = Mem_TryAlloc(data->size, 1); + audio = Mem_TryAlloc(src_size, 1); } if (!data) return false; ctx->_tmpData = audio; - ctx->_tmpSize = data->size; + ctx->_tmpSize = src_size; } audio = ctx->_tmpData; - Mem_Copy(audio, data->data, data->size); - ApplyVolume((cc_int16*)audio, data->size / 2, ctx->volume); - data->data = audio; + Mem_Copy(audio, *data, src_size); + ApplyVolume((cc_int16*)audio, src_size / 2, ctx->volume); + + *data = audio; + *size = src_size; return true; } #endif From 17f0e51a07bb545e056cfb576dc50f44d2136b4a Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 26 Mar 2024 07:38:32 +1100 Subject: [PATCH 4/5] Fix windowws audio backend --- src/Audio.h | 3 --- src/AudioBackend.c | 28 ++++++++++++++-------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/Audio.h b/src/Audio.h index aa4fcc308..698848a0f 100644 --- a/src/Audio.h +++ b/src/Audio.h @@ -66,11 +66,8 @@ cc_result Audio_Play(struct AudioContext* ctx); cc_result Audio_Poll(struct AudioContext* ctx, int* inUse); cc_result Audio_Pause(struct AudioContext* ctx); /* Only implemented with OpenSL ES backend */ -/* 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); - /* Allocates a group of chunks of data to store audio samples */ void Audio_AllocChunks(cc_uint32 size, void** chunks, int numChunks); /* Frees a previously allocated group of chunks of data */ diff --git a/src/AudioBackend.c b/src/AudioBackend.c index 8f8f0f041..fefa6c355 100644 --- a/src/AudioBackend.c +++ b/src/AudioBackend.c @@ -10,6 +10,9 @@ void Audio_Warn(cc_result res, const char* action) { Logger_Warn(res, action, Audio_DescribeError); } +/* Whether the given audio data can be played without recreating the underlying audio device */ +static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data); + /* Common/Base methods */ static void AudioBase_Clear(struct AudioContext* ctx); static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, void** data, cc_uint32* size); @@ -264,7 +267,7 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { *inUse = ctx->count - ctx->free; return 0; } -cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { +static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { /* Channels/Sample rate is per buffer, not a per source property */ return true; } @@ -430,7 +433,7 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate void Audio_SetVolume(struct AudioContext* ctx, int volume) { ctx->volume = volume; } cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) { - cc_result res = 0; + cc_result res; WAVEHDR* hdr; int i; @@ -442,8 +445,8 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 data if (!(hdr->dwFlags & WHDR_DONE)) continue; Mem_Set(hdr, 0, sizeof(WAVEHDR)); - hdr->lpData = (LPSTR)ctx->_tmpData; - hdr->dwBufferLength = ctx->_tmpSize; + hdr->lpData = (LPSTR)chunk; + hdr->dwBufferLength = dataSize; hdr->dwLoops = 1; if ((res = waveOutPrepareHeader(ctx->handle, hdr, sizeof(WAVEHDR)))) return res; @@ -475,7 +478,7 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { } -cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { +static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { int channels = data->channels; int sampleRate = Audio_AdjustSampleRate(data->sampleRate, data->rate); return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate); @@ -703,7 +706,7 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { return res; } -cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { +static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return !ctx->channels || (ctx->channels == data->channels && ctx->sampleRate == data->sampleRate); } @@ -826,13 +829,11 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 data for (int i = 0; i < ctx->count; i++) { buf = &ctx->bufs[i]; - //Platform_Log2("QUEUE_CHUNK: %i = %i", &ctx->chanID, &buf->status); if (buf->status == NDSP_WBUF_QUEUED || buf->status == NDSP_WBUF_PLAYING) continue; buf->data_pcm16 = chunk; buf->nsamples = dataSize / (sizeof(cc_int16) * (ctx->stereo ? 2 : 1)); - //Platform_Log1("PLAYING ON: %i", &ctx->chanID); DSP_FlushDataCache(buf->data_pcm16, dataSize); ndspChnWaveBufAdd(ctx->chanID, buf); return 0; @@ -850,7 +851,6 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { for (int i = 0; i < ctx->count; i++) { buf = &ctx->bufs[i]; - //Platform_Log2("CHECK_CHUNK: %i = %i", &ctx->chanID, &buf->status); if (buf->status == NDSP_WBUF_QUEUED || buf->status == NDSP_WBUF_PLAYING) { count++; continue; } @@ -861,7 +861,7 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { } -cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { +static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return true; } @@ -1061,7 +1061,7 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { return 0; } -cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { +static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return true; } @@ -1231,7 +1231,7 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { return 0; } -cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { +static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return true; } @@ -1310,7 +1310,7 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { return interop_AudioPoll(ctx->contextID, inUse); } -cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { +static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { /* Channels/Sample rate is per buffer, not a per source property */ return true; } @@ -1364,7 +1364,7 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { return ERR_NOT_SUPPORTED; } -cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return false; } +static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { return false; } cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { return false; } #endif From 25f6fddd2e48519614279e531e6e29b2cf3bee31 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 26 Mar 2024 19:36:55 +1100 Subject: [PATCH 5/5] Fix Android --- src/AudioBackend.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/AudioBackend.c b/src/AudioBackend.c index fefa6c355..e64a5b971 100644 --- a/src/AudioBackend.c +++ b/src/AudioBackend.c @@ -512,7 +512,8 @@ static SLEngineItf slEngineEngine; static SLObjectItf slOutputObject; struct AudioContext { - int count, channels, sampleRate; + int count, volume; + int channels, sampleRate; SLObjectItf playerObject; SLPlayItf playerPlayer; SLBufferQueueItf playerQueue; @@ -588,7 +589,8 @@ void AudioBackend_Free(void) { } cc_result Audio_Init(struct AudioContext* ctx, int buffers) { - ctx->count = buffers; + ctx->count = buffers; + ctx->volume = 100; return 0; } @@ -620,7 +622,18 @@ void Audio_Close(struct AudioContext* ctx) { ctx->sampleRate = 0; } -cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { +static float Log10(float volume) { return Math_Log(volume) / Math_Log(10); } + +static void UpdateVolume(struct AudioContext* ctx) { + /* Object doesn't exist until Audio_SetFormat is called */ + if (!ctx->playerVolume) return; + + /* log of 0 is undefined */ + SLmillibel attenuation = ctx->volume == 0 ? SL_MILLIBEL_MIN : (2000 * Log10(ctx->volume / 100.0f)); + (*ctx->playerVolume)->SetVolumeLevel(ctx->playerVolume, attenuation); +} + +static cc_result RecreatePlayer(struct AudioContext* ctx, int channels, int sampleRate) { SLDataLocator_AndroidSimpleBufferQueue input; SLDataLocator_OutputMix output; SLObjectItf playerObject; @@ -631,10 +644,6 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate SLDataSink dst; cc_result res; - /* rate is in milli, so 1000 = normal rate */ - if ((res = (*ctx->playerRate)->SetRate(ctx->playerRate, playbackRate * 10))) return res; - - if (ctx->channels == channels && ctx->sampleRate == sampleRate) return 0; ctx->channels = channels; ctx->sampleRate = sampleRate; Audio_Reset(ctx); @@ -671,16 +680,25 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate if ((res = (*playerObject)->GetInterface(playerObject, *_SL_IID_BUFFERQUEUE, &ctx->playerQueue))) return res; if ((res = (*playerObject)->GetInterface(playerObject, *_SL_IID_PLAYBACKRATE, &ctx->playerRate))) return res; if ((res = (*playerObject)->GetInterface(playerObject, *_SL_IID_VOLUME, &ctx->playerVolume))) return res; + + UpdateVolume(ctx); return 0; } -static float Log10(float volume) { return Math_Log(volume) / Math_Log(10); } +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) { + cc_result res; + + if (ctx->channels != channels || ctx->sampleRate != sampleRate) { + if ((res = RecreatePlayer(ctx, channels, sampleRate))) return res; + } + + /* rate is in milli, so 1000 = normal rate */ + return (*ctx->playerRate)->SetRate(ctx->playerRate, playbackRate * 10); +} void Audio_SetVolume(struct AudioContext* ctx, int volume) { - // log of 0 is undefined - SLmillibel attenuation = volume == 0 ? SL_MILLIBEL_MIN : (2000 * Log10(volume / 100.0f)); - - (*ctx->playerVolume)->SetVolumeLevel(ctx->playerVolume, attenuation); + ctx->volume = volume; + UpdateVolume(ctx); } cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 size) {