From 4b123a2e09444de7bf28da12b4670fa3a4d79d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Mar 2025 08:16:30 +0100 Subject: [PATCH 01/10] Move the sceSas error codes into the big enum --- Core/HLE/ErrorCodes.h | 24 ++++++++ Core/HLE/sceAtrac.cpp | 11 +++- Core/HLE/sceKernel.cpp | 24 ++++++++ Core/HLE/sceSas.cpp | 122 ++++++++++++++++------------------------- Core/HW/SasAudio.cpp | 7 ++- Core/HW/SasAudio.h | 4 +- 6 files changed, 110 insertions(+), 82 deletions(-) diff --git a/Core/HLE/ErrorCodes.h b/Core/HLE/ErrorCodes.h index a1a6f1eb83..15f240195d 100644 --- a/Core/HLE/ErrorCodes.h +++ b/Core/HLE/ErrorCodes.h @@ -467,4 +467,28 @@ enum PSPErrorCode : u32 { SCE_SSL_ERROR_ALREADY_INIT = 0x80435020, SCE_SSL_ERROR_OUT_OF_MEMORY = 0x80435022, SCE_SSL_ERROR_INVALID_PARAMETER = 0x804351FE, + + SCE_SAS_ERROR_INVALID_GRAIN = 0x80420001, + SCE_SAS_ERROR_INVALID_MAX_VOICES = 0x80420002, + SCE_SAS_ERROR_INVALID_OUTPUT_MODE = 0x80420003, + SCE_SAS_ERROR_INVALID_SAMPLE_RATE = 0x80420004, + SCE_SAS_ERROR_BAD_ADDRESS = 0x80420005, + SCE_SAS_ERROR_INVALID_VOICE = 0x80420010, + SCE_SAS_ERROR_INVALID_NOISE_FREQ = 0x80420011, + SCE_SAS_ERROR_INVALID_PITCH = 0x80420012, + SCE_SAS_ERROR_INVALID_ADSR_CURVE_MODE = 0x80420013, + SCE_SAS_ERROR_INVALID_PARAMETER = 0x80420014, + SCE_SAS_ERROR_INVALID_LOOP_POS = 0x80420015, + SCE_SAS_ERROR_VOICE_PAUSED = 0x80420016, + SCE_SAS_ERROR_INVALID_VOLUME = 0x80420018, + SCE_SAS_ERROR_INVALID_ADSR_RATE = 0x80420019, + SCE_SAS_ERROR_INVALID_PCM_SIZE = 0x8042001A, + SCE_SAS_ERROR_REV_INVALID_TYPE = 0x80420020, + SCE_SAS_ERROR_REV_INVALID_FEEDBACK = 0x80420021, + SCE_SAS_ERROR_REV_INVALID_DELAY = 0x80420022, + SCE_SAS_ERROR_REV_INVALID_VOLUME = 0x80420023, + SCE_SAS_ERROR_BUSY = 0x80420030, + SCE_SAS_ERROR_ATRAC3_ALREADY_SET = 0x80420040, + SCE_SAS_ERROR_ATRAC3_NOT_SET = 0x80420041, + SCE_SAS_ERROR_NOT_INIT = 0x80420100, }; diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index d231985edd..826d1816a3 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -1096,7 +1096,8 @@ static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesCo // This is __sceSasConcatenateATRAC3. -// The context's fileOff is incremented by the caller, but we need to bump the other pointers. +// The context's fileOff is incremented by the caller. No other pointers are bumped, except +// internally in sceSas on the real hardware. u32 AtracSasAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd) { AtracBase *atrac = getAtrac(atracID); if (!atrac) { @@ -1110,16 +1111,20 @@ void AtracSasDecodeData(int atracID, u8* outbuf, int *SamplesNum, int *finish) { if (!atrac) { WARN_LOG(Log::ME, "bad atrac ID"); } + // NOTE: If streaming, this will write 0xFFFFFFFF to secondBuffer in the context when close to running + // out of data. It'll then expect __sceSasConcatenateATRAC3 to concatenate a new buffer, which cannot + // be at the same address as the old one. I think you need to double buffer, and we in fact continouously + // read out of these. atrac->DecodeForSas((s16 *)outbuf, SamplesNum, finish); } -// Ugly hack, but needed to support both old and new contexts. int AtracSasBindContextAndGetID(u32 contextAddr) { + // Ugly hack, but needed to support both old and new contexts. int atracID = (int)Memory::Read_U32(contextAddr + 0xfc); if (atracID < PSP_MAX_ATRAC_IDS && atracContexts[atracID] && atracContexts[atracID]->GetContextVersion() == 1) { // We can assume the old atracID hack was used, and atracID is valid. } else { - // Let's just loop around the contexts and find it. + // Let's just loop around the contexts and find it by address. atracID = -1; for (int i = 0; i < PSP_MAX_ATRAC_IDS; i++) { if (!atracContexts[i]) { diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 3c300011f4..b1aedc9113 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -1467,6 +1467,30 @@ const char *KernelErrorToString(u32 err) { case SCE_SSL_ERROR_OUT_OF_MEMORY: return "SCE_SSL_ERROR_OUT_OF_MEMORY"; case SCE_SSL_ERROR_INVALID_PARAMETER: return "SCE_SSL_ERROR_INVALID_PARAMETER"; + case SCE_SAS_ERROR_INVALID_GRAIN: return "SCE_SAS_ERROR_INVALID_GRAIN"; + case SCE_SAS_ERROR_INVALID_MAX_VOICES: return "SCE_SAS_ERROR_INVALID_MAX_VOICES"; + case SCE_SAS_ERROR_INVALID_OUTPUT_MODE: return "SCE_SAS_ERROR_INVALID_OUTPUT_MODE"; + case SCE_SAS_ERROR_INVALID_SAMPLE_RATE: return "SCE_SAS_ERROR_INVALID_SAMPLE_RATE"; + case SCE_SAS_ERROR_BAD_ADDRESS: return "SCE_SAS_ERROR_BAD_ADDRESS"; + case SCE_SAS_ERROR_INVALID_VOICE: return "SCE_SAS_ERROR_INVALID_VOICE"; + case SCE_SAS_ERROR_INVALID_NOISE_FREQ: return "SCE_SAS_ERROR_INVALID_NOISE_FREQ"; + case SCE_SAS_ERROR_INVALID_PITCH: return "SCE_SAS_ERROR_INVALID_PITCH"; + case SCE_SAS_ERROR_INVALID_ADSR_CURVE_MODE: return "SCE_SAS_ERROR_INVALID_ADSR_CURVE_MODE"; + case SCE_SAS_ERROR_INVALID_PARAMETER: return "SCE_SAS_ERROR_INVALID_PARAMETER"; + case SCE_SAS_ERROR_INVALID_LOOP_POS: return "SCE_SAS_ERROR_INVALID_LOOP_POS"; + case SCE_SAS_ERROR_VOICE_PAUSED: return "SCE_SAS_ERROR_VOICE_PAUSED"; + case SCE_SAS_ERROR_INVALID_VOLUME: return "SCE_SAS_ERROR_INVALID_VOLUME"; + case SCE_SAS_ERROR_INVALID_ADSR_RATE: return "SCE_SAS_ERROR_INVALID_ADSR_RATE"; + case SCE_SAS_ERROR_INVALID_PCM_SIZE: return "SCE_SAS_ERROR_INVALID_PCM_SIZE"; + case SCE_SAS_ERROR_REV_INVALID_TYPE: return "SCE_SAS_ERROR_REV_INVALID_TYPE"; + case SCE_SAS_ERROR_REV_INVALID_FEEDBACK: return "SCE_SAS_ERROR_REV_INVALID_FEEDBACK"; + case SCE_SAS_ERROR_REV_INVALID_DELAY: return "SCE_SAS_ERROR_REV_INVALID_DELAY"; + case SCE_SAS_ERROR_REV_INVALID_VOLUME: return "SCE_SAS_ERROR_REV_INVALID_VOLUME"; + case SCE_SAS_ERROR_BUSY: return "SCE_SAS_ERROR_BUSY"; + case SCE_SAS_ERROR_ATRAC3_ALREADY_SET: return "SCE_SAS_ERROR_ATRAC3_ALREADY_SET"; + case SCE_SAS_ERROR_ATRAC3_NOT_SET: return "SCE_SAS_ERROR_ATRAC3_NOT_SET"; + case SCE_SAS_ERROR_NOT_INIT: return "SCE_SAS_ERROR_NOT_INIT"; + default: return nullptr; } diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 85710b93f2..a3b8b9af77 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -50,32 +50,6 @@ #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelThread.h" -enum { - ERROR_SAS_INVALID_GRAIN = 0x80420001, - ERROR_SAS_INVALID_MAX_VOICES = 0x80420002, - ERROR_SAS_INVALID_OUTPUT_MODE = 0x80420003, - ERROR_SAS_INVALID_SAMPLE_RATE = 0x80420004, - ERROR_SAS_BAD_ADDRESS = 0x80420005, - ERROR_SAS_INVALID_VOICE = 0x80420010, - ERROR_SAS_INVALID_NOISE_FREQ = 0x80420011, - ERROR_SAS_INVALID_PITCH = 0x80420012, - ERROR_SAS_INVALID_ADSR_CURVE_MODE = 0x80420013, - ERROR_SAS_INVALID_PARAMETER = 0x80420014, - ERROR_SAS_INVALID_LOOP_POS = 0x80420015, - ERROR_SAS_VOICE_PAUSED = 0x80420016, - ERROR_SAS_INVALID_VOLUME = 0x80420018, - ERROR_SAS_INVALID_ADSR_RATE = 0x80420019, - ERROR_SAS_INVALID_PCM_SIZE = 0x8042001A, - ERROR_SAS_REV_INVALID_TYPE = 0x80420020, - ERROR_SAS_REV_INVALID_FEEDBACK = 0x80420021, - ERROR_SAS_REV_INVALID_DELAY = 0x80420022, - ERROR_SAS_REV_INVALID_VOLUME = 0x80420023, - ERROR_SAS_BUSY = 0x80420030, - ERROR_SAS_ATRAC3_ALREADY_SET = 0x80420040, - ERROR_SAS_ATRAC3_NOT_SET = 0x80420041, - ERROR_SAS_NOT_INIT = 0x80420100, -}; - // TODO - allow more than one, associating each with one Core pointer (passed in to all the functions) // No known games use more than one instance of Sas though. static SasInstance *sas; @@ -230,23 +204,23 @@ void __SasShutdown() { static u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 outputMode, u32 sampleRate) { if (!Memory::IsValidAddress(core) || (core & 0x3F) != 0) { ERROR_LOG_REPORT(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i): bad core address", core, grainSize, maxVoices, outputMode, sampleRate); - return hleNoLog(ERROR_SAS_BAD_ADDRESS); + return hleNoLog(SCE_SAS_ERROR_BAD_ADDRESS); } if (maxVoices == 0 || maxVoices > PSP_SAS_VOICES_MAX) { ERROR_LOG_REPORT(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i): bad max voices", core, grainSize, maxVoices, outputMode, sampleRate); - return hleNoLog(ERROR_SAS_INVALID_MAX_VOICES); + return hleNoLog(SCE_SAS_ERROR_INVALID_MAX_VOICES); } if (grainSize < 0x40 || grainSize > 0x800 || (grainSize & 0x1F) != 0) { ERROR_LOG_REPORT(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i): bad grain size", core, grainSize, maxVoices, outputMode, sampleRate); - return hleNoLog(ERROR_SAS_INVALID_GRAIN); + return hleNoLog(SCE_SAS_ERROR_INVALID_GRAIN); } if (outputMode != 0 && outputMode != 1) { ERROR_LOG_REPORT(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i): bad output mode", core, grainSize, maxVoices, outputMode, sampleRate); - return hleNoLog(ERROR_SAS_INVALID_OUTPUT_MODE); + return hleNoLog(SCE_SAS_ERROR_INVALID_OUTPUT_MODE); } if (sampleRate != 44100) { ERROR_LOG_REPORT(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i): bad sample rate", core, grainSize, maxVoices, outputMode, sampleRate); - return hleNoLog(ERROR_SAS_INVALID_SAMPLE_RATE); + return hleNoLog(SCE_SAS_ERROR_INVALID_SAMPLE_RATE); } sas->SetGrainSize(grainSize); @@ -290,7 +264,7 @@ static u32 _sceSasCore(u32 core, u32 outAddr) { PROFILE_THIS_SCOPE("mixer"); if (!Memory::IsValidAddress(outAddr)) { - return hleReportError(Log::sceSas, ERROR_SAS_INVALID_PARAMETER, "invalid address"); + return hleReportError(Log::sceSas, SCE_SAS_ERROR_INVALID_PARAMETER, "invalid address"); } if (!__KernelIsDispatchEnabled()) { return hleLogError(Log::sceSas, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); @@ -306,7 +280,7 @@ static u32 _sceSasCoreWithMix(u32 core, u32 inoutAddr, int leftVolume, int right PROFILE_THIS_SCOPE("mixer"); if (!Memory::IsValidAddress(inoutAddr)) { - return hleReportError(Log::sceSas, ERROR_SAS_INVALID_PARAMETER, "invalid address"); + return hleReportError(Log::sceSas, SCE_SAS_ERROR_INVALID_PARAMETER, "invalid address"); } if (sas->outputMode == PSP_SAS_OUTPUTMODE_RAW) { return hleReportError(Log::sceSas, 0x80000004, "unsupported outputMode"); @@ -322,19 +296,19 @@ static u32 _sceSasCoreWithMix(u32 core, u32 inoutAddr, int leftVolume, int right static u32 sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loop) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogVerbose(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); + return hleLogVerbose(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voicenum"); } if (size == 0 || ((u32)size & 0xF) != 0) { if (size == 0) { - return hleLogDebug(Log::sceSas, ERROR_SAS_INVALID_PARAMETER, "invalid size %d", size); + return hleLogDebug(Log::sceSas, SCE_SAS_ERROR_INVALID_PARAMETER, "invalid size %d", size); } else { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_PARAMETER, "invalid size %d", size); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_PARAMETER, "invalid size %d", size); } } if (loop != 0 && loop != 1) { WARN_LOG_REPORT(Log::sceSas, "%s: invalid loop mode %d", __FUNCTION__, loop); - return hleNoLog(ERROR_SAS_INVALID_LOOP_POS); + return hleNoLog(SCE_SAS_ERROR_INVALID_LOOP_POS); } if (!Memory::IsValidAddress(vagAddr)) { @@ -344,7 +318,7 @@ static u32 sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loo __SasDrain(); SasVoice &v = sas->voices[voiceNum]; if (v.type == VOICETYPE_ATRAC3) { - return hleLogError(Log::sceSas, ERROR_SAS_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); + return hleLogError(Log::sceSas, SCE_SAS_ERROR_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); } if (size < 0) { @@ -373,14 +347,14 @@ static u32 sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loo static u32 sceSasSetVoicePCM(u32 core, int voiceNum, u32 pcmAddr, int size, int loopPos) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voicenum"); } if (size <= 0 || size > 0x10000) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_PCM_SIZE, "invalid size %d", size); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_PCM_SIZE, "invalid size %d", size); } if (loopPos >= size) { ERROR_LOG_REPORT(Log::sceSas, "sceSasSetVoicePCM(%08x, %i, %08x, %i, %i): bad loop pos", core, voiceNum, pcmAddr, size, loopPos); - return hleNoLog(ERROR_SAS_INVALID_LOOP_POS); + return hleNoLog(SCE_SAS_ERROR_INVALID_LOOP_POS); } if (!Memory::IsValidAddress(pcmAddr)) { return hleLogError(Log::sceSas, 0, "Ignoring invalid PCM audio address %08x", pcmAddr); @@ -389,7 +363,7 @@ static u32 sceSasSetVoicePCM(u32 core, int voiceNum, u32 pcmAddr, int size, int __SasDrain(); SasVoice &v = sas->voices[voiceNum]; if (v.type == VOICETYPE_ATRAC3) { - return hleLogError(Log::sceSas, ERROR_SAS_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); + return hleLogError(Log::sceSas, SCE_SAS_ERROR_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); } u32 prevPcmAddr = v.pcmAddr; @@ -428,12 +402,12 @@ static u32 sceSasSetPause(u32 core, u32 voicebit, int pause) { static u32 sceSasSetVolume(u32 core, int voiceNum, int leftVol, int rightVol, int effectLeftVol, int effectRightVol) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voicenum"); } bool overVolume = abs(leftVol) > PSP_SAS_VOL_MAX || abs(rightVol) > PSP_SAS_VOL_MAX; overVolume = overVolume || abs(effectLeftVol) > PSP_SAS_VOL_MAX || abs(effectRightVol) > PSP_SAS_VOL_MAX; if (overVolume) { - return hleLogError(Log::sceSas, ERROR_SAS_INVALID_VOLUME); + return hleLogError(Log::sceSas, SCE_SAS_ERROR_INVALID_VOLUME); } __SasDrain(); @@ -447,10 +421,10 @@ static u32 sceSasSetVolume(u32 core, int voiceNum, int leftVol, int rightVol, in static u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voiceNum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voiceNum"); } if (pitch < PSP_SAS_PITCH_MIN || pitch > PSP_SAS_PITCH_MAX) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_PITCH, "bad pitch"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_PITCH, "bad pitch"); } __SasDrain(); @@ -461,12 +435,12 @@ static u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) { static u32 sceSasSetKeyOn(u32 core, int voiceNum) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voiceNum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voiceNum"); } __SasDrain(); if (sas->voices[voiceNum].paused || sas->voices[voiceNum].on) { - return hleLogError(Log::sceSas, ERROR_SAS_VOICE_PAUSED); + return hleLogError(Log::sceSas, SCE_SAS_ERROR_VOICE_PAUSED); } SasVoice &v = sas->voices[voiceNum]; @@ -477,11 +451,11 @@ static u32 sceSasSetKeyOn(u32 core, int voiceNum) { // sceSasSetKeyOff can be used to start sounds, that just sound during the Release phase! static u32 sceSasSetKeyOff(u32 core, int voiceNum) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voiceNum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voiceNum"); } else { __SasDrain(); if (sas->voices[voiceNum].paused || !sas->voices[voiceNum].on) { - return hleLogDebug(Log::sceSas, ERROR_SAS_VOICE_PAUSED); // this is ok + return hleLogDebug(Log::sceSas, SCE_SAS_ERROR_VOICE_PAUSED); // this is ok } SasVoice &v = sas->voices[voiceNum]; @@ -492,10 +466,10 @@ static u32 sceSasSetKeyOff(u32 core, int voiceNum) { static u32 sceSasSetNoise(u32 core, int voiceNum, int freq) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voiceNum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voiceNum"); } if (freq < 0 || freq >= 64) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_NOISE_FREQ); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_NOISE_FREQ); } __SasDrain(); @@ -507,7 +481,7 @@ static u32 sceSasSetNoise(u32 core, int voiceNum, int freq) { static u32 sceSasSetSL(u32 core, int voiceNum, int level) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voiceNum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voiceNum"); } __SasDrain(); @@ -518,13 +492,13 @@ static u32 sceSasSetSL(u32 core, int voiceNum, int level) { static u32 sceSasSetADSR(u32 core, int voiceNum, int flag, int a, int d, int s, int r) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voiceNum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voiceNum"); } // Create a mask like flag for the invalid values. int invalid = (a < 0 ? 0x1 : 0) | (d < 0 ? 0x2 : 0) | (s < 0 ? 0x4 : 0) | (r < 0 ? 0x8 : 0); if (invalid & flag) { WARN_LOG_REPORT(Log::sceSas, "sceSasSetADSR(%08x, %i, %i, %08x, %08x, %08x, %08x): invalid value", core, voiceNum, flag, a, d, s, r); - return hleNoLog(ERROR_SAS_INVALID_ADSR_RATE); + return hleNoLog(SCE_SAS_ERROR_INVALID_ADSR_RATE); } __SasDrain(); @@ -535,7 +509,7 @@ static u32 sceSasSetADSR(u32 core, int voiceNum, int flag, int a, int d, int s, static u32 sceSasSetADSRMode(u32 core, int voiceNum, int flag, int a, int d, int s, int r) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voiceNum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voiceNum"); } // Probably by accident (?), the PSP ignores the top bit of these values. @@ -561,10 +535,10 @@ static u32 sceSasSetADSRMode(u32 core, int voiceNum, int flag, int a, int d, int if (invalid & flag) { if (a == 5 && d == 5 && s == 5 && r == 5) { // Some games do this right at init. It seems to fail even on a PSP, but let's not report it. - return hleLogDebug(Log::sceSas, ERROR_SAS_INVALID_ADSR_CURVE_MODE, "sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x): invalid modes", core, voiceNum, flag, a, d, s, r); + return hleLogDebug(Log::sceSas, SCE_SAS_ERROR_INVALID_ADSR_CURVE_MODE, "sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x): invalid modes", core, voiceNum, flag, a, d, s, r); } else { WARN_LOG_REPORT(Log::sceSas, "sceSasSetADSRMode(%08x, %i, %i, %08x, %08x, %08x, %08x): invalid modes", core, voiceNum, flag, a, d, s, r); - return hleNoLog(ERROR_SAS_INVALID_ADSR_CURVE_MODE); + return hleNoLog(SCE_SAS_ERROR_INVALID_ADSR_CURVE_MODE); } } @@ -577,11 +551,11 @@ static u32 sceSasSetADSRMode(u32 core, int voiceNum, int flag, int a, int d, int static u32 sceSasSetSimpleADSR(u32 core, int voiceNum, u32 ADSREnv1, u32 ADSREnv2) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voiceNum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voiceNum"); } // This bit could be related to decay type or systain type, but gives an error if you try to set it. if ((ADSREnv2 >> 13) & 1) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_ADSR_CURVE_MODE, "Invalid ADSREnv2"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_ADSR_CURVE_MODE, "Invalid ADSREnv2"); } __SasDrain(); @@ -592,7 +566,7 @@ static u32 sceSasSetSimpleADSR(u32 core, int voiceNum, u32 ADSREnv1, u32 ADSREnv static u32 sceSasGetEnvelopeHeight(u32 core, int voiceNum) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voiceNum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voiceNum"); } __SasDrain(); @@ -603,7 +577,7 @@ static u32 sceSasGetEnvelopeHeight(u32 core, int voiceNum) { static u32 sceSasRevType(u32 core, int type) { if (type < PSP_SAS_EFFECT_TYPE_OFF || type > PSP_SAS_EFFECT_TYPE_MAX) { - return hleLogError(Log::sceSas, ERROR_SAS_REV_INVALID_TYPE, "invalid type"); + return hleLogError(Log::sceSas, SCE_SAS_ERROR_REV_INVALID_TYPE, "invalid type"); } __SasDrain(); @@ -613,10 +587,10 @@ static u32 sceSasRevType(u32 core, int type) { static u32 sceSasRevParam(u32 core, int delay, int feedback) { if (delay < 0 || delay >= 128) { - return hleLogError(Log::sceSas, ERROR_SAS_REV_INVALID_DELAY, "invalid delay value"); + return hleLogError(Log::sceSas, SCE_SAS_ERROR_REV_INVALID_DELAY, "invalid delay value"); } if (feedback < 0 || feedback >= 128) { - return hleLogError(Log::sceSas, ERROR_SAS_REV_INVALID_FEEDBACK, "invalid feedback value"); + return hleLogError(Log::sceSas, SCE_SAS_ERROR_REV_INVALID_FEEDBACK, "invalid feedback value"); } __SasDrain(); @@ -627,7 +601,7 @@ static u32 sceSasRevParam(u32 core, int delay, int feedback) { static u32 sceSasRevEVOL(u32 core, u32 lv, u32 rv) { if (lv > 0x1000 || rv > 0x1000) { - return hleLogWarning(Log::sceSas, ERROR_SAS_REV_INVALID_VOLUME, "invalid volume"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_REV_INVALID_VOLUME, "invalid volume"); } __SasDrain(); @@ -660,7 +634,7 @@ static u32 sceSasGetOutputMode(u32 core) { static u32 sceSasSetOutputMode(u32 core, u32 outputMode) { if (outputMode != 0 && outputMode != 1) { ERROR_LOG_REPORT(Log::sceSas, "sceSasSetOutputMode(%08x, %i): bad output mode", core, outputMode); - return hleNoLog(ERROR_SAS_INVALID_OUTPUT_MODE); + return hleNoLog(SCE_SAS_ERROR_INVALID_OUTPUT_MODE); } __SasDrain(); @@ -670,7 +644,7 @@ static u32 sceSasSetOutputMode(u32 core, u32 outputMode) { static u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr) { if (!Memory::IsValidAddress(heightsAddr)) { - return hleLogError(Log::sceSas, ERROR_SAS_INVALID_PARAMETER); + return hleLogError(Log::sceSas, SCE_SAS_ERROR_INVALID_PARAMETER); } __SasDrain(); @@ -694,18 +668,18 @@ static u32 sceSasSetSteepWave(u32 sasCore, int voice, int unknown) { static u32 __sceSasSetVoiceATRAC3(u32 core, int voiceNum, u32 atrac3Context) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voicenum"); } __SasDrain(); SasVoice &v = sas->voices[voiceNum]; if (v.type == VOICETYPE_ATRAC3) { - return hleLogError(Log::sceSas, ERROR_SAS_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); + return hleLogError(Log::sceSas, SCE_SAS_ERROR_ATRAC3_ALREADY_SET, "voice is already ATRAC3"); } v.type = VOICETYPE_ATRAC3; v.loop = false; v.playing = true; - v.atrac3.setContext(atrac3Context); + v.atrac3.SetContext(atrac3Context); Memory::Write_U32(atrac3Context, core + 56 * voiceNum + 20); return hleLogDebug(Log::sceSas, 0); @@ -713,26 +687,26 @@ static u32 __sceSasSetVoiceATRAC3(u32 core, int voiceNum, u32 atrac3Context) { static u32 __sceSasConcatenateATRAC3(u32 core, int voiceNum, u32 atrac3DataAddr, int atrac3DataLength) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voicenum"); } DEBUG_LOG_REPORT_ONCE(concatAtrac3, Log::sceSas, "__sceSasConcatenateATRAC3(%08x, %i, %08x, %i)", core, voiceNum, atrac3DataAddr, atrac3DataLength); __SasDrain(); SasVoice &v = sas->voices[voiceNum]; if (Memory::IsValidAddress(atrac3DataAddr)) - v.atrac3.addStreamData(atrac3DataAddr, atrac3DataLength); + v.atrac3.Concatenate(atrac3DataAddr, atrac3DataLength); return hleNoLog(0); } static u32 __sceSasUnsetATRAC3(u32 core, int voiceNum) { if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) { - return hleLogWarning(Log::sceSas, ERROR_SAS_INVALID_VOICE, "invalid voicenum"); + return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voicenum"); } __SasDrain(); SasVoice &v = sas->voices[voiceNum]; if (v.type != VOICETYPE_ATRAC3) { - return hleLogError(Log::sceSas, ERROR_SAS_ATRAC3_NOT_SET, "voice is not ATRAC3"); + return hleLogError(Log::sceSas, SCE_SAS_ERROR_ATRAC3_NOT_SET, "voice is not ATRAC3"); } v.type = VOICETYPE_OFF; v.playing = false; diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index 99237bb70e..e36919d1c3 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -188,9 +188,10 @@ void VagDecoder::DoState(PointerWrap &p) { Do(p, end_); } -int SasAtrac3::setContext(u32 contextAddr) { +int SasAtrac3::SetContext(u32 contextAddr) { contextAddr_ = contextAddr; - // Note: This atracID_ is also stored in the loopNum member of the context. + // Note: On hardware, atracID_ is also stored in the loopNum member of the context. + // But we don't actually mirror our struct to memory, so it doesn't really matter. atracID_ = AtracSasBindContextAndGetID(contextAddr); if (!sampleQueue_) sampleQueue_ = new BufferQueue(); @@ -219,7 +220,7 @@ void SasAtrac3::getNextSamples(s16 *outbuf, int wantedSamples) { end_ = finish == 1; } -int SasAtrac3::addStreamData(u32 bufPtr, u32 addbytes) { +int SasAtrac3::Concatenate(u32 bufPtr, u32 addbytes) { if (atracID_ > 0) { AtracSasAddStreamData(atracID_, bufPtr, addbytes); } diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index 1cd2bc255c..6627c33129 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -139,10 +139,10 @@ class SasAtrac3 { public: SasAtrac3() : contextAddr_(0), atracID_(-1), sampleQueue_(0), end_(false) {} ~SasAtrac3() { delete sampleQueue_; } - int setContext(u32 context); + int SetContext(u32 context); int id() const { return atracID_; } void getNextSamples(s16 *outbuf, int wantedSamples); - int addStreamData(u32 bufPtr, u32 addbytes); + int Concatenate(u32 bufPtr, u32 addbytes); void DoState(PointerWrap &p); bool End() const { return end_; From d8f82b5875134c7ae050375b2343c8fb2b4031d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Mar 2025 16:45:43 +0100 Subject: [PATCH 02/10] Minor cleanup --- Core/WebServer.cpp | 4 ++-- Core/WebServer.h | 4 ++++ UI/NativeApp.cpp | 14 +++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Core/WebServer.cpp b/Core/WebServer.cpp index 68ea8525b4..43d415ed62 100644 --- a/Core/WebServer.cpp +++ b/Core/WebServer.cpp @@ -426,8 +426,8 @@ static void ExecuteWebServer() { RegisterServer(http->Port()); double lastRegister = time_now_d(); while (RetrieveStatus() == ServerStatus::RUNNING) { - http->RunSlice(1.0); - + constexpr double webServerSliceSeconds = 0.2f; + http->RunSlice(webServerSliceSeconds); double now = time_now_d(); if (now > lastRegister + 540.0) { RegisterServer(http->Port()); diff --git a/Core/WebServer.h b/Core/WebServer.h index e2713a6e0c..0e9f6abe34 100644 --- a/Core/WebServer.h +++ b/Core/WebServer.h @@ -17,12 +17,16 @@ #pragma once +#include "Common/Common.h" + enum class WebServerFlags { + NONE = 0, DISCS = 1, DEBUGGER = 2, ALL = 1 | 2, }; +ENUM_CLASS_BITOPS(WebServerFlags); bool StartWebServer(WebServerFlags flags); bool StopWebServer(WebServerFlags flags); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 8c0227e758..cbf73a92e2 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -749,12 +749,16 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch // Easy testing // screenManager->push(new GPUDriverTestScreen()); - if (g_Config.bRemoteShareOnStartup && g_Config.bRemoteDebuggerOnStartup) + WebServerFlags flags = (WebServerFlags)0; + if (g_Config.bRemoteShareOnStartup) { + flags |= WebServerFlags::DISCS; + } + if (g_Config.bRemoteDebuggerOnStartup) { + flags |= WebServerFlags::DEBUGGER; + } + if (flags != WebServerFlags::NONE) { StartWebServer(WebServerFlags::ALL); - else if (g_Config.bRemoteShareOnStartup) - StartWebServer(WebServerFlags::DISCS); - else if (g_Config.bRemoteDebuggerOnStartup) - StartWebServer(WebServerFlags::DEBUGGER); + } std::string sysName = System_GetProperty(SYSPROP_NAME); From 1bd5cffa1d026fd216835bf7eb5688d95af2718f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Mar 2025 16:45:50 +0100 Subject: [PATCH 03/10] Initial work on re-implementing atrac-through-sas --- Core/HLE/AtracCtx.cpp | 20 +----- Core/HLE/AtracCtx.h | 11 ++- Core/HLE/AtracCtx2.cpp | 128 +++++++++++++++++++++++++++-------- Core/HLE/AtracCtx2.h | 12 +++- Core/HLE/ErrorCodes.h | 1 + Core/HLE/sceAtrac.cpp | 4 +- Core/HLE/sceSas.cpp | 13 ++-- Core/HW/SasAudio.cpp | 14 ++-- Core/HW/SasAudio.h | 16 ++--- UI/ImDebugger/ImDebugger.cpp | 2 +- 10 files changed, 146 insertions(+), 75 deletions(-) diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp index 4339628b24..bc3eff908b 100644 --- a/Core/HLE/AtracCtx.cpp +++ b/Core/HLE/AtracCtx.cpp @@ -571,21 +571,6 @@ int Atrac::AddStreamData(u32 bytesToAdd) { return 0; } -u32 Atrac::AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) { - int addbytes = std::min(bytesToAdd, track_.fileSize - first_.fileoffset - track_.FirstOffsetExtra()); - Memory::Memcpy(dataBuf_ + first_.fileoffset + track_.FirstOffsetExtra(), bufPtr, addbytes, "AtracAddStreamData"); - first_.size += bytesToAdd; - if (first_.size >= track_.fileSize) { - first_.size = track_.fileSize; - if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) - bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; - } - first_.fileoffset += addbytes; - // refresh context_ - WriteContextToPSPMem(); - return 0; -} - u32 Atrac::GetNextSamples() { if (currentSample_ >= track_.endSample) { return 0; @@ -962,9 +947,8 @@ int Atrac::DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, i } void Atrac::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { - // Hack, but works. - int samplesNum; - DecodeData((u8 *)dstData, 0, &samplesNum, finish, nullptr); + // Disabled, can't work now that we changed the interface. + *finish = 1; } void Atrac::NotifyGetContextAddress() { diff --git a/Core/HLE/AtracCtx.h b/Core/HLE/AtracCtx.h index 5d80daa909..3696ac7dac 100644 --- a/Core/HLE/AtracCtx.h +++ b/Core/HLE/AtracCtx.h @@ -112,7 +112,6 @@ public: virtual void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) = 0; virtual int AddStreamData(u32 bytesToAdd) = 0; - virtual u32 AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) = 0; virtual int ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) = 0; virtual int GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample, bool *delay) = 0; virtual int SetData(const Track &track, u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) = 0; @@ -121,10 +120,14 @@ public: virtual int SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) = 0; virtual u32 DecodeData(u8 *outbuf, u32 outbufPtr, int *SamplesNum, int *finish, int *remains) = 0; virtual int DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) = 0; - virtual void DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) = 0; + virtual u32 GetNextSamples() = 0; virtual void InitLowLevel(const Atrac3LowLevelParams ¶ms, int codecType) = 0; + virtual void CheckForSas() = 0; + virtual int EnqueueForSas(u32 address, u32 ptr) = 0; + virtual void DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) = 0; + virtual int GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const = 0; virtual int GetContextVersion() const = 0; @@ -205,7 +208,6 @@ public: void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override; // Notify the player that the user has written some new data. int AddStreamData(u32 bytesToAdd) override; - u32 AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) override; int ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) override; int GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample, bool *delay) override; int SetData(const Track &track, u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) override; @@ -213,6 +215,9 @@ public: int SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) override; u32 DecodeData(u8 *outbuf, u32 outbufPtr, int *SamplesNum, int *finish, int *remains) override; int DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) override; + + void CheckForSas() {} + int EnqueueForSas(u32 address, u32 ptr) override { return 0; } void DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) override; // Returns how many samples the next DecodeData will write. diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index a3aeec8d36..7dbac9550b 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -175,15 +175,16 @@ Atrac2::Atrac2(u32 contextAddr, int codecType) { info.state = ATRAC_STATUS_NO_DATA; info.curBuffer = 0; - sasReadOffset_ = 0; - sasBasePtr_ = 0; + sasStreamOffset_ = 0; + sasBufferPtr_[0] = 0; + sasBufferPtr_[1] = 0; } else { // We're loading state, we'll restore the context in DoState. } } void Atrac2::DoState(PointerWrap &p) { - auto s = p.Section("Atrac2", 1, 2); + auto s = p.Section("Atrac2", 1, 3); if (!s) return; @@ -191,10 +192,17 @@ void Atrac2::DoState(PointerWrap &p) { // The only thing we need to save now is the outputChannels_ and the context pointer. And technically, not even that since // it can be computed. Still, for future proofing, let's save it. Do(p, context_); + // Actually, now we also need to save sas state. I guess this could also be saved on the Sas side, but this is easier. if (s >= 2) { - Do(p, sasReadOffset_); - Do(p, sasBasePtr_); + Do(p, sasStreamOffset_); + Do(p, sasBufferPtr_[0]); + } + // Added support for streaming sas audio, need some more context state. + if (s >= 3) { + Do(p, sasBufferPtr_[1]); + Do(p, sasBufferSize_); + Do(p, sasIsStreaming_); } const SceAtracIdInfo &info = context_->info; @@ -497,20 +505,6 @@ int Atrac2::AddStreamData(u32 bytesToAdd) { return 0; } -u32 Atrac2::AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) { - SceAtracIdInfo &info = context_->info; - // Internal API, seems like a combination of GetStreamDataInfo and AddStreamData, for use when - // an Atrac context is bound to an sceSas channel. - // Sol Trigger is the only game I know that uses this. - _dbg_assert_(false); - - u8 *dest = Memory::GetPointerWrite(sasBasePtr_ + sasReadOffset_); - memcpy(dest, Memory::GetPointer(bufPtr), bytesToAdd); - info.buffer += bytesToAdd; - info.streamDataByte += bytesToAdd; - return 0; -} - static int ComputeLoopedStreamWritableBytes(const SceAtracIdInfo &info, const int loopStartFileOffset, const u32 loopEndFileOffset) { const u32 writeOffset = info.curFileOff + info.streamDataByte; if (writeOffset >= loopEndFileOffset) { @@ -681,6 +675,10 @@ u32 Atrac2::DecodeInternal(u32 outbufAddr, int *SamplesNum, int *finish) { return SCE_ERROR_ATRAC_BUFFER_IS_EMPTY; } + if (info.state == ATRAC_STATUS_FOR_SCESAS) { + _dbg_assert_(false); + } + u32 streamOff; u32 bufferPtr; if (!AtracStatusIsStreaming(info.state)) { @@ -1039,27 +1037,97 @@ int Atrac2::DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, return 0; } +void Atrac2::CheckForSas() { + SceAtracIdInfo &info = context_->info; + if (info.numChan != 1) { + WARN_LOG(Log::ME, "Caller forgot to set channels to 1"); + } + if (info.state != 0x10) { + WARN_LOG(Log::ME, "Caller forgot to set state to 0x10"); + } + sasIsStreaming_ = info.fileDataEnd >= info.bufferByte; +} + +int Atrac2::EnqueueForSas(u32 address, u32 ptr) { + SceAtracIdInfo &info = context_->info; + // Set the new buffer up to be adopted by the next call to Decode that needs more data. + // Note: Can't call this if the decoder isn't asking for another buffer to be queued. + if (info.secondBuffer != 0xFFFFFFFF) { + return SCE_SAS_ERROR_ATRAC3_ALREADY_QUEUED; + } + + info.secondBuffer = address; + info.secondBufferByte = ptr; + return 0; +} + void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { SceAtracIdInfo &info = context_->info; - if (info.buffer) { - // Adopt it then zero it. - sasBasePtr_ = info.buffer; - sasReadOffset_ = 0; - info.buffer = 0; + // First frame handling. Not sure if accurate. Set up the initial buffer as the current streaming buffer. + // Also works for the non-streaming case. + if (sasBufferPtr_[0] == 0 && sasCurBuffer_ == 0) { + sasBufferPtr_[0] = info.buffer; + sasBufferSize_[0] = info.bufferByte - info.streamOff; + sasStreamOffset_ = 0; + sasFileOffset_ = 0; } - const u8 *srcData = Memory::GetPointer(sasBasePtr_ + sasReadOffset_); + u8 assembly[1000]; + // Keep decoding from the current buffer until it runs out. + if (sasStreamOffset_ + info.sampleSize <= sasBufferSize_[sasCurBuffer_]) { + // Just decode. + const u8 *srcData = Memory::GetPointer(sasBufferPtr_[sasCurBuffer_] + sasStreamOffset_); + int bytesConsumed = 0; + bool decodeResult = decoder_->Decode(srcData, info.sampleSize, &bytesConsumed, 1, dstData, bytesWritten); + if (!decodeResult) { + ERROR_LOG(Log::ME, "SAS failed to decode packet"); + } + sasStreamOffset_ += bytesConsumed; + sasFileOffset_ += bytesConsumed; + } else if (sasIsStreaming_) { + // TODO: Do we need special handling for the first buffer, since SetData will wrap around that packet? I think yes! + + WARN_LOG(Log::ME, "Streaming, and hit the end of buffer %d, switching over.", sasCurBuffer_); - int outSamples = 0; - int bytesConsumed = 0; - decoder_->Decode(srcData, info.sampleSize, &bytesConsumed, 1, dstData, bytesWritten); + int part1Size = sasBufferSize_[sasCurBuffer_] - sasStreamOffset_; + int part2Size = info.sampleSize - part1Size; + _dbg_assert_(part1Size >= 0); + if (part1Size >= 0) { + // Grab the partial packet, before we switch over to the other buffer. + Memory::Memcpy(assembly, sasBufferPtr_[sasCurBuffer_] + sasStreamOffset_, part1Size); + } + // Check that a new buffer actually exists + if ((int)info.secondBuffer < 0 || info.secondBuffer == sasBufferPtr_[sasCurBuffer_]) { + ERROR_LOG(Log::ME, "AtracSas streaming ran out of data, no secondbuffer pending"); + *finish = 1; + return; + } - sasReadOffset_ += bytesConsumed; + // Switch to the other buffer. + sasCurBuffer_ ^= 1; + sasBufferPtr_[sasCurBuffer_] = info.secondBuffer; + sasBufferSize_[sasCurBuffer_] = info.secondBufferByte; + sasStreamOffset_ = part2Size; + info.secondBuffer = 0xFFFFFFFF; // Signal to the caller that we accept a new next buffer. NOTE: This + + // Copy the second half (or if part1Size == 0, the whole packet) to the assembly buffer. + Memory::Memcpy(assembly + part1Size, sasBufferPtr_[sasCurBuffer_], part2Size); + // Decode the packet from the assembly, whether it's was assembled from two or one. + const u8 *srcData = assembly; + int bytesConsumed = 0; + bool decodeResult = decoder_->Decode(srcData, info.sampleSize, &bytesConsumed, 1, dstData, bytesWritten); + sasFileOffset_ += bytesConsumed; + if (!decodeResult) { + ERROR_LOG(Log::ME, "SAS failed to decode packet"); + } + } + + /* if (sasReadOffset_ + info.dataOff >= info.fileDataEnd) { *finish = 1; } else { *finish = 0; - } + }*/ } diff --git a/Core/HLE/AtracCtx2.h b/Core/HLE/AtracCtx2.h index 0e9ce26add..612c182a92 100644 --- a/Core/HLE/AtracCtx2.h +++ b/Core/HLE/AtracCtx2.h @@ -33,7 +33,6 @@ public: void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override; int GetSecondBufferInfo(u32 *fileOffset, u32 *desiredSize) override; int AddStreamData(u32 bytesToAdd) override; - u32 AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) override; int ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) override; int GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample, bool *delay) override; int SetData(const Track &track, u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) override; @@ -42,6 +41,9 @@ public: u32 DecodeData(u8 *outbuf, u32 outbufPtr, int *SamplesNum, int *finish, int *remains) override; int DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) override; + + void CheckForSas() override; + int EnqueueForSas(u32 address, u32 ptr) override; void DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) override; u32 GetNextSamples() override; @@ -73,6 +75,10 @@ private: // This is hidden state inside sceSas, really. Not visible in the context. // But it doesn't really matter whether it's here or there. - u32 sasBasePtr_ = 0; - int sasReadOffset_ = 0; + u32 sasBufferPtr_[2]{}; + u32 sasBufferSize_[2]{}; + int sasStreamOffset_ = 0; + int sasFileOffset_ = 0; + int sasCurBuffer_ = 0; + bool sasIsStreaming_ = false; }; diff --git a/Core/HLE/ErrorCodes.h b/Core/HLE/ErrorCodes.h index 15f240195d..62a629d087 100644 --- a/Core/HLE/ErrorCodes.h +++ b/Core/HLE/ErrorCodes.h @@ -490,5 +490,6 @@ enum PSPErrorCode : u32 { SCE_SAS_ERROR_BUSY = 0x80420030, SCE_SAS_ERROR_ATRAC3_ALREADY_SET = 0x80420040, SCE_SAS_ERROR_ATRAC3_NOT_SET = 0x80420041, + SCE_SAS_ERROR_ATRAC3_ALREADY_QUEUED = 0x80420042, SCE_SAS_ERROR_NOT_INIT = 0x80420100, }; diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 826d1816a3..87a7af42e2 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -1103,7 +1103,7 @@ u32 AtracSasAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd) { if (!atrac) { WARN_LOG(Log::ME, "bad atrac ID"); } - return atrac->AddStreamDataSas(bufPtr, bytesToAdd); + return atrac->EnqueueForSas(bufPtr, bytesToAdd); } void AtracSasDecodeData(int atracID, u8* outbuf, int *SamplesNum, int *finish) { @@ -1140,7 +1140,7 @@ int AtracSasBindContextAndGetID(u32 contextAddr) { // Not actually a hack, this happens. AtracBase *atrac = getAtrac(atracID); - atrac->SetOutputChannels(1); + atrac->CheckForSas(); return atracID; } diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index a3b8b9af77..f9dc374bca 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -681,7 +681,6 @@ static u32 __sceSasSetVoiceATRAC3(u32 core, int voiceNum, u32 atrac3Context) { v.playing = true; v.atrac3.SetContext(atrac3Context); Memory::Write_U32(atrac3Context, core + 56 * voiceNum + 20); - return hleLogDebug(Log::sceSas, 0); } @@ -691,11 +690,15 @@ static u32 __sceSasConcatenateATRAC3(u32 core, int voiceNum, u32 atrac3DataAddr, } DEBUG_LOG_REPORT_ONCE(concatAtrac3, Log::sceSas, "__sceSasConcatenateATRAC3(%08x, %i, %08x, %i)", core, voiceNum, atrac3DataAddr, atrac3DataLength); + __SasDrain(); + SasVoice &v = sas->voices[voiceNum]; - if (Memory::IsValidAddress(atrac3DataAddr)) + if (Memory::IsValidAddress(atrac3DataAddr)) { v.atrac3.Concatenate(atrac3DataAddr, atrac3DataLength); - return hleNoLog(0); + } + + return hleLogDebug(Log::sceSas, 0); } static u32 __sceSasUnsetATRAC3(u32 core, int voiceNum) { @@ -704,6 +707,7 @@ static u32 __sceSasUnsetATRAC3(u32 core, int voiceNum) { } __SasDrain(); + SasVoice &v = sas->voices[voiceNum]; if (v.type != VOICETYPE_ATRAC3) { return hleLogError(Log::sceSas, SCE_SAS_ERROR_ATRAC3_NOT_SET, "voice is not ATRAC3"); @@ -726,8 +730,7 @@ void __SasGetDebugStats(char *stats, size_t bufsize) { } } -const HLEFunction sceSasCore[] = -{ +const HLEFunction sceSasCore[] = { {0X42778A9F, &WrapU_UUUUU, "__sceSasInit", 'x', "xxxxx" }, {0XA3589D81, &WrapU_UU<_sceSasCore>, "__sceSasCore", 'x', "xx" }, {0X50A14DFC, &WrapU_UUII<_sceSasCoreWithMix>, "__sceSasCoreWithMix", 'x', "xxii" }, diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index e36919d1c3..42c86444dc 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -200,19 +200,23 @@ int SasAtrac3::SetContext(u32 contextAddr) { return 0; } -void SasAtrac3::getNextSamples(s16 *outbuf, int wantedSamples) { +void SasAtrac3::GetNextSamples(s16 *outbuf, int wantedSamples) { if (atracID_ < 0) { end_ = true; return; } + + if (!buf_) { + buf_ = new s16[0x800]; + } + int finish = 0; int wantedbytes = wantedSamples * sizeof(s16); while (!finish && sampleQueue_->getQueueSize() < wantedbytes) { int numSamples = 0; - static s16 buf[0x800]; - AtracSasDecodeData(atracID_, (u8*)buf, &numSamples, &finish); + AtracSasDecodeData(atracID_, (u8*)buf_, &numSamples, &finish); if (numSamples > 0) - sampleQueue_->push((u8*)buf, numSamples * sizeof(s16)); + sampleQueue_->push((u8*)buf_, numSamples * sizeof(s16)); else finish = 1; } @@ -497,7 +501,7 @@ void SasVoice::ReadSamples(s16 *output, int numSamples) { } break; case VOICETYPE_ATRAC3: - atrac3.getNextSamples(output, numSamples); + atrac3.GetNextSamples(output, numSamples); break; default: memset(output, 0, numSamples * sizeof(s16)); diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index 6627c33129..fb480a0ceb 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -137,11 +137,10 @@ private: class SasAtrac3 { public: - SasAtrac3() : contextAddr_(0), atracID_(-1), sampleQueue_(0), end_(false) {} - ~SasAtrac3() { delete sampleQueue_; } + ~SasAtrac3() { delete sampleQueue_; delete[] buf_; } + int AtracID() const { return atracID_; } // for the debugger int SetContext(u32 context); - int id() const { return atracID_; } - void getNextSamples(s16 *outbuf, int wantedSamples); + void GetNextSamples(s16 *outbuf, int wantedSamples); int Concatenate(u32 bufPtr, u32 addbytes); void DoState(PointerWrap &p); bool End() const { @@ -149,10 +148,11 @@ public: } private: - u32 contextAddr_; - int atracID_; - BufferQueue *sampleQueue_; - bool end_; + u32 contextAddr_ = 0; + int atracID_ = -1; + BufferQueue *sampleQueue_ = nullptr; + bool end_ = false; + s16 *buf_ = nullptr; }; class ADSREnvelope { diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index e70dbd88ea..40691bea33 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -1306,7 +1306,7 @@ void DrawSasAudio(ImConfig &cfg) { case VOICETYPE_OFF: ImGui::TextUnformatted("(off)"); break; case VOICETYPE_VAG: ImGui::Text("%08x", voice.vagAddr); break; case VOICETYPE_PCM: ImGui::Text("%08x", voice.pcmAddr); break; - case VOICETYPE_ATRAC3: ImGui::Text("atrac: %d", voice.atrac3.id()); break; + case VOICETYPE_ATRAC3: ImGui::Text("atrac: %d", voice.atrac3.AtracID()); break; default: ImGui::TextUnformatted("N/A"); break; From 172e54286ef2ea21bdc971d389dc5a5152c75fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Mar 2025 17:38:53 +0100 Subject: [PATCH 04/10] Refactor a bit to make it easier to expose the streaming state to the debugger. --- Core/HLE/AtracCtx.cpp | 1 + Core/HLE/AtracCtx.h | 9 +++++ Core/HLE/AtracCtx2.cpp | 85 ++++++++++++++++++++++++++++-------------- Core/HLE/AtracCtx2.h | 9 +---- 4 files changed, 68 insertions(+), 36 deletions(-) diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp index bc3eff908b..2ca9bbf952 100644 --- a/Core/HLE/AtracCtx.cpp +++ b/Core/HLE/AtracCtx.cpp @@ -948,6 +948,7 @@ int Atrac::DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, i void Atrac::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { // Disabled, can't work now that we changed the interface. + *bytesWritten = 0; *finish = 1; } diff --git a/Core/HLE/AtracCtx.h b/Core/HLE/AtracCtx.h index 3696ac7dac..996a4df404 100644 --- a/Core/HLE/AtracCtx.h +++ b/Core/HLE/AtracCtx.h @@ -37,6 +37,14 @@ struct AtracResetBufferInfo { AtracSingleResetBufferInfo second; }; +struct AtracSasStreamState { + u32 bufPtr[2]{}; + u32 bufSize[2]{}; + int streamOffset = 0; + int fileOffset = 0; + int curBuffer = 0; + bool isStreaming = false; +}; const int PSP_ATRAC_ALLDATA_IS_ON_MEMORY = -1; const int PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY = -2; @@ -127,6 +135,7 @@ public: virtual void CheckForSas() = 0; virtual int EnqueueForSas(u32 address, u32 ptr) = 0; virtual void DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) = 0; + virtual const AtracSasStreamState *StreamStateForSas() const { return nullptr; } virtual int GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const = 0; diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index 7dbac9550b..18cd15a85c 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -175,9 +175,9 @@ Atrac2::Atrac2(u32 contextAddr, int codecType) { info.state = ATRAC_STATUS_NO_DATA; info.curBuffer = 0; - sasStreamOffset_ = 0; - sasBufferPtr_[0] = 0; - sasBufferPtr_[1] = 0; + sas_.streamOffset = 0; + sas_.bufPtr[0] = 0; + sas_.bufPtr[1] = 0; } else { // We're loading state, we'll restore the context in DoState. } @@ -195,14 +195,17 @@ void Atrac2::DoState(PointerWrap &p) { // Actually, now we also need to save sas state. I guess this could also be saved on the Sas side, but this is easier. if (s >= 2) { - Do(p, sasStreamOffset_); - Do(p, sasBufferPtr_[0]); + Do(p, sas_.streamOffset); + Do(p, sas_.bufPtr[0]); } // Added support for streaming sas audio, need some more context state. if (s >= 3) { - Do(p, sasBufferPtr_[1]); - Do(p, sasBufferSize_); - Do(p, sasIsStreaming_); + Do(p, sas_.bufPtr[1]); + Do(p, sas_.bufSize[0]); + Do(p, sas_.bufSize[1]); + Do(p, sas_.isStreaming); + Do(p, sas_.curBuffer); + Do(p, sas_.fileOffset); } const SceAtracIdInfo &info = context_->info; @@ -1045,7 +1048,12 @@ void Atrac2::CheckForSas() { if (info.state != 0x10) { WARN_LOG(Log::ME, "Caller forgot to set state to 0x10"); } - sasIsStreaming_ = info.fileDataEnd >= info.bufferByte; + sas_.isStreaming = info.fileDataEnd > info.bufferByte; + if (sas_.isStreaming) { + INFO_LOG(Log::ME, "SasAtrac stream mode"); + } else { + INFO_LOG(Log::ME, "SasAtrac non-streaming mode"); + } } int Atrac2::EnqueueForSas(u32 address, u32 ptr) { @@ -1061,64 +1069,83 @@ int Atrac2::EnqueueForSas(u32 address, u32 ptr) { return 0; } +// Completely different streaming setup! void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { SceAtracIdInfo &info = context_->info; + *bytesWritten = 0; // First frame handling. Not sure if accurate. Set up the initial buffer as the current streaming buffer. // Also works for the non-streaming case. - if (sasBufferPtr_[0] == 0 && sasCurBuffer_ == 0) { - sasBufferPtr_[0] = info.buffer; - sasBufferSize_[0] = info.bufferByte - info.streamOff; - sasStreamOffset_ = 0; - sasFileOffset_ = 0; + if (sas_.bufPtr[0] == 0 && sas_.curBuffer == 0) { + sas_.bufPtr[0] = info.buffer; + sas_.bufSize[0] = info.bufferByte - info.streamOff; + sas_.streamOffset = 0; + sas_.fileOffset = 0; } u8 assembly[1000]; // Keep decoding from the current buffer until it runs out. - if (sasStreamOffset_ + info.sampleSize <= sasBufferSize_[sasCurBuffer_]) { + if (sas_.streamOffset + info.sampleSize <= sas_.bufSize[sas_.curBuffer]) { // Just decode. - const u8 *srcData = Memory::GetPointer(sasBufferPtr_[sasCurBuffer_] + sasStreamOffset_); + const u8 *srcData = Memory::GetPointer(sas_.bufPtr[sas_.curBuffer] + sas_.streamOffset); int bytesConsumed = 0; bool decodeResult = decoder_->Decode(srcData, info.sampleSize, &bytesConsumed, 1, dstData, bytesWritten); if (!decodeResult) { ERROR_LOG(Log::ME, "SAS failed to decode packet"); } - sasStreamOffset_ += bytesConsumed; - sasFileOffset_ += bytesConsumed; - } else if (sasIsStreaming_) { + sas_.streamOffset += bytesConsumed; + sas_.fileOffset += bytesConsumed; + } else if (sas_.isStreaming) { // TODO: Do we need special handling for the first buffer, since SetData will wrap around that packet? I think yes! - WARN_LOG(Log::ME, "Streaming, and hit the end of buffer %d, switching over.", sasCurBuffer_); + WARN_LOG(Log::ME, "Streaming, and hit the end of buffer %d, switching over.", sas_.curBuffer); - int part1Size = sasBufferSize_[sasCurBuffer_] - sasStreamOffset_; + int part1Size = sas_.bufSize[sas_.curBuffer] - sas_.streamOffset; int part2Size = info.sampleSize - part1Size; _dbg_assert_(part1Size >= 0); if (part1Size >= 0) { // Grab the partial packet, before we switch over to the other buffer. - Memory::Memcpy(assembly, sasBufferPtr_[sasCurBuffer_] + sasStreamOffset_, part1Size); + Memory::Memcpy(assembly, sas_.bufPtr[sas_.curBuffer] + sas_.streamOffset, part1Size); } + + // Check if we hit the end. + if (sas_.fileOffset >= info.fileDataEnd) { + WARN_LOG(Log::ME, "Streaming and hit the end."); + *bytesWritten = 0; + *finish = 1; + return; + } + // Check that a new buffer actually exists - if ((int)info.secondBuffer < 0 || info.secondBuffer == sasBufferPtr_[sasCurBuffer_]) { + if (info.secondBuffer == sas_.bufPtr[sas_.curBuffer]) { + ERROR_LOG(Log::ME, "Can't enqueue the same buffer twice in a row!"); + *bytesWritten = 0; + *finish = 1; + return; + } + + if ((int)info.secondBuffer < 0 || info.secondBuffer == sas_.bufPtr[sas_.curBuffer]) { ERROR_LOG(Log::ME, "AtracSas streaming ran out of data, no secondbuffer pending"); + *bytesWritten = 0; *finish = 1; return; } // Switch to the other buffer. - sasCurBuffer_ ^= 1; + sas_.curBuffer ^= 1; - sasBufferPtr_[sasCurBuffer_] = info.secondBuffer; - sasBufferSize_[sasCurBuffer_] = info.secondBufferByte; - sasStreamOffset_ = part2Size; + sas_.bufPtr[sas_.curBuffer] = info.secondBuffer; + sas_.bufSize[sas_.curBuffer] = info.secondBufferByte; + sas_.streamOffset = part2Size; info.secondBuffer = 0xFFFFFFFF; // Signal to the caller that we accept a new next buffer. NOTE: This // Copy the second half (or if part1Size == 0, the whole packet) to the assembly buffer. - Memory::Memcpy(assembly + part1Size, sasBufferPtr_[sasCurBuffer_], part2Size); + Memory::Memcpy(assembly + part1Size, sas_.bufPtr[sas_.curBuffer], part2Size); // Decode the packet from the assembly, whether it's was assembled from two or one. const u8 *srcData = assembly; int bytesConsumed = 0; bool decodeResult = decoder_->Decode(srcData, info.sampleSize, &bytesConsumed, 1, dstData, bytesWritten); - sasFileOffset_ += bytesConsumed; + sas_.fileOffset += bytesConsumed; if (!decodeResult) { ERROR_LOG(Log::ME, "SAS failed to decode packet"); } diff --git a/Core/HLE/AtracCtx2.h b/Core/HLE/AtracCtx2.h index 612c182a92..afd4956677 100644 --- a/Core/HLE/AtracCtx2.h +++ b/Core/HLE/AtracCtx2.h @@ -45,6 +45,7 @@ public: void CheckForSas() override; int EnqueueForSas(u32 address, u32 ptr) override; void DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) override; + const AtracSasStreamState *StreamStateForSas() const { return context_->info.state == 0x10 ? &sas_ : nullptr; } u32 GetNextSamples() override; @@ -57,7 +58,6 @@ public: void NotifyGetContextAddress() override {} int GetContextVersion() const override { return 2; } - u32 GetInternalCodecError() const override; private: @@ -75,10 +75,5 @@ private: // This is hidden state inside sceSas, really. Not visible in the context. // But it doesn't really matter whether it's here or there. - u32 sasBufferPtr_[2]{}; - u32 sasBufferSize_[2]{}; - int sasStreamOffset_ = 0; - int sasFileOffset_ = 0; - int sasCurBuffer_ = 0; - bool sasIsStreaming_ = false; + AtracSasStreamState sas_; }; From 5ea7729f663cc9048418116bfdd4db74369a7b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Mar 2025 18:37:30 +0100 Subject: [PATCH 05/10] More work on atrac-through-sas --- Core/HLE/AtracCtx.h | 6 ++++ Core/HLE/AtracCtx2.cpp | 31 +++++++++++++---- Core/HLE/sceSas.cpp | 9 ++--- UI/ImDebugger/ImDebugger.cpp | 66 ++++++++++++++++++++++-------------- 4 files changed, 74 insertions(+), 38 deletions(-) diff --git a/Core/HLE/AtracCtx.h b/Core/HLE/AtracCtx.h index 996a4df404..94560ca111 100644 --- a/Core/HLE/AtracCtx.h +++ b/Core/HLE/AtracCtx.h @@ -44,6 +44,12 @@ struct AtracSasStreamState { int fileOffset = 0; int curBuffer = 0; bool isStreaming = false; + + int CurPos() const { + int retval = fileOffset - bufSize[curBuffer] + streamOffset; + _dbg_assert_(retval >= 0); + return retval; + } }; const int PSP_ATRAC_ALLDATA_IS_ON_MEMORY = -1; diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index 18cd15a85c..58d9fa0e19 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -1064,6 +1064,11 @@ int Atrac2::EnqueueForSas(u32 address, u32 ptr) { return SCE_SAS_ERROR_ATRAC3_ALREADY_QUEUED; } + if (address == 0 && ptr == 0) { + INFO_LOG(Log::ME, "Caller tries to send us a zero buffer. Something went wrong."); + } + + INFO_LOG(Log::ME, "Second buffer updated to %08x, sz: %08x", address, ptr); info.secondBuffer = address; info.secondBufferByte = ptr; return 0; @@ -1080,7 +1085,7 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { sas_.bufPtr[0] = info.buffer; sas_.bufSize[0] = info.bufferByte - info.streamOff; sas_.streamOffset = 0; - sas_.fileOffset = 0; + sas_.fileOffset = info.bufferByte; } u8 assembly[1000]; @@ -1091,15 +1096,15 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { int bytesConsumed = 0; bool decodeResult = decoder_->Decode(srcData, info.sampleSize, &bytesConsumed, 1, dstData, bytesWritten); if (!decodeResult) { - ERROR_LOG(Log::ME, "SAS failed to decode packet"); + ERROR_LOG(Log::ME, "SAS failed to decode regular packet"); } sas_.streamOffset += bytesConsumed; - sas_.fileOffset += bytesConsumed; } else if (sas_.isStreaming) { // TODO: Do we need special handling for the first buffer, since SetData will wrap around that packet? I think yes! - WARN_LOG(Log::ME, "Streaming, and hit the end of buffer %d, switching over.", sas_.curBuffer); + WARN_LOG(Log::ME, "Streaming, and hit the end of buffer %d", sas_.curBuffer); + // Compute the part sizes using the current size. int part1Size = sas_.bufSize[sas_.curBuffer] - sas_.streamOffset; int part2Size = info.sampleSize - part1Size; _dbg_assert_(part1Size >= 0); @@ -1133,11 +1138,24 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { // Switch to the other buffer. sas_.curBuffer ^= 1; + WARN_LOG(Log::ME, "Switching over to buffer %d, updating buffer to %08x, sz: %08x", sas_.curBuffer, info.secondBuffer, info.secondBufferByte); sas_.bufPtr[sas_.curBuffer] = info.secondBuffer; sas_.bufSize[sas_.curBuffer] = info.secondBufferByte; + sas_.fileOffset += info.secondBufferByte; + sas_.streamOffset = part2Size; - info.secondBuffer = 0xFFFFFFFF; // Signal to the caller that we accept a new next buffer. NOTE: This + + // If we'll reach the end during this buffer, set second buffer to 0, signaling that we don't need more data. + if (sas_.fileOffset >= info.fileDataEnd) { + // We've reached the end. + info.secondBuffer = 0; + WARN_LOG(Log::ME, "%08x >= %08x: Reached the end.", sas_.fileOffset, info.fileDataEnd); + } else { + // Signal to the caller that we accept a new next buffer. + info.secondBuffer = 0xFFFFFFFF; + WARN_LOG(Log::ME, "Signalling for more data (%08x < %08x).", sas_.fileOffset, info.fileDataEnd); + } // Copy the second half (or if part1Size == 0, the whole packet) to the assembly buffer. Memory::Memcpy(assembly + part1Size, sas_.bufPtr[sas_.curBuffer], part2Size); @@ -1145,9 +1163,8 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { const u8 *srcData = assembly; int bytesConsumed = 0; bool decodeResult = decoder_->Decode(srcData, info.sampleSize, &bytesConsumed, 1, dstData, bytesWritten); - sas_.fileOffset += bytesConsumed; if (!decodeResult) { - ERROR_LOG(Log::ME, "SAS failed to decode packet"); + ERROR_LOG(Log::ME, "SAS failed to decode assembled packet"); } } diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index f9dc374bca..ee4142e258 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -689,15 +689,12 @@ static u32 __sceSasConcatenateATRAC3(u32 core, int voiceNum, u32 atrac3DataAddr, return hleLogWarning(Log::sceSas, SCE_SAS_ERROR_INVALID_VOICE, "invalid voicenum"); } - DEBUG_LOG_REPORT_ONCE(concatAtrac3, Log::sceSas, "__sceSasConcatenateATRAC3(%08x, %i, %08x, %i)", core, voiceNum, atrac3DataAddr, atrac3DataLength); - __SasDrain(); - SasVoice &v = sas->voices[voiceNum]; - if (Memory::IsValidAddress(atrac3DataAddr)) { - v.atrac3.Concatenate(atrac3DataAddr, atrac3DataLength); - } + DEBUG_LOG_REPORT_ONCE(concatAtrac3, Log::sceSas, "__sceSasConcatenateATRAC3(%08x, %i, %08x, %i)", core, voiceNum, atrac3DataAddr, atrac3DataLength); + SasVoice &v = sas->voices[voiceNum]; + v.atrac3.Concatenate(atrac3DataAddr, atrac3DataLength); return hleLogDebug(Log::sceSas, 0); } diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index 40691bea33..1960bf0a58 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -1028,14 +1028,14 @@ void DrawAudioDecodersView(ImConfig &cfg, ImControl &control) { char header[32]; snprintf(header, sizeof(header), "Atrac context %d", cfg.selectedAtracCtx); if (ctx && ImGui::CollapsingHeader(header, ImGuiTreeNodeFlags_DefaultOpen)) { - int pos; - ctx->GetNextDecodePosition(&pos); - int endSample, loopStart, loopEnd; - ctx->GetSoundSample(&endSample, &loopStart, &loopEnd); - ImGui::ProgressBar((float)pos / (float)endSample, ImVec2(200.0f, 0.0f)); - ImGui::Text("Status: %s", AtracStatusToString(ctx->BufferState())); - if (ctx->BufferState() <= ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) { - ImGui::Text("cur/end sample: %d/%d/%d", pos, endSample); + bool isNormal = AtracStatusIsNormal(ctx->BufferState()); + if (isNormal) { + int pos; + ctx->GetNextDecodePosition(&pos); + int endSample, loopStart, loopEnd; + ctx->GetSoundSample(&endSample, &loopStart, &loopEnd); + ImGui::ProgressBar((float)pos / (float)endSample, ImVec2(200.0f, 0.0f)); + ImGui::Text("Status: %s", AtracStatusToString(ctx->BufferState())); ImGui::Text("cur/end sample: %d/%d/%d", pos, endSample); } if (ctx->context_.IsValid()) { ImGui::Text("ctx addr: "); @@ -1044,25 +1044,41 @@ void DrawAudioDecodersView(ImConfig &cfg, ImControl &control) { } if (ctx->context_.IsValid() && ctx->GetContextVersion() >= 2) { const auto &info = ctx->context_->info; - ImGui::Text("Buffer: (size: %d / %08x) Frame: %d", info.bufferByte, info.bufferByte, info.sampleSize); - ImGui::SameLine(); - ImClickableValue("buffer", info.buffer, control, ImCmd::SHOW_IN_MEMORY_VIEWER); - if (info.secondBuffer || info.secondBufferByte) { - ImGui::Text("Second: (size: %d / %08x)", info.secondBufferByte, info.secondBufferByte); + if (isNormal) { + ImGui::Text("Buffer: (size: %d / %08x) Frame: %d", info.bufferByte, info.bufferByte, info.sampleSize); ImGui::SameLine(); - ImClickableValue("second", info.secondBuffer, control, ImCmd::SHOW_IN_MEMORY_VIEWER); + ImClickableValue("buffer", info.buffer, control, ImCmd::SHOW_IN_MEMORY_VIEWER); + if (info.secondBuffer || info.secondBufferByte) { + ImGui::Text("Second: (size: %d / %08x)", info.secondBufferByte, info.secondBufferByte); + ImGui::SameLine(); + ImClickableValue("second", info.secondBuffer, control, ImCmd::SHOW_IN_MEMORY_VIEWER); + } + ImGui::Text("Data: %d/%d", info.dataOff, info.fileDataEnd); + if (info.state != ATRAC_STATUS_STREAMED_WITHOUT_LOOP) { + ImGui::Text("LoopNum: %d (%d-%d)", info.loopNum, info.loopStart, info.loopEnd); + } + ImGui::Text("DecodePos: %d EndSample: %d", info.decodePos, info.fileDataEnd); + if (AtracStatusIsStreaming(info.state)) { + ImGui::Text("Stream: offset %d, streamDataBytes: %d", info.streamOff, info.streamDataByte); + } + ImGui::Text("numFrame: %d curBuffer: %d streamOff2: %d", info.numSkipFrames, info.curBuffer, info.secondStreamOff); + } else if (ctx->BufferState() == ATRAC_STATUS_FOR_SCESAS) { + // A different set of state! + const AtracSasStreamState *sas = ctx->StreamStateForSas(); + if (sas) { + ImGui::ProgressBar((float)sas->CurPos() / (float)info.fileDataEnd, ImVec2(200.0f, 0.0f)); + ImGui::ProgressBar((float)sas->streamOffset / (float)sas->bufSize[sas->curBuffer], ImVec2(200.0f, 0.0f)); + ImGui::Text("Cur pos: %08x File offset: %08x File end: %08x%s", sas->CurPos(), sas->fileOffset, info.fileDataEnd, sas->fileOffset >= info.fileDataEnd ? " (END)" : ""); + ImGui::Text("Second (next buffer): %08x (sz: %08x)", info.secondBuffer, info.secondBufferByte); + ImGui::Text("Cur buffer: %d (%08x, sz: %08x)", sas->curBuffer, sas->bufPtr[sas->curBuffer], sas->bufSize[sas->curBuffer]); + ImGui::Text("2nd buffer: %d (%08x, sz: %08x)", sas->curBuffer ^ 1, sas->bufPtr[sas->curBuffer ^ 1], sas->bufSize[sas->curBuffer ^ 1]); + ImGui::Text("Loop points: %08x, %08x", info.loopStart, info.loopEnd); + ImGui::TextUnformatted(sas->isStreaming ? "Streaming mode!" : "Non-streaming mode"); + } else { + ImGui::Text("can't access sas state"); + } } - ImGui::Text("Data: %d/%d", info.dataOff, info.fileDataEnd); - if (info.state != ATRAC_STATUS_STREAMED_WITHOUT_LOOP) { - ImGui::Text("LoopNum: %d (%d-%d)", info.loopNum, info.loopStart, info.loopEnd); - } - ImGui::Text("DecodePos: %d EndSample: %d", info.decodePos, info.fileDataEnd); - if (AtracStatusIsStreaming(info.state)) { - ImGui::Text("Stream: offset %d, streamDataBytes: %d", info.streamOff, info.streamDataByte); - } - // Display unknown vars. - ImGui::Text("numFrame: %d curBuffer: %d streamOff2: %d", info.numSkipFrames, info.curBuffer, info.secondStreamOff); - } else { + } else { ImGui::Text("loop: %d", ctx->LoopNum()); } } From c418513fa58625adf794c62ca49e1d6c5ec95d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Mar 2025 21:55:42 +0100 Subject: [PATCH 06/10] Fix bad check, add some comments And remove unneded initial text. --- Core/HLE/AtracCtx2.cpp | 4 ++-- Core/HW/SasAudio.cpp | 2 +- UI/TabbedDialogScreen.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index 58d9fa0e19..181d39c8b7 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -1083,9 +1083,9 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { // Also works for the non-streaming case. if (sas_.bufPtr[0] == 0 && sas_.curBuffer == 0) { sas_.bufPtr[0] = info.buffer; - sas_.bufSize[0] = info.bufferByte - info.streamOff; + sas_.bufSize[0] = info.bufferByte - info.streamOff; // also equals info.streamDataByte sas_.streamOffset = 0; - sas_.fileOffset = info.bufferByte; + sas_.fileOffset = info.bufferByte; // Possibly should just set it to info.curFileOff } u8 assembly[1000]; diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index 42c86444dc..126f3d68ff 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -225,7 +225,7 @@ void SasAtrac3::GetNextSamples(s16 *outbuf, int wantedSamples) { } int SasAtrac3::Concatenate(u32 bufPtr, u32 addbytes) { - if (atracID_ > 0) { + if (atracID_ >= 0) { AtracSasAddStreamData(atracID_, bufPtr, addbytes); } return 0; diff --git a/UI/TabbedDialogScreen.cpp b/UI/TabbedDialogScreen.cpp index 2e09bf4574..e762c6cef1 100644 --- a/UI/TabbedDialogScreen.cpp +++ b/UI/TabbedDialogScreen.cpp @@ -92,7 +92,7 @@ void TabbedUIDialogScreenWithGameBackground::CreateViews() { return UI::EVENT_DONE; }); - noSearchResults_ = searchSettings->Add(new TextView(se->T("No settings matched '%1'"), new LinearLayoutParams(Margins(20, 5)))); + noSearchResults_ = searchSettings->Add(new TextView("", new LinearLayoutParams(Margins(20, 5)))); }, true); } From 96ca0e95f30979c57fb4434911bad2d7036992c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Mar 2025 21:58:32 +0100 Subject: [PATCH 07/10] Cleanup logging --- Core/HLE/AtracCtx2.cpp | 24 ++++++++---------------- Core/HLE/sceSas.cpp | 2 +- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index 181d39c8b7..f9c6e97c95 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -1065,10 +1065,10 @@ int Atrac2::EnqueueForSas(u32 address, u32 ptr) { } if (address == 0 && ptr == 0) { - INFO_LOG(Log::ME, "Caller tries to send us a zero buffer. Something went wrong."); + WARN_LOG(Log::ME, "Caller tries to send us a zero buffer. Something went wrong."); } - INFO_LOG(Log::ME, "Second buffer updated to %08x, sz: %08x", address, ptr); + DEBUG_LOG(Log::ME, "EnqueueForSas: Second buffer updated to %08x, sz: %08x", address, ptr); info.secondBuffer = address; info.secondBufferByte = ptr; return 0; @@ -1101,8 +1101,7 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { sas_.streamOffset += bytesConsumed; } else if (sas_.isStreaming) { // TODO: Do we need special handling for the first buffer, since SetData will wrap around that packet? I think yes! - - WARN_LOG(Log::ME, "Streaming, and hit the end of buffer %d", sas_.curBuffer); + DEBUG_LOG(Log::ME, "Streaming atrac through sas, and hit the end of buffer %d", sas_.curBuffer); // Compute the part sizes using the current size. int part1Size = sas_.bufSize[sas_.curBuffer] - sas_.streamOffset; @@ -1115,7 +1114,7 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { // Check if we hit the end. if (sas_.fileOffset >= info.fileDataEnd) { - WARN_LOG(Log::ME, "Streaming and hit the end."); + DEBUG_LOG(Log::ME, "Streaming and hit the file end."); *bytesWritten = 0; *finish = 1; return; @@ -1129,7 +1128,7 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { return; } - if ((int)info.secondBuffer < 0 || info.secondBuffer == sas_.bufPtr[sas_.curBuffer]) { + if ((int)info.secondBuffer < 0) { ERROR_LOG(Log::ME, "AtracSas streaming ran out of data, no secondbuffer pending"); *bytesWritten = 0; *finish = 1; @@ -1138,7 +1137,6 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { // Switch to the other buffer. sas_.curBuffer ^= 1; - WARN_LOG(Log::ME, "Switching over to buffer %d, updating buffer to %08x, sz: %08x", sas_.curBuffer, info.secondBuffer, info.secondBufferByte); sas_.bufPtr[sas_.curBuffer] = info.secondBuffer; sas_.bufSize[sas_.curBuffer] = info.secondBufferByte; @@ -1150,13 +1148,14 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { if (sas_.fileOffset >= info.fileDataEnd) { // We've reached the end. info.secondBuffer = 0; - WARN_LOG(Log::ME, "%08x >= %08x: Reached the end.", sas_.fileOffset, info.fileDataEnd); + DEBUG_LOG(Log::ME, "%08x >= %08x: Reached the end.", sas_.fileOffset, info.fileDataEnd); } else { // Signal to the caller that we accept a new next buffer. info.secondBuffer = 0xFFFFFFFF; - WARN_LOG(Log::ME, "Signalling for more data (%08x < %08x).", sas_.fileOffset, info.fileDataEnd); } + DEBUG_LOG(Log::ME, "Switching over to buffer %d, updating buffer to %08x, sz: %08x. %s", sas_.curBuffer, info.secondBuffer, info.secondBufferByte, info.secondBuffer == 0xFFFFFFFF ? "Signalling for more data." : ""); + // Copy the second half (or if part1Size == 0, the whole packet) to the assembly buffer. Memory::Memcpy(assembly + part1Size, sas_.bufPtr[sas_.curBuffer], part2Size); // Decode the packet from the assembly, whether it's was assembled from two or one. @@ -1167,11 +1166,4 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { ERROR_LOG(Log::ME, "SAS failed to decode assembled packet"); } } - - /* - if (sasReadOffset_ + info.dataOff >= info.fileDataEnd) { - *finish = 1; - } else { - *finish = 0; - }*/ } diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index ee4142e258..0d9d854adf 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -416,7 +416,7 @@ static u32 sceSasSetVolume(u32 core, int voiceNum, int leftVol, int rightVol, in v.volumeRight = rightVol; v.effectLeft = effectLeftVol; v.effectRight = effectRightVol; - return hleLogDebug(Log::sceSas, 0); + return hleLogVerbose(Log::sceSas, 0); } static u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) { From 870995a76779054bf81119cfdd90a82b5dc229f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Mar 2025 22:19:09 +0100 Subject: [PATCH 08/10] Mostly restore the old code path --- Core/HLE/AtracCtx.cpp | 25 ++++++++++++++++++++++--- Core/HLE/AtracCtx.h | 4 ++-- Core/HLE/sceAtrac.cpp | 1 - 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp index 2ca9bbf952..14ee036062 100644 --- a/Core/HLE/AtracCtx.cpp +++ b/Core/HLE/AtracCtx.cpp @@ -946,10 +946,29 @@ int Atrac::DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, i return 0; } +void Atrac::CheckForSas() { + SetOutputChannels(1); +} + +int Atrac::EnqueueForSas(u32 bufPtr, u32 bytesToAdd) { + int addbytes = std::min(bytesToAdd, track_.fileSize - first_.fileoffset - track_.FirstOffsetExtra()); + Memory::Memcpy(dataBuf_ + first_.fileoffset + track_.FirstOffsetExtra(), bufPtr, addbytes, "AtracAddStreamData"); + first_.size += bytesToAdd; + if (first_.size >= track_.fileSize) { + first_.size = track_.fileSize; + if (bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) + bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; + } + first_.fileoffset += addbytes; + // refresh context_ + WriteContextToPSPMem(); + return 0; +} + void Atrac::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { - // Disabled, can't work now that we changed the interface. - *bytesWritten = 0; - *finish = 1; + // Hack, but works. + int samplesNum; + DecodeData((u8 *)dstData, 0, &samplesNum, finish, nullptr); } void Atrac::NotifyGetContextAddress() { diff --git a/Core/HLE/AtracCtx.h b/Core/HLE/AtracCtx.h index 94560ca111..276fd38a90 100644 --- a/Core/HLE/AtracCtx.h +++ b/Core/HLE/AtracCtx.h @@ -231,8 +231,8 @@ public: u32 DecodeData(u8 *outbuf, u32 outbufPtr, int *SamplesNum, int *finish, int *remains) override; int DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) override; - void CheckForSas() {} - int EnqueueForSas(u32 address, u32 ptr) override { return 0; } + void CheckForSas() override; + int EnqueueForSas(u32 address, u32 ptr) override; void DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) override; // Returns how many samples the next DecodeData will write. diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 87a7af42e2..0a27836758 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -1138,7 +1138,6 @@ int AtracSasBindContextAndGetID(u32 contextAddr) { _dbg_assert_(atracID != -1); } - // Not actually a hack, this happens. AtracBase *atrac = getAtrac(atracID); atrac->CheckForSas(); return atracID; From 8403597efd873bf0328d17a6b7b8e25c32eab094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Mar 2025 22:19:28 +0100 Subject: [PATCH 09/10] Fix an unrelated issue where "Cache full iso in RAM" didn't actually work until resetting --- Core/System.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/System.cpp b/Core/System.cpp index bd4b80222b..103fca6074 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -212,7 +212,7 @@ bool DiscIDFromGEDumpPath(const Path &path, FileLoader *fileLoader, std::string } } -bool CPU_Init(std::string *errorString, FileLoader *loadedFile) { +bool CPU_Init(std::string *errorString, FileLoader *loadedFile, IdentifiedFileType type) { coreState = CORE_POWERUP; currentMIPS = &mipsr4k; @@ -228,8 +228,6 @@ bool CPU_Init(std::string *errorString, FileLoader *loadedFile) { Path filename = g_CoreParameter.fileToStart; - IdentifiedFileType type = Identify_File(loadedFile, errorString); - // TODO: Put this somewhere better? if (!g_CoreParameter.mountIso.empty()) { g_CoreParameter.mountIsoLoader = ConstructFileLoader(g_CoreParameter.mountIso); @@ -414,9 +412,12 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) { Path filename = g_CoreParameter.fileToStart; FileLoader *loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename)); -#if PPSSPP_ARCH(AMD64) + + IdentifiedFileType type = Identify_File(loadedFile, &g_CoreParameter.errorString); + g_CoreParameter.fileType = type; + if (g_Config.bCacheFullIsoInRam) { - switch (coreParam.fileType) { + switch (g_CoreParameter.fileType) { case IdentifiedFileType::PSP_ISO: case IdentifiedFileType::PSP_ISO_NP: loadedFile = new RamCachingFileLoader(loadedFile); @@ -426,7 +427,6 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) { break; } } -#endif if (g_Config.bAchievementsEnable) { // Need to re-identify after ResolveFileLoaderTarget - although in practice probably not, @@ -436,7 +436,7 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) { Achievements::SetGame(filename, type, loadedFile); } - if (!CPU_Init(&g_CoreParameter.errorString, loadedFile)) { + if (!CPU_Init(&g_CoreParameter.errorString, loadedFile, type)) { *error_string = g_CoreParameter.errorString; if (error_string->empty()) { *error_string = "Failed initializing CPU/Memory"; From 2af71d049b865e4f21e9974e7ccf8e2e59fa5fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 25 Mar 2025 23:27:43 +0100 Subject: [PATCH 10/10] Lost this behavior by mistake. Should fix the tests. --- Core/HLE/AtracCtx2.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index f9c6e97c95..655a074b4b 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -1081,11 +1081,13 @@ void Atrac2::DecodeForSas(s16 *dstData, int *bytesWritten, int *finish) { // First frame handling. Not sure if accurate. Set up the initial buffer as the current streaming buffer. // Also works for the non-streaming case. - if (sas_.bufPtr[0] == 0 && sas_.curBuffer == 0) { + if (info.buffer) { + sas_.curBuffer = 0; sas_.bufPtr[0] = info.buffer; sas_.bufSize[0] = info.bufferByte - info.streamOff; // also equals info.streamDataByte sas_.streamOffset = 0; sas_.fileOffset = info.bufferByte; // Possibly should just set it to info.curFileOff + info.buffer = 0; // yes, this happens. } u8 assembly[1000];