From 95e86c73b8c9a0c3827f53dc3f89910bf4e939da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 5 Sep 2023 11:49:43 +0200 Subject: [PATCH] SasAudio: Some cleanup and debug overlay improvements Shows "BAD" in the overlay if address out of range. Which does happen in Afterburner, see issue #14010. --- Core/HW/SasAudio.cpp | 62 ++++++++++++++++++++++++++++---------------- Core/HW/SasAudio.h | 61 ++++++++++++++++++++++++++++--------------- UI/DebugOverlay.cpp | 4 +-- 3 files changed, 82 insertions(+), 45 deletions(-) diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index a8a2f6d56d..1186e31eee 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -125,6 +125,7 @@ void VagDecoder::GetSamples(s16 *outSamples, int numSamples) { WARN_LOG_REPORT(SASMIX, "Bad VAG samples address? %08x / %d", read_, numBlocks_); return; } + const u8 *readp = Memory::GetPointerUnchecked(read_); const u8 *origp = readp; @@ -146,6 +147,7 @@ void VagDecoder::GetSamples(s16 *outSamples, int numSamples) { return; } } + _dbg_assert_(curSample < 28); outSamples[i] = samples[curSample++]; } @@ -320,13 +322,13 @@ static int getSustainLevel(int bitfield1) { void ADSREnvelope::SetEnvelope(int flag, int a, int d, int s, int r) { if ((flag & 0x1) != 0) - attackType = a; + attackType = (SasADSRCurveMode)a; if ((flag & 0x2) != 0) - decayType = d; + decayType = (SasADSRCurveMode)d; if ((flag & 0x4) != 0) - sustainType = s; + sustainType = (SasADSRCurveMode)s; if ((flag & 0x8) != 0) - releaseType = r; + releaseType = (SasADSRCurveMode)r; if (PSP_CoreParameter().compat.flags().RockmanDash2SoundFix && sustainType == PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE) { sustainType = PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE; @@ -346,13 +348,13 @@ void ADSREnvelope::SetRate(int flag, int a, int d, int s, int r) { void ADSREnvelope::SetSimpleEnvelope(u32 ADSREnv1, u32 ADSREnv2) { attackRate = getAttackRate(ADSREnv1); - attackType = getAttackType(ADSREnv1); + attackType = (SasADSRCurveMode)getAttackType(ADSREnv1); decayRate = getDecayRate(ADSREnv1); decayType = PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE; sustainRate = getSustainRate(ADSREnv2); - sustainType = getSustainType(ADSREnv2); + sustainType = (SasADSRCurveMode)getSustainType(ADSREnv2); releaseRate = getReleaseRate(ADSREnv2); - releaseType = getReleaseType(ADSREnv2); + releaseType = (SasADSRCurveMode)getReleaseType(ADSREnv2); sustainLevel = getSustainLevel(ADSREnv1); if (PSP_CoreParameter().compat.flags().RockmanDash2SoundFix && sustainType == PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE) { @@ -371,6 +373,7 @@ SasInstance::SasInstance() { memset(&waveformEffect, 0, sizeof(waveformEffect)); waveformEffect.type = PSP_SAS_EFFECT_TYPE_OFF; waveformEffect.isDryOn = 1; + memset(mixTemp_, 0, sizeof(mixTemp_)); // just to avoid a static analysis warning. } SasInstance::~SasInstance() { @@ -383,7 +386,24 @@ void SasInstance::GetDebugText(char *text, size_t bufsize) { char *p = voiceBuf; for (int i = 0; i < maxVoices; i++) { if (voices[i].playing) { - p += snprintf(p, sizeof(voiceBuf) - (p - voiceBuf), " %d: Pitch %d L/R,FX: %d,%d|%d,%d VAG: %08x:%d:%08x Height:%d%%\n", i, voices[i].pitch, voices[i].volumeLeft, voices[i].volumeRight, voices[i].effectLeft, voices[i].effectRight, voices[i].vagAddr, voices[i].vagSize, voices[i].vag.GetReadPtr(), (int)((int64_t)voices[i].envelope.GetHeight() * 100 / PSP_SAS_ENVELOPE_HEIGHT_MAX)); + uint32_t readAddr = voices[i].GetReadAddress(); + const char *indicator = ""; + switch (voices[i].type) { + case VOICETYPE_VAG: + if (readAddr < voices[i].vagAddr || readAddr > voices[i].vagAddr + voices[i].vagSize) { + indicator = " (BAD!)"; + } + break; + } + p += snprintf(p, sizeof(voiceBuf) - (p - voiceBuf), " %d: Pitch %04x L/R,FX: %d,%d|%d,%d VAG: %08x:%d:%08x%s Height:%d%%\n", i, + voices[i].pitch, voices[i].volumeLeft, voices[i].volumeRight, voices[i].effectLeft, voices[i].effectRight, + voices[i].vagAddr, voices[i].vagSize, voices[i].GetReadAddress(), indicator, (int)((int64_t)voices[i].envelope.GetHeight() * 100 / PSP_SAS_ENVELOPE_HEIGHT_MAX)); + p += snprintf(p, sizeof(voiceBuf) - (p - voiceBuf), " - ADSR: %s/%s/%s/%s\n", + ADSRCurveModeAsString(voices[i].envelope.attackType), + ADSRCurveModeAsString(voices[i].envelope.decayType), + ADSRCurveModeAsString(voices[i].envelope.sustainType), + ADSRCurveModeAsString(voices[i].envelope.releaseType) + ); } } @@ -851,20 +871,6 @@ void SasVoice::DoState(PointerWrap &p) { atrac3.DoState(p); } -ADSREnvelope::ADSREnvelope() - : attackRate(0), - decayRate(0), - sustainRate(0), - releaseRate(0), - attackType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE), - decayType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE), - sustainType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE), - sustainLevel(0), - releaseType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE), - state_(STATE_OFF), - height_(0) { -} - void ADSREnvelope::WalkCurve(int type, int rate) { s64 expDelta; switch (type) { @@ -999,3 +1005,15 @@ void ADSREnvelope::DoState(PointerWrap &p) { } Do(p, height_); } + +const char *ADSRCurveModeAsString(SasADSRCurveMode mode) { + switch (mode) { + case PSP_SAS_ADSR_CURVE_MODE_DIRECT: return "D"; + case PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE: return "L+"; + case PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE: return "L-"; + case PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT: return "LB"; + case PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE: return "E-"; + case PSP_SAS_ADSR_CURVE_MODE_EXPONENT_INCREASE: return "E+"; + default: return "N/A"; + } +} diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index bae8b738d9..8680d223c7 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -28,36 +28,41 @@ class PointerWrap; +// General constants. enum { PSP_SAS_VOICES_MAX = 32, - + PSP_SAS_VOL_MAX = 0x1000, + PSP_SAS_MAX_GRAIN = 2048, // Matches the max value of the parameter to sceSasInit PSP_SAS_PITCH_MIN = 0x0000, PSP_SAS_PITCH_BASE = 0x1000, PSP_SAS_PITCH_MASK = 0xFFF, PSP_SAS_PITCH_BASE_SHIFT = 12, PSP_SAS_PITCH_MAX = 0x4000, + PSP_SAS_ENVELOPE_HEIGHT_MAX = 0x40000000, + PSP_SAS_ENVELOPE_FREQ_MAX = 0x7FFFFFFF, +}; - PSP_SAS_VOL_MAX = 0x1000, - PSP_SAS_MAX_GRAIN = 2048, // Matches the max value of the parameter to sceSasInit - +// The type of these are baked into savestates. +enum SasADSRCurveMode : int { PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE = 0, PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE = 1, PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT = 2, PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE = 3, PSP_SAS_ADSR_CURVE_MODE_EXPONENT_INCREASE = 4, PSP_SAS_ADSR_CURVE_MODE_DIRECT = 5, +}; +enum { PSP_SAS_ADSR_ATTACK = 1, PSP_SAS_ADSR_DECAY = 2, PSP_SAS_ADSR_SUSTAIN = 4, PSP_SAS_ADSR_RELEASE = 8, +}; - PSP_SAS_ENVELOPE_HEIGHT_MAX = 0x40000000, - PSP_SAS_ENVELOPE_FREQ_MAX = 0x7FFFFFFF, - +enum SasEffectType { PSP_SAS_EFFECT_TYPE_OFF = -1, PSP_SAS_EFFECT_TYPE_ROOM = 0, - PSP_SAS_EFFECT_TYPE_STUDIO_SMALL= 1, + PSP_SAS_EFFECT_TYPE_STUDIO_SMALL = 1, PSP_SAS_EFFECT_TYPE_STUDIO_MEDIUM = 2, PSP_SAS_EFFECT_TYPE_STUDIO_LARGE = 3, PSP_SAS_EFFECT_TYPE_HALL = 4, @@ -66,7 +71,9 @@ enum { PSP_SAS_EFFECT_TYPE_DELAY = 7, PSP_SAS_EFFECT_TYPE_PIPE = 8, PSP_SAS_EFFECT_TYPE_MAX = 8, +}; +enum SasOutputMode { PSP_SAS_OUTPUTMODE_MIXED = 0, PSP_SAS_OUTPUTMODE_RAW = 1, }; @@ -149,7 +156,6 @@ private: class ADSREnvelope { public: - ADSREnvelope(); void SetSimpleEnvelope(u32 ADSREnv1, u32 ADSREnv2); void SetEnvelope(int flag, int a, int d, int s, int r); void SetRate(int flag, int a, int d, int s, int r); @@ -177,6 +183,17 @@ public: void DoState(PointerWrap &p); + int attackRate = 0; + int decayRate = 0; + int sustainRate = 0; + int sustainLevel = 0; + int releaseRate = 0; + + SasADSRCurveMode attackType = PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE; + SasADSRCurveMode decayType = PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE; + SasADSRCurveMode sustainType = PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE; + SasADSRCurveMode releaseType = PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE; + private: // Actual PSP values. enum ADSRState { @@ -192,18 +209,8 @@ private: }; void SetState(ADSRState state); - int attackRate; - int decayRate; - int sustainRate; - int releaseRate; - int attackType; - int decayType; - int sustainType; - int sustainLevel; - int releaseType; - - ADSRState state_; - s64 height_; // s64 to avoid having to care about overflow when calculating. TODO: this should be fine as s32 + ADSRState state_ = STATE_OFF; + s64 height_ = 0; // s64 to avoid having to care about overflow when calculating. TODO: this should be fine as s32 }; // A SAS voice. @@ -243,6 +250,15 @@ struct SasVoice { void ReadSamples(s16 *output, int numSamples); bool HaveSamplesEnded() const; + // For debugging. + u32 GetReadAddress() const { + if (type == VOICETYPE_VAG) { + return vag.GetReadPtr(); + } else { + return 0; // TODO. + } + } + bool playing; bool paused; // a voice can be playing AND paused. In that case, it won't play. bool on; // key-on, key-off. @@ -273,6 +289,7 @@ struct SasVoice { ADSREnvelope envelope; + // TODO: Union these two? VagDecoder vag; SasAtrac3 atrac3; }; @@ -318,3 +335,5 @@ private: int grainSize = 0; int16_t mixTemp_[PSP_SAS_MAX_GRAIN * 4 + 2 + 8]; // some extra margin for very high pitches. }; + +const char *ADSRCurveModeAsString(SasADSRCurveMode mode); diff --git a/UI/DebugOverlay.cpp b/UI/DebugOverlay.cpp index bcf9314007..ac44ebfe1d 100644 --- a/UI/DebugOverlay.cpp +++ b/UI/DebugOverlay.cpp @@ -44,11 +44,11 @@ static void DrawAudioDebugStats(UIContext *ctx, const Bounds &bounds) { ctx->Flush(); ctx->BindFontTexture(); - ctx->Draw()->SetFontScale(0.7f, 0.7f); + ctx->Draw()->SetFontScale(0.5f, 0.5f); ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 11, bounds.y + 31, bounds.w - 20, bounds.h - 30, 0xc0000000, FLAG_DYNAMIC_ASCII); ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + 10, bounds.y + 30, bounds.w - 20, bounds.h - 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII); - float left = std::max(bounds.w / 2 - 20.0f, 550.0f); + float left = std::max(bounds.w / 2 - 20.0f, 500.0f); __SasGetDebugStats(statbuf, sizeof(statbuf)); ctx->Draw()->DrawTextRect(ubuntu24, statbuf, bounds.x + left + 21, bounds.y + 31, bounds.w - left, bounds.h - 30, 0xc0000000, FLAG_DYNAMIC_ASCII);