States: Prevent lockup when loading older save states taken when SPC sample rate was set to 32khz

This commit is contained in:
Sour 2020-02-29 11:34:23 -05:00
parent bc6067707c
commit c6dfcd1900
2 changed files with 20 additions and 3 deletions

View file

@ -48,7 +48,7 @@ Spc::Spc(Console* console)
_operandB = 0;
_enabled = true;
_clockRatio = (double)(Spc::SpcSampleRate * 64) / _console->GetMasterClockRate();
UpdateClockRatio();
}
#ifndef DUMMYSPC
@ -96,7 +96,7 @@ void Spc::SetSpcState(bool enabled)
if(_enabled != enabled) {
if(enabled) {
//When re-enabling, adjust the cycle counter to prevent running extra cycles
_state.Cycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio);
UpdateClockRatio();
} else {
//Catch up SPC before disabling it
Run();
@ -105,6 +105,19 @@ void Spc::SetSpcState(bool enabled)
}
}
void Spc::UpdateClockRatio()
{
_clockRatio = (double)(Spc::SpcSampleRate * 64) / _console->GetMasterClockRate();
//If the target cycle is off by more than 10 cycles, reset the counter to match what was expected
//This can happen due to overclocking (which disables the SPC for some scanlines) or if the SPC's
//internal sample rate is changed between versions (e.g 32000hz -> 32040hz)
uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio);
if(std::abs((int64_t)targetCycle - (int64_t)_state.Cycle) > 10) {
_state.Cycle = targetCycle;
}
}
void Spc::Idle()
{
IncCycleCount(-1);
@ -359,7 +372,7 @@ void Spc::ProcessEndFrame()
{
Run();
_clockRatio = (double)(Spc::SpcSampleRate * 64) / _console->GetMasterClockRate();
UpdateClockRatio();
int sampleCount = _dsp->sample_count();
if(sampleCount != 0) {
@ -446,6 +459,8 @@ void Spc::Serialize(Serializer &s)
} else {
s.StreamArray(dspState, SPC_DSP::state_size);
UpdateClockRatio();
uint8_t *in = dspState;
_dsp->copy_state(&in, [](uint8_t** input, void* output, size_t size) {
memcpy(output, *input, size);

View file

@ -280,6 +280,8 @@ private:
void EndAddr();
void ProcessCycle();
void Exec();
void UpdateClockRatio();
public:
Spc(Console* console);