diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index e4beebf6d8..30f3823b94 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -758,12 +758,26 @@ void ADSREnvelope::Step() { case STATE_OFF: // Do nothing break; + + case STATE_KEYON: + height_ = 0; + SetState(STATE_KEYON_STEP); + break; + case STATE_KEYON_STEP: + // This entire state is pretty much a hack to reproduce PSP behavior. + // The STATE_KEYON state is a real state, but not sure how it switches. + // It takes 32 steps at 0 for keyon to "kick in", 31 should shift to 0 anyway. + height_++; + if (height_ >= 31) { + height_ = 0; + SetState(STATE_ATTACK); + } + break; } } void ADSREnvelope::KeyOn() { - SetState(STATE_ATTACK); - height_ = 0; + SetState(STATE_KEYON); } void ADSREnvelope::KeyOff() { @@ -779,7 +793,7 @@ void ADSREnvelope::End() { } void ADSREnvelope::DoState(PointerWrap &p) { - auto s = p.Section("ADSREnvelope", 1); + auto s = p.Section("ADSREnvelope", 1, 2); if (!s) { return; } @@ -793,8 +807,15 @@ void ADSREnvelope::DoState(PointerWrap &p) { p.Do(sustainType); p.Do(sustainLevel); p.Do(releaseType); - p.Do(state_); - int stepsLegacy; - p.Do(stepsLegacy); + if (s < 2) { + p.Do(state_); + if (state_ == 4) { + state_ = STATE_OFF; + } + int stepsLegacy; + p.Do(stepsLegacy); + } else { + p.Do(state_); + } p.Do(height_); } diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index 6779693607..451d11a57f 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -144,7 +144,7 @@ public: void Step(); int GetHeight() const { - return height_ > (s64)PSP_SAS_ENVELOPE_HEIGHT_MAX ? (s64)PSP_SAS_ENVELOPE_HEIGHT_MAX : height_; + return height_ > (s64)PSP_SAS_ENVELOPE_HEIGHT_MAX ? PSP_SAS_ENVELOPE_HEIGHT_MAX : height_; } bool HasEnded() const { return state_ == STATE_OFF; @@ -162,14 +162,17 @@ public: void DoState(PointerWrap &p); private: - void ComputeDuration(); - + // Actual PSP values. enum ADSRState { - STATE_ATTACK, - STATE_DECAY, - STATE_SUSTAIN, - STATE_RELEASE, - STATE_OFF, + // Okay, this one isn't a real value but it might be. + STATE_KEYON_STEP = -42, + + STATE_KEYON = -2, + STATE_OFF = -1, + STATE_ATTACK = 0, + STATE_DECAY = 1, + STATE_SUSTAIN = 2, + STATE_RELEASE = 3, }; void SetState(ADSRState state);