From addb5cb8870203e90b339c23846bf97d91c3b8a6 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 27 Dec 2014 12:15:27 +0100 Subject: [PATCH] Zelda HLE: Support the per-frame sync protocol used by SMS. Didn't test if SMS sounds right (travelling with no headphones \o/) but the waveform looks ok and the mails are flowing as expected. --- Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp | 1 + Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp | 32 +++++++++++++++++--- Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h | 3 +- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp index 0cf1d6fd5a..f52d03c495 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp @@ -60,6 +60,7 @@ UCodeInterface* UCodeFactory(u32 crc, DSPHLE* dsphle, bool wii) case 0x2fcdf1ec: // Zelda FSA - US case 0x4be6a5cb: // Pikmin 1 GC - US case 0x42f64ac4: // Luigi's Mansion - US + case 0x56d36052: // Super Mario Sunshine - US return new ZeldaUCode(dsphle, crc); case 0x2ea36ce6: // Some Wii demos diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp index 16823c8bbf..fd1d044ca1 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp @@ -40,6 +40,9 @@ enum ZeldaUCodeFlag // If set, interpret non-Dolby mixing parameters as step/current volume // instead of target/current volume. VOLUME_EXPLICIT_STEP = 0x00000020, + + // If set, handle synchronization per-frame instead of per-16-voices. + SYNC_PER_FRAME = 0x00000040, }; static const std::map UCODE_FLAGS = { @@ -53,6 +56,8 @@ static const std::map UCODE_FLAGS = { { 0x4BE6A5CB, LIGHT_PROTOCOL }, // Luigi's Mansion. { 0x42F64AC4, LIGHT_PROTOCOL }, + // Super Mario Sunshine. + { 0x56D36052, SYNC_PER_FRAME }, // The Legend of Zelda: The Wind Waker. { 0x86840740, 0 }, // The Legend of Zelda: Four Swords Adventures. @@ -122,6 +127,7 @@ void ZeldaUCode::DoState(PointerWrap &p) p.Do(m_sync_max_voice_id); p.Do(m_sync_voice_skip_flags); + p.Do(m_sync_flags_second_half); p.Do(m_cmd_buffer); p.Do(m_read_offset); @@ -214,11 +220,27 @@ void ZeldaUCode::HandleMailDefault(u32 mail) break; case MailState::RENDERING: - m_sync_max_voice_id = (((mail >> 16) & 0xF) + 1) << 4; - m_sync_voice_skip_flags[(mail >> 16) & 0xFF] = mail & 0xFFFF; + if (m_flags & SYNC_PER_FRAME) + { + int base = m_sync_flags_second_half ? 2 : 0; + m_sync_voice_skip_flags[base] = mail >> 16; + m_sync_voice_skip_flags[base + 1] = mail & 0xFFFF; - RenderAudio(); - SetMailState(MailState::WAITING); + if (m_sync_flags_second_half) + m_sync_max_voice_id = 0xFFFF; + + RenderAudio(); + if (m_sync_flags_second_half) + SetMailState(MailState::WAITING); + m_sync_flags_second_half = !m_sync_flags_second_half; + } + else + { + m_sync_max_voice_id = (((mail >> 16) & 0xF) + 1) << 4; + m_sync_voice_skip_flags[(mail >> 16) & 0xFF] = mail & 0xFFFF; + RenderAudio(); + SetMailState(MailState::WAITING); + } break; case MailState::WRITING_CMD: @@ -286,7 +308,7 @@ void ZeldaUCode::HandleMailLight(u32 mail) // No per-voice syncing in the light protocol. m_sync_max_voice_id = 0xFFFFFFFF; - m_sync_voice_skip_flags.fill(0xFFFFFFFF); + m_sync_voice_skip_flags.fill(0xFFFF); RenderAudio(); DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); break; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h index fbf2729828..8f62aaa376 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h @@ -236,7 +236,8 @@ private: // these sync mails contain 16 bit values that are used as bitfields to // control voice skipping on a voice per voice level. u32 m_sync_max_voice_id = 0; - std::array m_sync_voice_skip_flags{}; + std::array m_sync_voice_skip_flags{}; + bool m_sync_flags_second_half = false; // Command buffer (circular queue with r/w indices). Filled by HandleMail // when the state machine is in WRITING_CMD state. Commands get executed