From 91a6962565e130954a254d82e0b786a2d3d9ceeb Mon Sep 17 00:00:00 2001 From: skid Date: Mon, 1 Sep 2014 21:43:33 +1000 Subject: [PATCH] Take the size of the audio data into account when checking for the loop address. Fixes the static audio in the FMV of Megaman X Collection, Pac Man World 2, off pitched instruments in Skies of Arcadia and audio desync in the Taiko no Tatsujin series. Fixes: issue 7154 issue 7222 issue 7280 issue 7457 --- Source/Core/Core/DSP/DSPAccelerator.cpp | 17 +++++++++++------ Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h | 7 ++++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/DSP/DSPAccelerator.cpp b/Source/Core/Core/DSP/DSPAccelerator.cpp index c330d404e3..0a0e59d7a3 100644 --- a/Source/Core/Core/DSP/DSPAccelerator.cpp +++ b/Source/Core/Core/DSP/DSPAccelerator.cpp @@ -15,7 +15,7 @@ static s16 ADPCM_Step(u32& _rSamplePos) { const s16 *pCoefTable = (const s16 *)&g_dsp.ifx_regs[DSP_COEF_A1_0]; - if (((_rSamplePos) & 15) == 0) + if (((_rSamplePos)& 15) == 0) { g_dsp.ifx_regs[DSP_PRED_SCALE] = DSPHost::ReadHostMemory((_rSamplePos & ~15) >> 1); _rSamplePos += 2; @@ -63,7 +63,7 @@ u16 dsp_read_aram_d3() Address++; break; case 0x6: // u16 reads - val = (DSPHost::ReadHostMemory(Address*2) << 8) | DSPHost::ReadHostMemory(Address*2 + 1); + val = (DSPHost::ReadHostMemory(Address * 2) << 8) | DSPHost::ReadHostMemory(Address * 2 + 1); Address++; break; default: @@ -93,8 +93,8 @@ void dsp_write_aram_d3(u16 value) switch (g_dsp.ifx_regs[DSP_FORMAT]) { case 0xA: // u16 writes - DSPHost::WriteHostMemory(value >> 8, Address*2); - DSPHost::WriteHostMemory(value & 0xFF, Address*2 + 1); + DSPHost::WriteHostMemory(value >> 8, Address * 2); + DSPHost::WriteHostMemory(value & 0xFF, Address * 2 + 1); Address++; break; default: @@ -111,6 +111,7 @@ u16 dsp_read_accelerator() const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL]; u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; u16 val; + u8 step_size_bytes = 0; // let's do the "hardware" decode DSP_FORMAT is interesting - the Zelda // ucode seems to indicate that the bottom two bits specify the "read size" @@ -122,21 +123,25 @@ u16 dsp_read_accelerator() { case 0x00: // ADPCM audio val = ADPCM_Step(Address); + step_size_bytes = 2; break; case 0x0A: // 16-bit PCM audio - val = (DSPHost::ReadHostMemory(Address*2) << 8) | DSPHost::ReadHostMemory(Address*2 + 1); + val = (DSPHost::ReadHostMemory(Address * 2) << 8) | DSPHost::ReadHostMemory(Address * 2 + 1); g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; g_dsp.ifx_regs[DSP_YN1] = val; + step_size_bytes = 2; Address++; break; case 0x19: // 8-bit PCM audio val = DSPHost::ReadHostMemory(Address) << 8; g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; g_dsp.ifx_regs[DSP_YN1] = val; + step_size_bytes = 1; Address++; break; default: ERROR_LOG(DSPLLE, "dsp_read_accelerator() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); + step_size_bytes = 1; Address++; val = 0; break; @@ -151,7 +156,7 @@ u16 dsp_read_accelerator() // Somehow, YN1 and YN2 must be initialized with their "loop" values, // so yeah, it seems likely that we should raise an exception to let // the DSP program do that, at least if DSP_FORMAT == 0x0A. - if ((Address & ~1) == (EndAddress & ~1)) + if (Address == (EndAddress + step_size_bytes - 1)) { // Set address back to start address. Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL]; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h b/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h index 73f20f4e3b..f32ca75ea1 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h @@ -149,12 +149,17 @@ void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr) u16 AcceleratorGetSample() { u16 ret; + u8 step_size_bytes = 2; + + // 8-bit PCM audio uses 1 byte per sample/sample block, not 2 like other formats. + if (acc_pb->audio_addr.sample_format == 0x19) + step_size_bytes = 1; // Have we reached the end address? // // On real hardware, this would raise an interrupt that is handled by the // UCode. We simulate what this interrupt does here. - if ((*acc_cur_addr & ~1) == (acc_end_addr & ~1)) + if (*acc_cur_addr == (acc_end_addr + step_size_bytes - 1)) { // loop back to loop_addr. *acc_cur_addr = acc_loop_addr;