diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index 95eb7017..1e1ae8f3 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -108,6 +108,7 @@ bool CPU::executeInstructions(int count) { moveLoadDelaySlots(); + sys->cycles++; if (sys->state != System::State::run) return false; } return true; diff --git a/src/device/spu/voice.cpp b/src/device/spu/voice.cpp index 8494e2bb..4831c745 100644 --- a/src/device/spu/voice.cpp +++ b/src/device/spu/voice.cpp @@ -90,7 +90,7 @@ void Voice::parseFlags(uint8_t flags) { repeatAddress = currentAddress; } - // Jump to Repeat address AFTER playing current sample + // Jump to Repeat address AFTER playing current sample if (flags & ADPCM::Flag::LoopEnd) { loopEnd = true; loadRepeatAddress = true; @@ -103,7 +103,7 @@ void Voice::parseFlags(uint8_t flags) { } } -void Voice::keyOn() { +void Voice::keyOn(uint64_t cycles) { decodedSamples.clear(); counter.sample = 0; adsrVolume._reg = 0; @@ -124,9 +124,18 @@ void Voice::keyOn() { prevSample[0] = prevSample[1] = 0; prevDecodedSamples.clear(); + + this->cycles = cycles; } -void Voice::keyOff() { +void Voice::keyOff(uint64_t cycles) { + // SPU seems to ignore KeyOff events that were fired close to KeyOn. + // Value of 384 cycles was picked by listening to Dragon Ball Final Bout - BGM 29 + // and comparing it to recording from real HW. + // It's not verified by any tests for now + if (cycles != 0 && cycles - this->cycles < 384) { + return; + } state = Voice::State::Release; adsrWaitCycles = 0; } diff --git a/src/device/spu/voice.h b/src/device/spu/voice.h index ca1bbe01..8e990495 100644 --- a/src/device/spu/voice.h +++ b/src/device/spu/voice.h @@ -39,7 +39,8 @@ struct Voice { float sample; // Used for Pitch Modulation - bool enabled; // Allows for muting individual channels + bool enabled; // Allows for muting individual channels + uint64_t cycles; // For dismissing KeyOff write right after KeyOn // ADPCM decoding int32_t prevSample[2]; @@ -52,8 +53,8 @@ struct Voice { void processEnvelope(); void parseFlags(uint8_t flags); - void keyOn(); - void keyOff(); + void keyOn(uint64_t cycles = 0); + void keyOff(uint64_t cycles = 0); template void serialize(Archive& ar) { @@ -72,6 +73,7 @@ struct Voice { ar(loadRepeatAddress); ar(flagsParsed); ar(sample); + ar(cycles); ar(prevSample); ar(decodedSamples); ar(prevDecodedSamples); diff --git a/src/system.cpp b/src/system.cpp index 6f142427..4a939ba3 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -34,6 +34,8 @@ System::System() { debugOutput = config["debug"]["log"]["system"].get(); biosLog = config["debug"]["log"]["bios"]; + + cycles = 0; } // Note: stupid static_casts and asserts are only to suppress MSVC warnings diff --git a/src/system.h b/src/system.h index 9dd604ac..f47a6ee6 100644 --- a/src/system.h +++ b/src/system.h @@ -64,6 +64,8 @@ struct System { bool debugOutput = true; // Print BIOS logs bool biosLoaded = false; + uint64_t cycles; + // Devices std::unique_ptr cpu;