mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-08-31 18:17:33 -04:00
Honour the loop end when reading streamed music (#7129)
Streamed samples were read a whole block at a time regardless of where the loop ended, so playback ran past it and only then jumped back. The seam therefore landed at a random offset up to a block late instead of where the sample asked for it, which is why a loop that is clean in an editor pops in game. Fixes #5780. Claude-Session: https://claude.ai/code/session_011Ex3z29fQzPEZgwH4EA641 Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -851,28 +851,43 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
|
||||
s5 = samplesLenAdjusted;
|
||||
goto skip;
|
||||
case CODEC_S16:
|
||||
case CODEC_OPUS:
|
||||
AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, (samplesLenAdjusted + 16) * 2);
|
||||
case CODEC_OPUS: {
|
||||
if (nSamplesProcessed == 0) {
|
||||
AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, (samplesLenAdjusted + 16) * 2);
|
||||
}
|
||||
flags = A_CONTINUE;
|
||||
skipBytes = 0;
|
||||
size_t bytesToRead;
|
||||
nSamplesProcessed += samplesLenAdjusted;
|
||||
s32 nSamplesToRead = nSamplesToProcess;
|
||||
|
||||
if (((synthState->samplePosInt * 2) + (samplesLenAdjusted)*2) < audioFontSample->size) {
|
||||
bytesToRead = (samplesLenAdjusted)*2;
|
||||
} else {
|
||||
bytesToRead = audioFontSample->size - (synthState->samplePosInt * 2);
|
||||
// Reading a whole block past the loop end plays back whatever the song has after
|
||||
// it and only then jumps, landing the seam at a random offset rather than the one
|
||||
// the sample asked for.
|
||||
if (nSamplesUntilLoopEnd > 0 && nSamplesToRead > nSamplesUntilLoopEnd) {
|
||||
nSamplesToRead = nSamplesUntilLoopEnd;
|
||||
}
|
||||
|
||||
size_t bytesToRead = nSamplesToRead * 2;
|
||||
size_t bytesAvailable = (synthState->samplePosInt * 2) < audioFontSample->size
|
||||
? audioFontSample->size - (synthState->samplePosInt * 2)
|
||||
: 0;
|
||||
if (bytesToRead > bytesAvailable) {
|
||||
bytesToRead = bytesAvailable;
|
||||
}
|
||||
|
||||
// 2S2H [Port] [Custom audio] Handle decoding OPUS data
|
||||
if (audioFontSample->codec == CODEC_OPUS) {
|
||||
aOPUSdecImpl(sampleAddr, DMEM_UNCOMPRESSED_NOTE, bytesToRead, &synthState->opusFile,
|
||||
aOPUSdecImpl(sampleAddr, DMEM_UNCOMPRESSED_NOTE + s5, bytesToRead, &synthState->opusFile,
|
||||
synthState->samplePosInt, audioFontSample->fileSize);
|
||||
} else {
|
||||
aLoadBuffer(cmd++, sampleAddr + (synthState->samplePosInt * 2), DMEM_UNCOMPRESSED_NOTE,
|
||||
aLoadBuffer(cmd++, sampleAddr + (synthState->samplePosInt * 2), DMEM_UNCOMPRESSED_NOTE + s5,
|
||||
bytesToRead);
|
||||
}
|
||||
|
||||
nSamplesProcessed += nSamplesToRead;
|
||||
s5 += nSamplesToRead * 2;
|
||||
|
||||
goto skip;
|
||||
}
|
||||
case CODEC_REVERB:
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user