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.
This commit is contained in:
parent
89037781e0
commit
addb5cb887
|
@ -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
|
||||
|
|
|
@ -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<u32, u32> UCODE_FLAGS = {
|
||||
|
@ -53,6 +56,8 @@ static const std::map<u32, u32> 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;
|
||||
|
|
|
@ -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<u32, 256> m_sync_voice_skip_flags{};
|
||||
std::array<u16, 256> 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
|
||||
|
|
Loading…
Reference in New Issue