mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-02-16 19:05:39 +00:00
SPU: Ignore manually set loop address only on first block
Fixes occasional missing dialogue in Valkyrie Profile.
This commit is contained in:
parent
d7bd21c06d
commit
a90c25d0e7
|
@ -2,7 +2,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
||||||
static constexpr u32 SAVE_STATE_VERSION = 46;
|
static constexpr u32 SAVE_STATE_VERSION = 47;
|
||||||
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
|
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
|
||||||
|
|
||||||
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
||||||
|
|
|
@ -91,6 +91,7 @@ void SPU::Reset()
|
||||||
std::fill_n(v.regs.index, NUM_VOICE_REGISTERS, u16(0));
|
std::fill_n(v.regs.index, NUM_VOICE_REGISTERS, u16(0));
|
||||||
v.counter.bits = 0;
|
v.counter.bits = 0;
|
||||||
v.current_block_flags.bits = 0;
|
v.current_block_flags.bits = 0;
|
||||||
|
v.is_first_block = 0;
|
||||||
v.current_block_samples.fill(s16(0));
|
v.current_block_samples.fill(s16(0));
|
||||||
v.adpcm_last_samples.fill(s32(0));
|
v.adpcm_last_samples.fill(s32(0));
|
||||||
v.adsr_envelope.Reset(0, false, false);
|
v.adsr_envelope.Reset(0, false, false);
|
||||||
|
@ -150,6 +151,7 @@ bool SPU::DoState(StateWrapper& sw)
|
||||||
sw.DoArray(v.regs.index, NUM_VOICE_REGISTERS);
|
sw.DoArray(v.regs.index, NUM_VOICE_REGISTERS);
|
||||||
sw.Do(&v.counter.bits);
|
sw.Do(&v.counter.bits);
|
||||||
sw.Do(&v.current_block_flags.bits);
|
sw.Do(&v.current_block_flags.bits);
|
||||||
|
sw.DoEx(&v.is_first_block, 47, false);
|
||||||
sw.DoArray(&v.current_block_samples[NUM_SAMPLES_FROM_LAST_ADPCM_BLOCK], NUM_SAMPLES_PER_ADPCM_BLOCK);
|
sw.DoArray(&v.current_block_samples[NUM_SAMPLES_FROM_LAST_ADPCM_BLOCK], NUM_SAMPLES_PER_ADPCM_BLOCK);
|
||||||
sw.DoArray(&v.current_block_samples[0], NUM_SAMPLES_FROM_LAST_ADPCM_BLOCK);
|
sw.DoArray(&v.current_block_samples[0], NUM_SAMPLES_FROM_LAST_ADPCM_BLOCK);
|
||||||
sw.Do(&v.adpcm_last_samples);
|
sw.Do(&v.adpcm_last_samples);
|
||||||
|
@ -586,8 +588,7 @@ void SPU::WriteVoiceRegister(u32 offset, u16 value)
|
||||||
DebugAssert(voice_index < 24);
|
DebugAssert(voice_index < 24);
|
||||||
|
|
||||||
Voice& voice = m_voices[voice_index];
|
Voice& voice = m_voices[voice_index];
|
||||||
const u32 pending_key_on = m_key_on_register;
|
if (voice.IsOn() || m_key_on_register & (1u << voice_index))
|
||||||
if (voice.IsOn() || pending_key_on & (1u << voice_index))
|
|
||||||
m_tick_event->InvokeEarly();
|
m_tick_event->InvokeEarly();
|
||||||
|
|
||||||
switch (reg_index)
|
switch (reg_index)
|
||||||
|
@ -649,11 +650,22 @@ void SPU::WriteVoiceRegister(u32 offset, u16 value)
|
||||||
|
|
||||||
case 0x0E: // repeat address
|
case 0x0E: // repeat address
|
||||||
{
|
{
|
||||||
const bool ignore_loop_address = (pending_key_on & (1u << voice_index)) == 0 && !voice.IsOn();
|
// There is a short window of time here between the voice being keyed on and the first block finishing decoding
|
||||||
Log_DebugPrintf("SPU voice %u ADPCM repeat address <- 0x%04X, ignoring block address = %s", voice_index, value,
|
// where setting the repeat address will *NOT* ignore the block/loop start flag. Games sensitive to this are:
|
||||||
ignore_loop_address ? "yes" : "no");
|
// - The Misadventures of Tron Bonne
|
||||||
|
// - Re-Loaded - The Hardcore Sequel
|
||||||
|
// - Valkyrie Profile
|
||||||
|
|
||||||
|
const bool ignore_loop_address = voice.IsOn() && !voice.is_first_block;
|
||||||
|
Log_DebugPrintf("SPU voice %u ADPCM repeat address <- 0x%04X", voice_index, value);
|
||||||
voice.regs.adpcm_repeat_address = value;
|
voice.regs.adpcm_repeat_address = value;
|
||||||
voice.ignore_loop_address |= ignore_loop_address;
|
voice.ignore_loop_address |= ignore_loop_address;
|
||||||
|
|
||||||
|
if (!ignore_loop_address)
|
||||||
|
{
|
||||||
|
Log_DevPrintf("Not ignoring loop address, the ADPCM repeat address of 0x%04X for voice %u will be overwritten",
|
||||||
|
value, voice_index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -957,6 +969,7 @@ void SPU::Voice::KeyOn()
|
||||||
static_cast<s16>(0));
|
static_cast<s16>(0));
|
||||||
|
|
||||||
has_samples = false;
|
has_samples = false;
|
||||||
|
is_first_block = true;
|
||||||
ignore_loop_address = false;
|
ignore_loop_address = false;
|
||||||
adsr_phase = ADSRPhase::Attack;
|
adsr_phase = ADSRPhase::Attack;
|
||||||
UpdateADSREnvelope();
|
UpdateADSREnvelope();
|
||||||
|
@ -1374,6 +1387,7 @@ ALWAYS_INLINE_RELEASE std::tuple<s32, s32> SPU::SampleVoice(u32 voice_index)
|
||||||
// next block
|
// next block
|
||||||
voice.counter.sample_index -= NUM_SAMPLES_PER_ADPCM_BLOCK;
|
voice.counter.sample_index -= NUM_SAMPLES_PER_ADPCM_BLOCK;
|
||||||
voice.has_samples = false;
|
voice.has_samples = false;
|
||||||
|
voice.is_first_block = false;
|
||||||
voice.current_address += 2;
|
voice.current_address += 2;
|
||||||
|
|
||||||
// handle flags
|
// handle flags
|
||||||
|
|
|
@ -244,6 +244,7 @@ private:
|
||||||
VoiceRegisters regs;
|
VoiceRegisters regs;
|
||||||
VoiceCounter counter;
|
VoiceCounter counter;
|
||||||
ADPCMFlags current_block_flags;
|
ADPCMFlags current_block_flags;
|
||||||
|
bool is_first_block;
|
||||||
std::array<s16, NUM_SAMPLES_FROM_LAST_ADPCM_BLOCK + NUM_SAMPLES_PER_ADPCM_BLOCK> current_block_samples;
|
std::array<s16, NUM_SAMPLES_FROM_LAST_ADPCM_BLOCK + NUM_SAMPLES_PER_ADPCM_BLOCK> current_block_samples;
|
||||||
std::array<s16, 2> adpcm_last_samples;
|
std::array<s16, 2> adpcm_last_samples;
|
||||||
s32 last_volume;
|
s32 last_volume;
|
||||||
|
|
Loading…
Reference in a new issue