From 1668a1ba2b84f6ca94cd0e35b95258b19e635a3b Mon Sep 17 00:00:00 2001 From: headshot2017 <> Date: Tue, 26 Mar 2024 13:54:16 -0400 Subject: [PATCH 1/4] Wii: some more fixes to audio backend/music --- src/AudioBackend.c | 89 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 17 deletions(-) diff --git a/src/AudioBackend.c b/src/AudioBackend.c index 113554f2e..29c6ccd62 100644 --- a/src/AudioBackend.c +++ b/src/AudioBackend.c @@ -1134,8 +1134,15 @@ void Audio_FreeChunks(void** chunks, int numChunks) { #include #include +struct AudioBuffer { + int available; + int size; + void* samples; +}; + struct AudioContext { - int chanID, count; + int chanID, count, bufHead; + struct AudioBuffer bufs[AUDIO_MAX_BUFFERS]; int channels, sampleRate, volume; }; @@ -1152,10 +1159,29 @@ void AudioBackend_Free(void) { ASND_End(); } +void MusicCallback(s32 voice) { + struct AudioContext* ctx = &music_ctx; + struct AudioBuffer* buf = &ctx->bufs[ctx->bufHead]; + struct AudioBuffer* nextBuf = &ctx->bufs[(ctx->bufHead + 1) % ctx->count]; + + if (ASND_AddVoice(voice, buf->samples, buf->size) == SND_OK) { + ctx->bufHead = (ctx->bufHead + 1) % ctx->count; + buf->samples = NULL; + buf->available = true; + } +} + cc_result Audio_Init(struct AudioContext* ctx, int buffers) { - ctx->chanID = -1; - ctx->count = buffers; - ctx->volume = 255; + ctx->chanID = ASND_GetFirstUnusedVoice();; + ctx->count = buffers; + ctx->volume = 255; + ctx->bufHead = 0; + + Mem_Set(ctx->bufs, 0, sizeof(ctx->bufs)); + for (int i = 0; i < buffers; i++) { + ctx->bufs[i].available = true; + } + return 0; } @@ -1169,7 +1195,7 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); ctx->channels = channels; ctx->sampleRate = sampleRate; - ctx->chanID = ASND_GetFirstUnusedVoice(); + return 0; } @@ -1182,41 +1208,70 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 data if (((uintptr_t)chunk & 0x20) != 0) { Platform_Log1("Audio_QueueData: tried to queue buffer with non-aligned audio buffer 0x%x\n", &chunk); } - if ((dataSize & 0x20) != 0) { - Platform_Log1("Audio_QueueData: unaligned audio data size 0x%x\n", &dataSize); + + struct AudioBuffer* buf; + + for (int i = 0; i < ctx->count; i++) + { + buf = &ctx->bufs[i]; + if (!buf->available) continue; + + buf->samples = chunk; + buf->size = dataSize; + buf->available = false; + + return 0; } - int format = (ctx->channels == 2) ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT; - ASND_SetVoice(ctx->chanID, format, ctx->sampleRate, 0, chunk, dataSize, ctx->volume, ctx->volume, NULL); - - return 0; - // tried to queue data without polling for free buffers first return ERR_INVALID_ARGUMENT; } cc_result Audio_Play(struct AudioContext* ctx) { + int format = (ctx->channels == 2) ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT; + ASND_SetVoice(ctx->chanID, format, ctx->sampleRate, 0, ctx->bufs[0].samples, ctx->bufs[0].size, ctx->volume, ctx->volume, (ctx->count > 1) ? MusicCallback : NULL); + return 0; } cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { - int status = ASND_StatusVoice(ctx->chanID); - *inUse = (status <= 0) ? 0 : ctx->count; + struct AudioBuffer* buf; + int count = 0; + for (int i = 0; i < ctx->count; i++) { + buf = &ctx->bufs[i]; + if (!buf->available) count++; + } + + *inUse = count; return 0; } -static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) { + +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; + + ctx->volume = data->volume/100.f*255; + + 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_bool Audio_DescribeError(cc_result res, cc_string* dst) { return false; } cc_result Audio_AllocChunks(cc_uint32 size, void** chunks, int numChunks) { - size = (size + 0x1F) & ~0x1F; // round up to nearest multiple of 0x20 - void* dst = aligned_alloc(0x20, size * numChunks); + size = (size + 0x1F) & ~0x1F; // round up to nearest multiple of 0x20 + cc_uint32 alignedSize = ((size*numChunks) + 0x1F) & ~0x1F; // round up to nearest multiple of 0x20 + void* dst = aligned_alloc(0x20, alignedSize); if (!dst) return ERR_OUT_OF_MEMORY; for (int i = 0; i < numChunks; i++) { From 38736b2a2516053f998192db61b4ddae8453c38f Mon Sep 17 00:00:00 2001 From: headshot2017 <> Date: Tue, 26 Mar 2024 14:00:24 -0400 Subject: [PATCH 2/4] Wii: remove Audio_PlayData, make buf[0] available immediately if playing a wav file --- src/AudioBackend.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/AudioBackend.c b/src/AudioBackend.c index 29c6ccd62..9c3a3af40 100644 --- a/src/AudioBackend.c +++ b/src/AudioBackend.c @@ -1230,6 +1230,7 @@ cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 data cc_result Audio_Play(struct AudioContext* ctx) { int format = (ctx->channels == 2) ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT; ASND_SetVoice(ctx->chanID, format, ctx->sampleRate, 0, ctx->bufs[0].samples, ctx->bufs[0].size, ctx->volume, ctx->volume, (ctx->count > 1) ? MusicCallback : NULL); + if (ctx->count == 1) ctx->bufs[0].available = true; return 0; } @@ -1252,18 +1253,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; - - ctx->volume = data->volume/100.f*255; - - 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_bool Audio_DescribeError(cc_result res, cc_string* dst) { return false; } From 0676d409a4459c9f39d94ea0ce15321cd42537bf Mon Sep 17 00:00:00 2001 From: headshot2017 <> Date: Tue, 26 Mar 2024 14:03:50 -0400 Subject: [PATCH 3/4] Wii: set unused voice channel in Audio_SetFormat if it's set in Audio_Init, all sounds will be on the same channel, causing cut-offs --- src/AudioBackend.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AudioBackend.c b/src/AudioBackend.c index 9c3a3af40..6d36aeb37 100644 --- a/src/AudioBackend.c +++ b/src/AudioBackend.c @@ -1172,7 +1172,7 @@ void MusicCallback(s32 voice) { } cc_result Audio_Init(struct AudioContext* ctx, int buffers) { - ctx->chanID = ASND_GetFirstUnusedVoice();; + ctx->chanID = -1; ctx->count = buffers; ctx->volume = 255; ctx->bufHead = 0; @@ -1195,6 +1195,7 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate sampleRate = Audio_AdjustSampleRate(sampleRate, playbackRate); ctx->channels = channels; ctx->sampleRate = sampleRate; + ctx->chanID = ASND_GetFirstUnusedVoice(); return 0; } From b443562b7f156be2e6920fb3e83b0d97df5f23cb Mon Sep 17 00:00:00 2001 From: headshot2017 <> Date: Fri, 29 Mar 2024 04:19:45 -0400 Subject: [PATCH 4/4] GC/Wii: fix music --- src/AudioBackend.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/AudioBackend.c b/src/AudioBackend.c index 6d36aeb37..c0e61d7a6 100644 --- a/src/AudioBackend.c +++ b/src/AudioBackend.c @@ -1144,6 +1144,7 @@ struct AudioContext { int chanID, count, bufHead; struct AudioBuffer bufs[AUDIO_MAX_BUFFERS]; int channels, sampleRate, volume; + cc_bool makeAvailable; }; cc_bool AudioBackend_Init(void) { @@ -1161,21 +1162,34 @@ void AudioBackend_Free(void) { void MusicCallback(s32 voice) { struct AudioContext* ctx = &music_ctx; - struct AudioBuffer* buf = &ctx->bufs[ctx->bufHead]; struct AudioBuffer* nextBuf = &ctx->bufs[(ctx->bufHead + 1) % ctx->count]; - if (ASND_AddVoice(voice, buf->samples, buf->size) == SND_OK) { + if (ASND_StatusVoice(voice) != SND_WORKING) return; + + if (ASND_AddVoice(voice, nextBuf->samples, nextBuf->size) == SND_OK) { ctx->bufHead = (ctx->bufHead + 1) % ctx->count; - buf->samples = NULL; - buf->available = true; + if (ctx->bufHead == 2) ctx->makeAvailable = true; + if (ctx->makeAvailable) { + int prev = ctx->bufHead - 2; + if (prev < 0) prev += 4; + ctx->bufs[prev].available = true; + } + } + + int inUse; + Audio_Poll(ctx, &inUse); + if (!inUse) { + // music has finished, stop the voice so this function isn't called anymore + ASND_StopVoice(ctx->chanID); } } cc_result Audio_Init(struct AudioContext* ctx, int buffers) { - ctx->chanID = -1; - ctx->count = buffers; - ctx->volume = 255; - ctx->bufHead = 0; + ctx->chanID = -1; + ctx->count = buffers; + ctx->volume = 255; + ctx->bufHead = 0; + ctx->makeAvailable = false; Mem_Set(ctx->bufs, 0, sizeof(ctx->bufs)); for (int i = 0; i < buffers; i++) {