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 0x2fcdf1ec: // Zelda FSA - US
|
||||||
case 0x4be6a5cb: // Pikmin 1 GC - US
|
case 0x4be6a5cb: // Pikmin 1 GC - US
|
||||||
case 0x42f64ac4: // Luigi's Mansion - US
|
case 0x42f64ac4: // Luigi's Mansion - US
|
||||||
|
case 0x56d36052: // Super Mario Sunshine - US
|
||||||
return new ZeldaUCode(dsphle, crc);
|
return new ZeldaUCode(dsphle, crc);
|
||||||
|
|
||||||
case 0x2ea36ce6: // Some Wii demos
|
case 0x2ea36ce6: // Some Wii demos
|
||||||
|
|
|
@ -40,6 +40,9 @@ enum ZeldaUCodeFlag
|
||||||
// If set, interpret non-Dolby mixing parameters as step/current volume
|
// If set, interpret non-Dolby mixing parameters as step/current volume
|
||||||
// instead of target/current volume.
|
// instead of target/current volume.
|
||||||
VOLUME_EXPLICIT_STEP = 0x00000020,
|
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 = {
|
static const std::map<u32, u32> UCODE_FLAGS = {
|
||||||
|
@ -53,6 +56,8 @@ static const std::map<u32, u32> UCODE_FLAGS = {
|
||||||
{ 0x4BE6A5CB, LIGHT_PROTOCOL },
|
{ 0x4BE6A5CB, LIGHT_PROTOCOL },
|
||||||
// Luigi's Mansion.
|
// Luigi's Mansion.
|
||||||
{ 0x42F64AC4, LIGHT_PROTOCOL },
|
{ 0x42F64AC4, LIGHT_PROTOCOL },
|
||||||
|
// Super Mario Sunshine.
|
||||||
|
{ 0x56D36052, SYNC_PER_FRAME },
|
||||||
// The Legend of Zelda: The Wind Waker.
|
// The Legend of Zelda: The Wind Waker.
|
||||||
{ 0x86840740, 0 },
|
{ 0x86840740, 0 },
|
||||||
// The Legend of Zelda: Four Swords Adventures.
|
// 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_max_voice_id);
|
||||||
p.Do(m_sync_voice_skip_flags);
|
p.Do(m_sync_voice_skip_flags);
|
||||||
|
p.Do(m_sync_flags_second_half);
|
||||||
|
|
||||||
p.Do(m_cmd_buffer);
|
p.Do(m_cmd_buffer);
|
||||||
p.Do(m_read_offset);
|
p.Do(m_read_offset);
|
||||||
|
@ -214,11 +220,27 @@ void ZeldaUCode::HandleMailDefault(u32 mail)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MailState::RENDERING:
|
case MailState::RENDERING:
|
||||||
m_sync_max_voice_id = (((mail >> 16) & 0xF) + 1) << 4;
|
if (m_flags & SYNC_PER_FRAME)
|
||||||
m_sync_voice_skip_flags[(mail >> 16) & 0xFF] = mail & 0xFFFF;
|
{
|
||||||
|
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();
|
if (m_sync_flags_second_half)
|
||||||
SetMailState(MailState::WAITING);
|
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;
|
break;
|
||||||
|
|
||||||
case MailState::WRITING_CMD:
|
case MailState::WRITING_CMD:
|
||||||
|
@ -286,7 +308,7 @@ void ZeldaUCode::HandleMailLight(u32 mail)
|
||||||
|
|
||||||
// No per-voice syncing in the light protocol.
|
// No per-voice syncing in the light protocol.
|
||||||
m_sync_max_voice_id = 0xFFFFFFFF;
|
m_sync_max_voice_id = 0xFFFFFFFF;
|
||||||
m_sync_voice_skip_flags.fill(0xFFFFFFFF);
|
m_sync_voice_skip_flags.fill(0xFFFF);
|
||||||
RenderAudio();
|
RenderAudio();
|
||||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -236,7 +236,8 @@ private:
|
||||||
// these sync mails contain 16 bit values that are used as bitfields to
|
// these sync mails contain 16 bit values that are used as bitfields to
|
||||||
// control voice skipping on a voice per voice level.
|
// control voice skipping on a voice per voice level.
|
||||||
u32 m_sync_max_voice_id = 0;
|
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
|
// Command buffer (circular queue with r/w indices). Filled by HandleMail
|
||||||
// when the state machine is in WRITING_CMD state. Commands get executed
|
// when the state machine is in WRITING_CMD state. Commands get executed
|
||||||
|
|
Loading…
Reference in New Issue