SPU: Update ADSR envelope when register changes
Fixes menu sounds in Final Fantasy 7 staying audible for too long.
This commit is contained in:
parent
dcfb929de5
commit
8eb3ac69b2
|
@ -71,8 +71,11 @@ void SPU::Reset()
|
||||||
v.current_block_samples.fill(s16(0));
|
v.current_block_samples.fill(s16(0));
|
||||||
v.previous_block_last_samples.fill(s16(0));
|
v.previous_block_last_samples.fill(s16(0));
|
||||||
v.adpcm_last_samples.fill(s32(0));
|
v.adpcm_last_samples.fill(s32(0));
|
||||||
v.SetADSRPhase(ADSRPhase::Off);
|
v.adsr_envelope.Reset(0, false, false);
|
||||||
|
v.adsr_phase = ADSRPhase::Off;
|
||||||
|
v.adsr_target = 0;
|
||||||
v.has_samples = false;
|
v.has_samples = false;
|
||||||
|
v.ignore_loop_address = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_transfer_fifo.Clear();
|
m_transfer_fifo.Clear();
|
||||||
|
@ -594,21 +597,25 @@ void SPU::WriteVoiceRegister(u32 offset, u16 value)
|
||||||
|
|
||||||
case 0x08: // adsr low
|
case 0x08: // adsr low
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("SPU voice %u ADSR low <- 0x%04X", voice_index, value);
|
Log_DebugPrintf("SPU voice %u ADSR low <- 0x%04X (was 0x%04X)", voice_index, value, voice.regs.adsr.bits_low);
|
||||||
voice.regs.adsr.bits_low = value;
|
voice.regs.adsr.bits_low = value;
|
||||||
|
if (voice.IsOn())
|
||||||
|
voice.UpdateADSREnvelope();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0A: // adsr high
|
case 0x0A: // adsr high
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("SPU voice %u ADSR high <- 0x%04X", voice_index, value);
|
Log_DebugPrintf("SPU voice %u ADSR high <- 0x%04X (was 0x%04X)", voice_index, value, voice.regs.adsr.bits_low);
|
||||||
voice.regs.adsr.bits_high = value;
|
voice.regs.adsr.bits_high = value;
|
||||||
|
if (voice.IsOn())
|
||||||
|
voice.UpdateADSREnvelope();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0C: // adsr volume
|
case 0x0C: // adsr volume
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("SPU voice %u ADSR volume <- 0x%04X", voice_index, value);
|
Log_DebugPrintf("SPU voice %u ADSR volume <- 0x%04X (was 0x%04X)", voice_index, value, voice.regs.adsr_volume);
|
||||||
voice.regs.adsr_volume = value;
|
voice.regs.adsr_volume = value;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1055,7 +1062,8 @@ void SPU::Voice::KeyOn()
|
||||||
adpcm_last_samples.fill(0);
|
adpcm_last_samples.fill(0);
|
||||||
has_samples = false;
|
has_samples = false;
|
||||||
ignore_loop_address = false;
|
ignore_loop_address = false;
|
||||||
SetADSRPhase(ADSRPhase::Attack);
|
adsr_phase = ADSRPhase::Attack;
|
||||||
|
UpdateADSREnvelope();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPU::Voice::KeyOff()
|
void SPU::Voice::KeyOff()
|
||||||
|
@ -1063,7 +1071,8 @@ void SPU::Voice::KeyOff()
|
||||||
if (adsr_phase == ADSRPhase::Off || adsr_phase == ADSRPhase::Release)
|
if (adsr_phase == ADSRPhase::Off || adsr_phase == ADSRPhase::Release)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SetADSRPhase(ADSRPhase::Release);
|
adsr_phase = ADSRPhase::Release;
|
||||||
|
UpdateADSREnvelope();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPU::Voice::ForceOff()
|
void SPU::Voice::ForceOff()
|
||||||
|
@ -1072,7 +1081,7 @@ void SPU::Voice::ForceOff()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
regs.adsr_volume = 0;
|
regs.adsr_volume = 0;
|
||||||
SetADSRPhase(ADSRPhase::Off);
|
adsr_phase = ADSRPhase::Off;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPU::ADSRPhase SPU::GetNextADSRPhase(ADSRPhase phase)
|
SPU::ADSRPhase SPU::GetNextADSRPhase(ADSRPhase phase)
|
||||||
|
@ -1216,10 +1225,9 @@ void SPU::VolumeSweep::Tick()
|
||||||
(envelope.decreasing ? (current_level > ENVELOPE_MIN_VOLUME) : (current_level < ENVELOPE_MAX_VOLUME));
|
(envelope.decreasing ? (current_level > ENVELOPE_MIN_VOLUME) : (current_level < ENVELOPE_MAX_VOLUME));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPU::Voice::SetADSRPhase(ADSRPhase phase)
|
void SPU::Voice::UpdateADSREnvelope()
|
||||||
{
|
{
|
||||||
adsr_phase = phase;
|
switch (adsr_phase)
|
||||||
switch (phase)
|
|
||||||
{
|
{
|
||||||
case ADSRPhase::Off:
|
case ADSRPhase::Off:
|
||||||
adsr_target = 0;
|
adsr_target = 0;
|
||||||
|
@ -1261,7 +1269,10 @@ void SPU::Voice::TickADSR()
|
||||||
const bool reached_target =
|
const bool reached_target =
|
||||||
adsr_envelope.decreasing ? (regs.adsr_volume <= adsr_target) : (regs.adsr_volume >= adsr_target);
|
adsr_envelope.decreasing ? (regs.adsr_volume <= adsr_target) : (regs.adsr_volume >= adsr_target);
|
||||||
if (reached_target)
|
if (reached_target)
|
||||||
SetADSRPhase(GetNextADSRPhase(adsr_phase));
|
{
|
||||||
|
adsr_phase = GetNextADSRPhase(adsr_phase);
|
||||||
|
UpdateADSREnvelope();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -277,7 +277,7 @@ private:
|
||||||
s32 Interpolate() const;
|
s32 Interpolate() const;
|
||||||
|
|
||||||
// Switches to the specified phase, filling in target.
|
// Switches to the specified phase, filling in target.
|
||||||
void SetADSRPhase(ADSRPhase phase);
|
void UpdateADSREnvelope();
|
||||||
|
|
||||||
// Updates the ADSR volume/phase.
|
// Updates the ADSR volume/phase.
|
||||||
void TickADSR();
|
void TickADSR();
|
||||||
|
|
Loading…
Reference in New Issue