From 324f65168370d3103d99be9bd194592184b18ee9 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Fri, 20 Mar 2026 19:38:49 +0100 Subject: [PATCH] Fix block-unaligned loop decoding --- src/dusk/audio/DuskDsp.cpp | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/dusk/audio/DuskDsp.cpp b/src/dusk/audio/DuskDsp.cpp index 97c6f1c6d1..81cceddb75 100644 --- a/src/dusk/audio/DuskDsp.cpp +++ b/src/dusk/audio/DuskDsp.cpp @@ -179,7 +179,7 @@ static void ReadSampleData( * Read a single *contiguous* chunk of sample data from a channel, * writes the samples to the channel's resampler stream. * - * @returns Amount of samples actually read. + * @returns Amount of samples actually read. Can be greater than the amount requested. */ static int ReadChannelSamplesChunk( JASDsp::TChannel& channel, @@ -193,6 +193,22 @@ static int ReadChannelSamplesChunk( // Streaming logic directly modifies mSamplesLeft. // So we use that as our tracking of where we are. auto curSamplePosition = channel.mEndSample - channel.mSamplesLeft; + + u32 skipSamples = curSamplePosition % channel.mSamplesPerBlock; + if (skipSamples != 0) { + // We need to start reading in the middle of a block. This can happen thanks to loops. + // So we move back to the start of the block and keep track that those samples should + // *not* be emitted. + desiredSamples += static_cast(skipSamples); + curSamplePosition -= skipSamples; + + channel.mSamplesLeft += skipSamples; + channel.mSamplePosition -= skipSamples; + } + + // Pad desiredSamples so that we always leave the channel block-aligned. + desiredSamples = ALIGN_NEXT(desiredSamples, channel.mSamplesPerBlock); + assert(curSamplePosition % channel.mSamplesPerBlock == 0); auto dataPosition = ConvertSamplesToDataLength(channel, curSamplePosition); @@ -213,9 +229,14 @@ static int ReadChannelSamplesChunk( channel.mSamplesLeft -= renderSamples; channel.mSamplePosition += renderSamples; - SDL_PutAudioStreamData(aux.resampleStream, renderData, renderSize); + SDL_PutAudioStreamData( + aux.resampleStream, + renderData + skipSamples, + static_cast(renderSize - skipSamples * sizeof(u16))); - return static_cast(renderSamples); + assert(channel.mSamplePosition % channel.mSamplesPerBlock == 0 || channel.mSamplesLeft == 0); + + return static_cast(renderSamples - skipSamples); } /** @@ -241,8 +262,6 @@ static void SDLCALL ReadChannelSamples( return; } - additional_amount = ALIGN_NEXT(additional_amount, channel.mSamplesPerBlock); - auto samplesRead = ReadChannelSamplesChunk(channel, aux, additional_amount); additional_amount -= samplesRead; @@ -254,6 +273,9 @@ static void SDLCALL ReadChannelSamples( channel.mSamplesLeft = channel.mEndSample - channel.mLoopStartSample; channel.mSamplePosition = channel.mLoopStartSample; + + aux.hist1 = channel.mpPenult; + aux.hist0 = channel.mpLast; } if (additional_amount >= 0) {