From fd9564166bece3ea7a7eaf60fac17e64c8d03fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 16 Mar 2025 11:06:52 +0100 Subject: [PATCH 1/5] More GetTrack removal --- Core/HLE/AtracCtx.cpp | 2 +- Core/HLE/AtracCtx.h | 36 +++++++++++++++++++++++------------- Core/HLE/AtracCtx2.cpp | 8 ++++++++ Core/HLE/AtracCtx2.h | 6 ++++++ Core/HLE/sceAtrac.cpp | 20 +++++++++++--------- 5 files changed, 49 insertions(+), 23 deletions(-) diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp index 462b5c6700..c6cccacabb 100644 --- a/Core/HLE/AtracCtx.cpp +++ b/Core/HLE/AtracCtx.cpp @@ -547,7 +547,7 @@ int Atrac::AnalyzeAA3(u32 addr, u32 size, u32 fileSize) { return AnalyzeAA3Track(addr, size, fileSize, &track_); } -int AtracBase::GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) { +int Atrac::GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const { *endSample = GetTrack().endSample; *loopStartSample = GetTrack().loopStartSample == -1 ? -1 : GetTrack().loopStartSample - GetTrack().FirstSampleOffsetFull(); *loopEndSample = GetTrack().loopEndSample == -1 ? -1 : GetTrack().loopEndSample - GetTrack().FirstSampleOffsetFull(); diff --git a/Core/HLE/AtracCtx.h b/Core/HLE/AtracCtx.h index 6818367847..99d3eed7c9 100644 --- a/Core/HLE/AtracCtx.h +++ b/Core/HLE/AtracCtx.h @@ -141,12 +141,13 @@ struct Track { return codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES; } - void UpdateBitrate() { - bitrate = (bytesPerFrame * 352800) / 1000; + int Bitrate() const { + int bitrate = (bytesPerFrame * 352800) / 1000; if (codecType == PSP_MODE_AT_3_PLUS) bitrate = ((bitrate >> 11) + 8) & 0xFFFFFFF0; else bitrate = (bitrate + 511) >> 10; + return bitrate; } // This appears to be buggy, should probably include FirstOffsetExtra? @@ -186,17 +187,10 @@ public: const Track &GetTrack() const { return track_; } - // This should be rare. - Track &GetTrackMut() { - return track_; - } int Channels() const { return track_.channels; } - int SamplesPerFrame() const { - return track_.SamplesPerFrame(); - } int GetOutputChannels() const { return outputChannels_; @@ -215,9 +209,7 @@ public: return bufferState_; } - int LoopNum() const { - return loopNum_; - } + virtual int LoopNum() const = 0; virtual int LoopStatus() const = 0; u32 CodecType() const { return track_.codecType; @@ -231,6 +223,8 @@ public: virtual int CurrentSample() const = 0; virtual int RemainingFrames() const = 0; virtual u32 SecondBufferSize() const = 0; + virtual int Bitrate() const = 0; + virtual int SamplesPerFrame() const = 0; virtual int Analyze(u32 addr, u32 size) = 0; virtual int AnalyzeAA3(u32 addr, u32 size, u32 filesize) = 0; @@ -253,7 +247,7 @@ public: virtual u32 GetNextSamples() = 0; virtual void InitLowLevel(u32 paramsAddr, bool jointStereo) = 0; - int GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample); + virtual int GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const = 0; protected: Track track_{}; @@ -295,12 +289,26 @@ public: u32 SecondBufferSize() const override { return second_.size; } + int LoopNum() const override { + return loopNum_; + } int LoopStatus() const override { if (track_.loopinfo.size() > 0) return 1; else return 0; } + int Bitrate() const override { + return track_.Bitrate(); + } + int SamplesPerFrame() const override { + return track_.SamplesPerFrame(); + } + + // This should be rare. + Track &GetTrackMut() { + return track_; + } // Ask where in memory new data should be written. void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override; @@ -317,6 +325,8 @@ public: u32 GetNextSamples() override; void InitLowLevel(u32 paramsAddr, bool jointStereo) override; + int GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const override; + protected: void AnalyzeReset(); diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index aa60e2c7be..76ee437225 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -35,6 +35,10 @@ // * Half Minute Hero (bufsize 65536) // * Flatout (tricky! needs investigation) +Atrac2::Atrac2(int codecType) { + track_.codecType = codecType; +} + void Atrac2::DoState(PointerWrap &p) { _assert_msg_(false, "Savestates not yet support with new Atrac implementation.\n\nTurn it off in Developer settings.\n\n"); } @@ -114,6 +118,10 @@ int Atrac2::GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) { return 0; } +int Atrac2::GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const { + return 0; +} + int Atrac2::SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) { if (readSize == bufferSize) { bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; diff --git a/Core/HLE/AtracCtx2.h b/Core/HLE/AtracCtx2.h index 12fe48714d..fd24006390 100644 --- a/Core/HLE/AtracCtx2.h +++ b/Core/HLE/AtracCtx2.h @@ -7,6 +7,7 @@ class Atrac2 : public AtracBase { public: + Atrac2(int codecType); void DoState(PointerWrap &p) override; void WriteContextToPSPMem() override; @@ -16,6 +17,9 @@ public: int CurrentSample() const override { return currentSample_; } int RemainingFrames() const override; int LoopStatus() const override { return 0; } + int Bitrate() const override { return 0; } + int LoopNum() const override { return 0; } + int SamplesPerFrame() const override { return 0; } void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override; int AddStreamData(u32 bytesToAdd) override; @@ -31,6 +35,8 @@ public: u32 GetNextSamples() override; void InitLowLevel(u32 paramsAddr, bool jointStereo) override; + int GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const override; + private: int currentSample_ = 0; }; diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 66b80c6e80..e54e37524e 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -157,11 +157,15 @@ void __AtracDoState(PointerWrap &p) { } } -static AtracBase *allocAtrac(bool forceOld = false) { - if (g_Config.bUseExperimentalAtrac && !forceOld) { - return new Atrac2(); +static AtracBase *allocAtrac(int codecType = 0) { + if (g_Config.bUseExperimentalAtrac) { + return new Atrac2(codecType); } else { - return new Atrac(); + Atrac *atrac = new Atrac(); + if (codecType) { + atrac->GetTrackMut().codecType = codecType; + } + return atrac; } } @@ -205,8 +209,7 @@ static u32 sceAtracGetAtracID(int codecType) { return hleReportError(Log::ME, SCE_ERROR_ATRAC_INVALID_CODECTYPE, "invalid codecType"); } - AtracBase *atrac = allocAtrac(); - atrac->GetTrackMut().codecType = codecType; + AtracBase *atrac = allocAtrac(codecType); int atracID = createAtrac(atrac); if (atracID < 0) { delete atrac; @@ -325,10 +328,9 @@ static u32 sceAtracGetBitrate(int atracID, u32 outBitrateAddr) { return hleLogError(Log::ME, err); } - atrac->GetTrackMut().UpdateBitrate(); - + int bitrate = atrac->Bitrate(); if (Memory::IsValidAddress(outBitrateAddr)) { - Memory::WriteUnchecked_U32(atrac->GetTrack().bitrate, outBitrateAddr); + Memory::WriteUnchecked_U32(atrac->Bitrate(), outBitrateAddr); return hleLogDebug(Log::ME, 0); } else { return hleLogError(Log::ME, 0, "invalid address"); From a3b43d8283835333e2d4dd48c35757d12f19a92f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 16 Mar 2025 11:18:15 +0100 Subject: [PATCH 2/5] Refactor CurrentSample and ResetPlayPosition --- Core/HLE/AtracCtx.cpp | 32 ++++++++++++++++++++++++++------ Core/HLE/AtracCtx.h | 10 ++++------ Core/HLE/AtracCtx2.cpp | 3 ++- Core/HLE/AtracCtx2.h | 4 ++-- Core/HLE/sceAtrac.cpp | 36 +++++++++++++----------------------- UI/ImDebugger/ImDebugger.cpp | 10 +++++++--- 6 files changed, 54 insertions(+), 41 deletions(-) diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp index c6cccacabb..30dddc3ed2 100644 --- a/Core/HLE/AtracCtx.cpp +++ b/Core/HLE/AtracCtx.cpp @@ -554,6 +554,16 @@ int Atrac::GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSamp return 0; } +int Atrac::GetNextDecodePosition(int *pos) const { + if (currentSample_ >= track_.endSample) { + *pos = 0; + return SCE_ERROR_ATRAC_ALL_DATA_DECODED; + } else { + *pos = currentSample_; + return 0; + } +} + void Atrac::CalculateStreamInfo(u32 *outReadOffset) { u32 readOffset = first_.fileoffset; if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) { @@ -860,7 +870,7 @@ u32 Atrac::AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) { } u32 Atrac::GetNextSamples() { - if (CurrentSample() >= track_.endSample) { + if (currentSample_ >= track_.endSample) { return 0; } @@ -1114,16 +1124,24 @@ void AtracBase::SetLoopNum(int loopNum) { WriteContextToPSPMem(); } -u32 Atrac::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) { +int Atrac::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) { + *delay = false; + if (BufferState() == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && SecondBufferSize() == 0) { + return SCE_ERROR_ATRAC_SECOND_BUFFER_NEEDED; + } else if ((u32)sample + GetTrack().firstSampleOffset > (u32)GetTrack().endSample + GetTrack().firstSampleOffset) { + // NOTE: Above we have to add firstSampleOffset to both sides - we seem to rely on wraparound. + return SCE_ERROR_ATRAC_BAD_SAMPLE; + } + // Reuse the same calculation as before. AtracResetBufferInfo bufferInfo; GetResetBufferInfo(&bufferInfo, sample); if ((u32)bytesWrittenFirstBuf < bufferInfo.first.minWriteBytes || (u32)bytesWrittenFirstBuf > bufferInfo.first.writableBytes) { - return hleLogError(Log::ME, SCE_ERROR_ATRAC_BAD_FIRST_RESET_SIZE, "first byte count not in valid range"); + return SCE_ERROR_ATRAC_BAD_FIRST_RESET_SIZE; } if ((u32)bytesWrittenSecondBuf < bufferInfo.second.minWriteBytes || (u32)bytesWrittenSecondBuf > bufferInfo.second.writableBytes) { - return hleLogError(Log::ME, SCE_ERROR_ATRAC_BAD_SECOND_RESET_SIZE, "second byte count not in valid range"); + return SCE_ERROR_ATRAC_BAD_SECOND_RESET_SIZE; } if (bufferState_ == ATRAC_STATUS_ALL_DATA_LOADED) { @@ -1146,7 +1164,9 @@ u32 Atrac::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrit } } else { if (bufferInfo.first.filePos > track_.fileSize) { - return hleDelayResult(hleLogError(Log::ME, SCE_ERROR_ATRAC_API_FAIL, "invalid file position"), "reset play pos", 200); + *delay = true; + // The decoder failed during skip-frame operation. + return SCE_ERROR_ATRAC_API_FAIL; } // Move the offset to the specified position. @@ -1171,7 +1191,7 @@ u32 Atrac::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrit } WriteContextToPSPMem(); - return hleNoLog(0); + return 0; } void Atrac::InitLowLevel(u32 paramsAddr, bool jointStereo) { diff --git a/Core/HLE/AtracCtx.h b/Core/HLE/AtracCtx.h index 99d3eed7c9..f840de5183 100644 --- a/Core/HLE/AtracCtx.h +++ b/Core/HLE/AtracCtx.h @@ -220,7 +220,7 @@ public: void CreateDecoder(); - virtual int CurrentSample() const = 0; + virtual int GetNextDecodePosition(int *pos) const = 0; virtual int RemainingFrames() const = 0; virtual u32 SecondBufferSize() const = 0; virtual int Bitrate() const = 0; @@ -236,7 +236,7 @@ public: virtual int AddStreamData(u32 bytesToAdd) = 0; virtual u32 AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) = 0; virtual void SetLoopNum(int loopNum); - virtual u32 ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) = 0; + virtual int ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) = 0; virtual int GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) = 0; virtual int SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) = 0; @@ -282,9 +282,7 @@ public: int Analyze(u32 addr, u32 size) override; int AnalyzeAA3(u32 addr, u32 size, u32 filesize) override; - int CurrentSample() const override { - return currentSample_; - } + int GetNextDecodePosition(int *pos) const override; int RemainingFrames() const override; u32 SecondBufferSize() const override { return second_.size; @@ -315,7 +313,7 @@ public: // Notify the player that the user has written some new data. int AddStreamData(u32 bytesToAdd) override; u32 AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) override; - u32 ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) override; + int ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) override; int GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) override; int SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) override; u32 SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) override; diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index 76ee437225..acb3f23b4e 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -110,7 +110,8 @@ u32 Atrac2::AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) { return 0; } -u32 Atrac2::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) { +int Atrac2::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) { + *delay = false; return 0; } diff --git a/Core/HLE/AtracCtx2.h b/Core/HLE/AtracCtx2.h index fd24006390..b098e51403 100644 --- a/Core/HLE/AtracCtx2.h +++ b/Core/HLE/AtracCtx2.h @@ -14,7 +14,7 @@ public: int Analyze(u32 addr, u32 size) override; int AnalyzeAA3(u32 addr, u32 size, u32 filesize) override; - int CurrentSample() const override { return currentSample_; } + int GetNextDecodePosition(int *pos) const { return 0; } int RemainingFrames() const override; int LoopStatus() const override { return 0; } int Bitrate() const override { return 0; } @@ -24,7 +24,7 @@ public: void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override; int AddStreamData(u32 bytesToAdd) override; u32 AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) override; - u32 ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) override; + int ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) override; int GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) override; int SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) override; u32 SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) override; diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index e54e37524e..bfdc0c02b4 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -406,17 +406,18 @@ static u32 sceAtracGetNextDecodePosition(int atracID, u32 outposAddr) { return hleLogError(Log::ME, err); } - if (Memory::IsValidAddress(outposAddr)) { - if (atrac->CurrentSample() >= atrac->GetTrack().endSample) { - Memory::WriteUnchecked_U32(0, outposAddr); - return hleLogDebug(Log::ME, SCE_ERROR_ATRAC_ALL_DATA_DECODED, "all data decoded - beyond endSample"); - } else { - Memory::WriteUnchecked_U32(atrac->CurrentSample(), outposAddr); - return hleLogDebug(Log::ME, 0); - } - } else { + int pos = 0; + int ret = atrac->GetNextDecodePosition(&pos); + if (ret < 0) { + return hleLogError(Log::ME, ret); + } + + if (!Memory::IsValidAddress(outposAddr)) { return hleLogError(Log::ME, 0, "invalid address"); } + + Memory::WriteUnchecked_U32(pos, outposAddr); + return hleLogDebug(Log::ME, 0); } static u32 sceAtracGetNextSample(int atracID, u32 outNAddr) { @@ -547,20 +548,9 @@ static u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFi return hleLogError(Log::ME, err); } - if (atrac->BufferState() == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && atrac->SecondBufferSize() == 0) { - return hleReportError(Log::ME, SCE_ERROR_ATRAC_SECOND_BUFFER_NEEDED, "no second buffer"); - } else if ((u32)sample + atrac->GetTrack().firstSampleOffset > (u32)atrac->GetTrack().endSample + atrac->GetTrack().firstSampleOffset) { - // NOTE: Above we have to add firstSampleOffset to both sides - we seem to rely on wraparound. - return hleLogWarning(Log::ME, SCE_ERROR_ATRAC_BAD_SAMPLE, "invalid sample position"); - } - - u32 res = atrac->ResetPlayPosition(sample, bytesWrittenFirstBuf, bytesWrittenSecondBuf); - if (res != 0) { - // Already logged. - return res; - } - - return hleDelayResult(0, "reset play pos", 3000); + bool delay = false; + int res = atrac->ResetPlayPosition(sample, bytesWrittenFirstBuf, bytesWrittenSecondBuf, &delay); + return hleDelayResult(hleLogDebugOrError(Log::ME, res), "reset play pos", 3000 + delay ? 200 : 0); } static int _AtracSetData(int atracID, u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) { diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index bc466c5772..4b6806d046 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -999,7 +999,9 @@ void DrawAudioDecodersView(ImConfig &cfg, ImControl &control) { ImGui::TableNextColumn(); ImGui::Text("%d", ctx->GetOutputChannels()); ImGui::TableNextColumn(); - ImGui::Text("%d", ctx->CurrentSample()); + int pos; + ctx->GetNextDecodePosition(&pos); + ImGui::Text("%d", pos); ImGui::TableNextColumn(); ImGui::Text("%d", ctx->RemainingFrames()); } @@ -1014,9 +1016,11 @@ 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)) { - ImGui::ProgressBar((float)ctx->CurrentSample() / (float)ctx->GetTrack().endSample, ImVec2(200.0f, 0.0f)); + int pos; + ctx->GetNextDecodePosition(&pos); + ImGui::ProgressBar((float)pos / (float)ctx->GetTrack().endSample, ImVec2(200.0f, 0.0f)); ImGui::Text("Status: %s", AtracStatusToString(ctx->BufferState())); - ImGui::Text("cur/end sample: %d/%d", ctx->CurrentSample(), ctx->GetTrack().endSample); + ImGui::Text("cur/end sample: %d/%d", pos, ctx->GetTrack().endSample); ImGui::Text("ctx addr: "); ImGui::SameLine(); ImClickableValue("addr", ctx->Decoder()->GetCtxPtr(), control, ImCmd::SHOW_IN_MEMORY_VIEWER); ImGui::Text("loop: %d", ctx->LoopNum()); } From 3d143a0cba8b5c503a16c5ca1d598a3dd2169ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 16 Mar 2025 11:29:00 +0100 Subject: [PATCH 3/5] Finally get rid of the GetTrack() accessor --- Core/HLE/AtracCtx.cpp | 15 ++++++++++----- Core/HLE/AtracCtx.h | 20 ++++++++++++-------- Core/HLE/AtracCtx2.h | 3 +++ Core/HLE/sceAtrac.cpp | 30 +++++++++++++----------------- UI/ImDebugger/ImDebugger.cpp | 6 ++++-- 5 files changed, 42 insertions(+), 32 deletions(-) diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp index 30dddc3ed2..d9252c0aef 100644 --- a/Core/HLE/AtracCtx.cpp +++ b/Core/HLE/AtracCtx.cpp @@ -548,9 +548,9 @@ int Atrac::AnalyzeAA3(u32 addr, u32 size, u32 fileSize) { } int Atrac::GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const { - *endSample = GetTrack().endSample; - *loopStartSample = GetTrack().loopStartSample == -1 ? -1 : GetTrack().loopStartSample - GetTrack().FirstSampleOffsetFull(); - *loopEndSample = GetTrack().loopEndSample == -1 ? -1 : GetTrack().loopEndSample - GetTrack().FirstSampleOffsetFull(); + *endSample = track_.endSample; + *loopStartSample = track_.loopStartSample == -1 ? -1 : track_.loopStartSample - track_.FirstSampleOffsetFull(); + *loopEndSample = track_.loopEndSample == -1 ? -1 : track_.loopEndSample - track_.FirstSampleOffsetFull(); return 0; } @@ -1110,7 +1110,11 @@ u32 Atrac::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, i return 0; } -void AtracBase::SetLoopNum(int loopNum) { +int Atrac::SetLoopNum(int loopNum) { + if (track_.loopinfo.size() == 0) { + return SCE_ERROR_ATRAC_NO_LOOP_INFORMATION; + } + // Spammed in MHU loopNum_ = loopNum; // Logic here looks wacky? @@ -1122,13 +1126,14 @@ void AtracBase::SetLoopNum(int loopNum) { track_.loopEndSample = track_.endSample + track_.FirstSampleOffsetFull(); } WriteContextToPSPMem(); + return 0; } int Atrac::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) { *delay = false; if (BufferState() == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && SecondBufferSize() == 0) { return SCE_ERROR_ATRAC_SECOND_BUFFER_NEEDED; - } else if ((u32)sample + GetTrack().firstSampleOffset > (u32)GetTrack().endSample + GetTrack().firstSampleOffset) { + } else if ((u32)sample + track_.firstSampleOffset > (u32)track_.endSample + track_.firstSampleOffset) { // NOTE: Above we have to add firstSampleOffset to both sides - we seem to rely on wraparound. return SCE_ERROR_ATRAC_BAD_SAMPLE; } diff --git a/Core/HLE/AtracCtx.h b/Core/HLE/AtracCtx.h index f840de5183..e32ee428e0 100644 --- a/Core/HLE/AtracCtx.h +++ b/Core/HLE/AtracCtx.h @@ -184,13 +184,7 @@ public: virtual void DoState(PointerWrap &p) = 0; - const Track &GetTrack() const { - return track_; - } - - int Channels() const { - return track_.channels; - } + virtual int Channels() const = 0; int GetOutputChannels() const { return outputChannels_; @@ -209,8 +203,10 @@ public: return bufferState_; } + virtual int SetLoopNum(int loopNum) = 0; virtual int LoopNum() const = 0; virtual int LoopStatus() const = 0; + u32 CodecType() const { return track_.codecType; } @@ -224,6 +220,7 @@ public: virtual int RemainingFrames() const = 0; virtual u32 SecondBufferSize() const = 0; virtual int Bitrate() const = 0; + virtual int BytesPerFrame() const = 0; virtual int SamplesPerFrame() const = 0; virtual int Analyze(u32 addr, u32 size) = 0; @@ -235,7 +232,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 void SetLoopNum(int loopNum); virtual int ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) = 0; virtual int GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) = 0; virtual int SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) = 0; @@ -287,6 +283,9 @@ public: u32 SecondBufferSize() const override { return second_.size; } + int Channels() const override { + return track_.channels; + } int LoopNum() const override { return loopNum_; } @@ -299,6 +298,9 @@ public: int Bitrate() const override { return track_.Bitrate(); } + int BytesPerFrame() const override { + return track_.BytesPerFrame(); + } int SamplesPerFrame() const override { return track_.SamplesPerFrame(); } @@ -308,6 +310,8 @@ public: return track_; } + int SetLoopNum(int loopNum) override; + // Ask where in memory new data should be written. void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override; // Notify the player that the user has written some new data. diff --git a/Core/HLE/AtracCtx2.h b/Core/HLE/AtracCtx2.h index b098e51403..adc408b54b 100644 --- a/Core/HLE/AtracCtx2.h +++ b/Core/HLE/AtracCtx2.h @@ -20,6 +20,9 @@ public: int Bitrate() const override { return 0; } int LoopNum() const override { return 0; } int SamplesPerFrame() const override { return 0; } + int Channels() const override { return 2; } + int BytesPerFrame() const override { return 0; } + int SetLoopNum(int loopNum) override { return 0; } void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override; int AddStreamData(u32 bytesToAdd) override; diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index bfdc0c02b4..be1cd4a563 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -666,17 +666,13 @@ static u32 sceAtracSetLoopNum(int atracID, int loopNum) { if (err != 0) { return hleLogError(Log::ME, err); } - if (atrac->GetTrack().loopinfo.size() == 0) { - if (loopNum == -1) { - // This is very common and not really a problem. - return hleLogDebug(Log::ME, SCE_ERROR_ATRAC_NO_LOOP_INFORMATION, "no loop information to write to!"); - } else { - return hleLogError(Log::ME, SCE_ERROR_ATRAC_NO_LOOP_INFORMATION, "no loop information to write to!"); - } - } - atrac->SetLoopNum(loopNum); - return hleLogDebug(Log::ME, 0); + int ret = atrac->SetLoopNum(loopNum); + if (ret == SCE_ERROR_ATRAC_NO_LOOP_INFORMATION && loopNum == -1) { + // Not really an issue + return hleLogDebug(Log::ME, ret); + } + return hleLogDebugOrError(Log::ME, ret); } static int sceAtracReinit(int at3Count, int at3plusCount) { @@ -762,7 +758,7 @@ static int sceAtracSetMOutHalfwayBuffer(int atracID, u32 buffer, u32 readSize, u if (ret < 0) { return hleLogError(Log::ME, ret); } - if (atrac->GetTrack().channels != 1) { + if (atrac->Channels() != 1) { // It seems it still sets the data. atrac->SetData(buffer, readSize, bufferSize, 2); return hleReportError(Log::ME, SCE_ERROR_ATRAC_NOT_MONO, "not mono data"); @@ -784,7 +780,7 @@ static u32 sceAtracSetMOutData(int atracID, u32 buffer, u32 bufferSize) { if (ret < 0) { return hleLogError(Log::ME, ret); } - if (atrac->GetTrack().channels != 1) { + if (atrac->Channels() != 1) { // It seems it still sets the data. atrac->SetData(buffer, bufferSize, bufferSize, 2); return hleReportError(Log::ME, SCE_ERROR_ATRAC_NOT_MONO, "not mono data"); @@ -802,7 +798,7 @@ static int sceAtracSetMOutDataAndGetID(u32 buffer, u32 bufferSize) { delete atrac; return hleLogError(Log::ME, ret); } - if (atrac->GetTrack().channels != 1) { + if (atrac->Channels() != 1) { delete atrac; return hleReportError(Log::ME, SCE_ERROR_ATRAC_NOT_MONO, "not mono data"); } @@ -826,7 +822,7 @@ static int sceAtracSetMOutHalfwayBufferAndGetID(u32 buffer, u32 readSize, u32 bu delete atrac; return hleLogError(Log::ME, ret); } - if (atrac->GetTrack().channels != 1) { + if (atrac->Channels() != 1) { delete atrac; return hleReportError(Log::ME, SCE_ERROR_ATRAC_NOT_MONO, "not mono data"); } @@ -885,7 +881,7 @@ struct At3HeaderMap { u8 jointStereo; bool Matches(const AtracBase *at) const { - return bytes == at->GetTrack().BytesPerFrame() && channels == at->GetTrack().channels; + return bytes == at->BytesPerFrame() && channels == at->Channels(); } }; @@ -921,7 +917,7 @@ static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { } } if (!found) { - WARN_LOG_REPORT_ONCE(at3headermap, Log::ME, "AT3 header map lacks entry for bpf: %i channels: %i", atrac->GetTrack().BytesPerFrame(), atrac->GetTrack().channels); + WARN_LOG_REPORT_ONCE(at3headermap, Log::ME, "AT3 header map lacks entry for bpf: %i channels: %i", atrac->BytesPerFrame(), atrac->Channels()); // TODO: Should we return an error code for these values? } } @@ -929,7 +925,7 @@ static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { atrac->InitLowLevel(paramsAddr, jointStereo); const char *codecName = atrac->CodecType() == PSP_MODE_AT_3 ? "atrac3" : "atrac3+"; - const char *channelName = atrac->GetTrack().channels == 1 ? "mono" : "stereo"; + const char *channelName = atrac->Channels() == 1 ? "mono" : "stereo"; return hleLogInfo(Log::ME, 0, "%s %s audio", codecName, channelName); } diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index 4b6806d046..7de3997c17 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -1018,9 +1018,11 @@ void DrawAudioDecodersView(ImConfig &cfg, ImControl &control) { if (ctx && ImGui::CollapsingHeader(header, ImGuiTreeNodeFlags_DefaultOpen)) { int pos; ctx->GetNextDecodePosition(&pos); - ImGui::ProgressBar((float)pos / (float)ctx->GetTrack().endSample, ImVec2(200.0f, 0.0f)); + 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", pos, ctx->GetTrack().endSample); + ImGui::Text("cur/end sample: %d/%d", pos, endSample); ImGui::Text("ctx addr: "); ImGui::SameLine(); ImClickableValue("addr", ctx->Decoder()->GetCtxPtr(), control, ImCmd::SHOW_IN_MEMORY_VIEWER); ImGui::Text("loop: %d", ctx->LoopNum()); } From 6a4a46025b1151b35bacdcf9114bfa9bdf7089fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 16 Mar 2025 11:32:00 +0100 Subject: [PATCH 4/5] Remove now-unnecessary wrapper _AtracSetData --- Core/HLE/sceAtrac.cpp | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index be1cd4a563..554b166f43 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -553,15 +553,6 @@ static u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFi return hleDelayResult(hleLogDebugOrError(Log::ME, res), "reset play pos", 3000 + delay ? 200 : 0); } -static int _AtracSetData(int atracID, u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) { - AtracBase *atrac = getAtrac(atracID); - // Don't use AtracValidateManaged here. - if (!atrac) { - return SCE_ERROR_ATRAC_BAD_ATRACID; - } - return atrac->SetData(buffer, readSize, bufferSize, outputChannels); -} - static u32 sceAtracSetHalfwayBuffer(int atracID, u32 buffer, u32 readSize, u32 bufferSize) { AtracBase *atrac = getAtrac(atracID); // Don't use AtracValidateManaged here. @@ -578,7 +569,7 @@ static u32 sceAtracSetHalfwayBuffer(int atracID, u32 buffer, u32 readSize, u32 b return hleLogError(Log::ME, ret); } - ret = _AtracSetData(atracID, buffer, readSize, bufferSize, 2); + ret = atrac->SetData(buffer, readSize, bufferSize, 2); // not sure the real delay time return hleDelayResult(hleLogDebugOrError(Log::ME, ret), "atrac set data", 100); } @@ -608,7 +599,7 @@ static u32 sceAtracSetData(int atracID, u32 buffer, u32 bufferSize) { return hleReportError(Log::ME, SCE_ERROR_ATRAC_WRONG_CODECTYPE, "atracID uses different codec type than data"); } - ret = _AtracSetData(atracID, buffer, bufferSize, bufferSize, 2); + ret = atrac->SetData(buffer, bufferSize, bufferSize, 2); return hleDelayResult(hleLogDebugOrError(Log::ME, ret), "atrac set data", 100); } @@ -632,7 +623,7 @@ static int sceAtracSetDataAndGetID(u32 buffer, int bufferSize) { return hleLogError(Log::ME, atracID, "no free ID"); } - ret = _AtracSetData(atracID, buffer, bufferSize, bufferSize, 2); + ret = atrac->SetData(buffer, bufferSize, bufferSize, 2); return hleDelayResult(hleLogDebugOrError(Log::ME, ret == 0 ? atracID : ret), "atrac set data", 100); } @@ -651,7 +642,7 @@ static int sceAtracSetHalfwayBufferAndGetID(u32 buffer, u32 readSize, u32 buffer delete atrac; return hleLogError(Log::ME, atracID, "no free ID"); } - ret = _AtracSetData(atracID, buffer, readSize, bufferSize, 2); + ret = atrac->SetData(buffer, readSize, bufferSize, 2); return hleDelayResult(hleLogDebugOrError(Log::ME, ret == 0 ? atracID : ret), "atrac set data", 100); } @@ -763,7 +754,7 @@ static int sceAtracSetMOutHalfwayBuffer(int atracID, u32 buffer, u32 readSize, u atrac->SetData(buffer, readSize, bufferSize, 2); return hleReportError(Log::ME, SCE_ERROR_ATRAC_NOT_MONO, "not mono data"); } else { - ret = _AtracSetData(atracID, buffer, readSize, bufferSize, 1); + ret = atrac->SetData(buffer, readSize, bufferSize, 1); return hleDelayResult(hleLogDebugOrError(Log::ME, ret), "atrac set data mono", 100); } } @@ -785,7 +776,7 @@ static u32 sceAtracSetMOutData(int atracID, u32 buffer, u32 bufferSize) { atrac->SetData(buffer, bufferSize, bufferSize, 2); return hleReportError(Log::ME, SCE_ERROR_ATRAC_NOT_MONO, "not mono data"); } else { - ret = _AtracSetData(atracID, buffer, bufferSize, bufferSize, 1); + ret = atrac->SetData(buffer, bufferSize, bufferSize, 1); return hleDelayResult(hleLogDebugOrError(Log::ME, ret), "atrac set data mono", 100); } } @@ -808,7 +799,7 @@ static int sceAtracSetMOutDataAndGetID(u32 buffer, u32 bufferSize) { return hleLogError(Log::ME, atracID, "no free ID"); } - ret = _AtracSetData(atracID, buffer, bufferSize, bufferSize, 1); + ret = atrac->SetData(buffer, bufferSize, bufferSize, 1); return hleDelayResult(hleLogDebugOrError(Log::ME, ret == 0 ? atracID : ret), "atrac set data", 100); } @@ -832,7 +823,7 @@ static int sceAtracSetMOutHalfwayBufferAndGetID(u32 buffer, u32 readSize, u32 bu return hleLogError(Log::ME, atracID, "no free ID"); } - ret = _AtracSetData(atracID, buffer, readSize, bufferSize, 1); + ret = atrac->SetData(buffer, readSize, bufferSize, 1); return hleDelayResult(hleLogDebugOrError(Log::ME, ret == 0 ? atracID : ret), "atrac set data", 100); } @@ -849,7 +840,7 @@ static int sceAtracSetAA3DataAndGetID(u32 buffer, u32 bufferSize, u32 fileSize, return hleLogError(Log::ME, atracID, "no free ID"); } - ret = _AtracSetData(atracID, buffer, bufferSize, bufferSize, 2); + ret = atrac->SetData(buffer, bufferSize, bufferSize, 2); return hleDelayResult(hleLogDebugOrError(Log::ME, ret == 0 ? atracID : ret), "atrac set data", 100); } @@ -971,7 +962,7 @@ static int sceAtracSetAA3HalfwayBufferAndGetID(u32 buffer, u32 readSize, u32 buf return hleLogError(Log::ME, atracID, "no free ID"); } - ret = _AtracSetData(atracID, buffer, readSize, bufferSize, 2); + ret = atrac->SetData(buffer, readSize, bufferSize, 2); return hleDelayResult(hleLogDebugOrError(Log::ME, ret == 0 ? atracID : ret), "atrac set data", 100); } From c6ea7cfd152c7ac5fbd1a5502cb9674777370e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 16 Mar 2025 11:57:09 +0100 Subject: [PATCH 5/5] Delay fix --- Core/HLE/sceAtrac.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 554b166f43..18570c00c1 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -550,7 +550,14 @@ static u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFi bool delay = false; int res = atrac->ResetPlayPosition(sample, bytesWrittenFirstBuf, bytesWrittenSecondBuf, &delay); - return hleDelayResult(hleLogDebugOrError(Log::ME, res), "reset play pos", 3000 + delay ? 200 : 0); + if (res < 0) { + if (delay) { + return hleDelayResult(hleLogError(Log::ME, res), "reset play pos", 200); + } else { + return hleLogError(Log::ME, res); + } + } + return hleDelayResult(hleLogDebug(Log::ME, res), "reset play pos", 3000); } static u32 sceAtracSetHalfwayBuffer(int atracID, u32 buffer, u32 readSize, u32 bufferSize) {