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
This commit is contained in:
skid 2014-09-01 21:43:33 +10:00
parent ea7eee1f58
commit 91a6962565
2 changed files with 17 additions and 7 deletions

View File

@ -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];

View File

@ -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;