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] 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_; };