From 724fc1dd95430de78100d4f20f3b97f0d6b5c2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 9 Mar 2025 10:44:33 +0100 Subject: [PATCH] Work on the new implementation. --- Core/HLE/AtracCtx.h | 10 +- Core/HLE/AtracCtx2.cpp | 243 ++++++++++++++++++++++++++++++++++++----- Core/HLE/AtracCtx2.h | 28 +++-- Core/HLE/sceAtrac.h | 4 +- 4 files changed, 246 insertions(+), 39 deletions(-) diff --git a/Core/HLE/AtracCtx.h b/Core/HLE/AtracCtx.h index ae292b748f..ccd4fcfbd9 100644 --- a/Core/HLE/AtracCtx.h +++ b/Core/HLE/AtracCtx.h @@ -192,9 +192,7 @@ public: PSPPointer context_{}; - AtracStatus BufferState() const { - return bufferState_; - } + virtual AtracStatus BufferState() const = 0; virtual int SetLoopNum(int loopNum) = 0; virtual int LoopNum() const = 0; @@ -241,7 +239,6 @@ protected: // TODO: Save the internal state of this, now technically possible. AudioDecoder *decoder_ = nullptr; - AtracStatus bufferState_ = ATRAC_STATUS_NO_DATA; }; class Atrac : public AtracBase { @@ -264,6 +261,10 @@ public: u8 *BufferStart(); + AtracStatus BufferState() const { + return bufferState_; + } + void DoState(PointerWrap &p) override; int GetNextDecodePosition(int *pos) const override; @@ -357,4 +358,5 @@ private: u32 bufferHeaderSize_ = 0; int atracID_ = -1; + AtracStatus bufferState_ = ATRAC_STATUS_NO_DATA; }; diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index 3ed3e91a0b..e6ae0e1d86 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -15,6 +15,8 @@ Atrac2::Atrac2(int atracID, u32 contextAddr, int codecType) { context_ = PSPPointer::Create(contextAddr); track_.codecType = codecType; context_->info.codec = codecType; + context_->info.atracID = atracID; + context_->info.state = ATRAC_STATUS_NO_DATA; } void Atrac2::DoState(PointerWrap &p) { @@ -22,22 +24,53 @@ void Atrac2::DoState(PointerWrap &p) { } int Atrac2::RemainingFrames() const { - return 0; + const SceAtracIdInfo &info = context_->info; + + if (info.state == ATRAC_STATUS_ALL_DATA_LOADED) { + // The buffer contains everything. + return PSP_ATRAC_ALLDATA_IS_ON_MEMORY; + } + + const bool isStreaming = (info.state & ATRAC_STATUS_STREAMED_MASK) != 0; + + if (info.decodePos >= track_.endSample) { + if (info.state == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) { + return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY; + } + int loopEndAdjusted = track_.loopEndSample - track_.FirstOffsetExtra() - track_.firstSampleOffset; + if (info.state == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER && info.decodePos > loopEndAdjusted) { + // No longer looping in this case, outside the loop. + return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY; + } + if (isStreaming && loopNum_ == 0) { + return PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY; + } + return info.streamDataByte / info.sampleSize; + } + + if (isStreaming) { + // Since we're streaming, the remaining frames are what's valid in the buffer. + return info.streamDataByte / info.sampleSize; + } + + // Fallback + return info.dataEnd / info.sampleSize; } u32 Atrac2::SecondBufferSize() const { - return 0; -} - -void Atrac2::GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) { - -} - -int Atrac2::AddStreamData(u32 bytesToAdd) { - return 0; + const SceAtracIdInfo &info = context_->info; + return info.secondBufferByte; } u32 Atrac2::AddStreamDataSas(u32 bufPtr, u32 bytesToAdd) { + _dbg_assert_(false); + return 0; +} + +int Atrac2::GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const { + *endSample = track_.endSample; + *loopStartSample = track_.loopStartSample == -1 ? -1 : track_.loopStartSample - track_.FirstSampleOffsetFull(); + *loopEndSample = track_.loopEndSample == -1 ? -1 : track_.loopEndSample - track_.FirstSampleOffsetFull(); return 0; } @@ -47,19 +80,158 @@ int Atrac2::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWri } int Atrac2::GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) { + _dbg_assert_(false); return 0; } -int Atrac2::GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const { - return 0; -} - -int Atrac2::SetData(const Track &track, u32 buffer, u32 readSize, u32 bufferSize, int outputChannels) { - if (readSize == bufferSize) { - bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; - } else { - bufferState_ = ATRAC_STATUS_HALFWAY_BUFFER; +int Atrac2::SetLoopNum(int loopNum) { + SceAtracIdInfo &info = context_->info; + if (info.loopEnd <= 0) { + return SCE_ERROR_ATRAC_NO_LOOP_INFORMATION; } + info.loopNum = loopNum; + return 0; +} + +u32 Atrac2::GetNextSamples() { + // This has to be possible to do in an easier way, from the existing state. + + int currentSample = context_->info.decodePos; + // It seems like the PSP aligns the sample position to 0x800...? + u32 skipSamples = track_.FirstSampleOffsetFull(); + u32 firstSamples = (track_.SamplesPerFrame() - skipSamples) % track_.SamplesPerFrame(); + u32 numSamples = track_.endSample + 1 - currentSample; + if (currentSample == 0 && firstSamples != 0) { + numSamples = firstSamples; + } + u32 unalignedSamples = (skipSamples + currentSample) % track_.SamplesPerFrame(); + if (unalignedSamples != 0) { + // We're off alignment, possibly due to a loop. Force it back on. + numSamples = track_.SamplesPerFrame() - unalignedSamples; + } + if (numSamples > track_.SamplesPerFrame()) + numSamples = track_.SamplesPerFrame(); + return numSamples; +} + +int Atrac2::AddStreamData(u32 bytesToAdd) { + SceAtracIdInfo &info = context_->info; + // if (bytesToAdd > first_.writableBytes) + // return SCE_ERROR_ATRAC_ADD_DATA_IS_TOO_BIG; + info.streamDataByte += bytesToAdd; + return 0; +} + +void Atrac2::GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) { + SceAtracIdInfo &info = context_->info; + + *readOffset = info.bufferByte; + *writePtr = context_->codec.inBuf + info.curOff; + + *writableBytes = 0; + // Probably we treat +} + +u32 Atrac2::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) { + SceAtracIdInfo &info = context_->info; + + if (!decodeTemp_) { + decodeTemp_ = new int16_t[track_.SamplesPerFrame() * track_.channels]; + } + + /* + const uint8_t *indata = Memory::GetPointer(context_->codec.inBuf + info.curOff); + int bytesConsumed = 0; + int outSamples = 0; + if (!decoder_->Decode(indata, track_.bytesPerFrame, &bytesConsumed, outputChannels_, decodeTemp_, &outSamples)) { + // Decode failed. + *SamplesNum = 0; + *finish = 1; + // Is this the right error code? Needs testing. + return SCE_ERROR_ATRAC_ALL_DATA_DECODED; + } + */ + + info.streamDataByte -= info.sampleSize; + info.curOff += info.sampleSize; + info.decodePos += track_.SamplesPerFrame(); + + // This one starts out being the same as curOff but sometimes gets reset?? + info.unk48 += info.sampleSize; + + *remains = RemainingFrames(); + return 0; +} + +int Atrac2::SetData(const Track &track, u32 bufferAddr, u32 readSize, u32 bufferSize, int outputChannels) { + // TODO: Remove track_. + track_ = track; + + if (track_.codecType != PSP_MODE_AT_3 && track_.codecType != PSP_MODE_AT_3_PLUS) { + // Shouldn't have gotten here, Analyze() checks this. + context_->info.state = ATRAC_STATUS_NO_DATA; + ERROR_LOG(Log::ME, "unexpected codec type %d in set data", track_.codecType); + return SCE_ERROR_ATRAC_UNKNOWN_FORMAT; + } + + if (outputChannels != track_.channels) { + // TODO: Figure out what this means + WARN_LOG(Log::ME, "Atrac::SetData: outputChannels %d doesn't match track_.channels %d", outputChannels, track_.channels); + } + + context_->codec.inBuf = bufferAddr; + + // Copied from the old implementation, let's see where they are useful. + int bufOff = track_.dataByteOffset + track_.bytesPerFrame; + int skipSamples = track_.FirstSampleOffsetFull(); + int firstExtra = track_.FirstOffsetExtra(); + + SceAtracIdInfo &info = context_->info; + // Copy parameters into struct. + info.buffer = bufferAddr; + info.bufferByte = bufferSize; + info.samplesPerChan = track_.FirstSampleOffsetFull(); // TODO: Where does 970 come from? + info.endSample = track_.endSample + info.samplesPerChan; + if (track_.loopStartSample != 0xFFFFFFFF) { + info.loopStart = track_.loopStartSample; + info.loopEnd = track_.loopEndSample; + } + info.codec = track_.codecType; + info.sampleSize = track_.bytesPerFrame; + info.numChan = track_.channels; + info.numFrame = 0; + info.dataOff = track_.dataByteOffset; + info.curOff = 0x1D8; // 472 + info.unk48 = info.curOff; + info.streamDataByte = readSize - info.curOff; + info.dataEnd = track_.fileSize; + + if (readSize > track_.fileSize) { + WARN_LOG(Log::ME, "readSize %d > track_.fileSize", readSize, track_.fileSize); + readSize = track_.fileSize; + } + + if (bufferSize >= track_.fileSize) { + // Buffer is big enough to fit the whole track. + if (readSize < bufferSize) { + info.state = ATRAC_STATUS_HALFWAY_BUFFER; + } else { + info.state = ATRAC_STATUS_ALL_DATA_LOADED; + } + } else { + // Streaming cases with various looping types. + if (track_.loopEndSample <= 0) { + // There's no looping, but we need to stream the data in our buffer. + info.state = ATRAC_STATUS_STREAMED_WITHOUT_LOOP; + } else if (track_.loopEndSample == track_.endSample + track_.FirstSampleOffsetFull()) { + info.state = ATRAC_STATUS_STREAMED_LOOP_FROM_END; + } else { + info.state = ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER; + } + } + + CreateDecoder(); + return 0; } @@ -67,16 +239,37 @@ u32 Atrac2::SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) { return 0; } -u32 Atrac2::DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) { +int Atrac2::Bitrate() const { + const SceAtracIdInfo &info = context_->info; - return 0; -} - -u32 Atrac2::GetNextSamples() { - return 0; + int bitrate = (info.sampleSize * 352800) / 1000; + if (info.codec == PSP_MODE_AT_3_PLUS) + bitrate = ((bitrate >> 11) + 8) & 0xFFFFFFF0; + else + bitrate = (bitrate + 511) >> 10; + return bitrate; } void Atrac2::InitLowLevel(u32 paramsAddr, bool jointStereo, int codecType) { + track_ = Track(); + track_.codecType = codecType; + track_.channels = Memory::Read_U32(paramsAddr); + outputChannels_ = Memory::Read_U32(paramsAddr + 4); + track_.bytesPerFrame = Memory::Read_U32(paramsAddr + 8); + if (track_.codecType == PSP_MODE_AT_3) { + track_.bitrate = (track_.bytesPerFrame * 352800) / 1000; + track_.bitrate = (track_.bitrate + 511) >> 10; + track_.jointStereo = false; + } else if (track_.codecType == PSP_MODE_AT_3_PLUS) { + track_.bitrate = (track_.bytesPerFrame * 352800) / 1000; + track_.bitrate = ((track_.bitrate >> 11) + 8) & 0xFFFFFFF0; + track_.jointStereo = false; + } + track_.dataByteOffset = 0; + + context_->info.decodePos = 0; + context_->info.state = ATRAC_STATUS_LOW_LEVEL; + CreateDecoder(); } int Atrac2::DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) { diff --git a/Core/HLE/AtracCtx2.h b/Core/HLE/AtracCtx2.h index b2afd4614e..e17ed2719f 100644 --- a/Core/HLE/AtracCtx2.h +++ b/Core/HLE/AtracCtx2.h @@ -7,20 +7,28 @@ class Atrac2 : public AtracBase { public: Atrac2(int atracID, u32 contextAddr, int codecType); + ~Atrac2() { + delete[] decodeTemp_; + } + + AtracStatus BufferState() const { + return context_->info.state; + } void DoState(PointerWrap &p) override; - int GetID() const override { return 0; } + int GetID() const override { return context_->info.atracID; } + + int GetNextDecodePosition(int *pos) const override { return context_->info.decodePos; } - int GetNextDecodePosition(int *pos) const { return 0; } int RemainingFrames() const override; int LoopStatus() const override { return 0; } - int Bitrate() const override { return 0; } - int LoopNum() const override { return 0; } + int Bitrate() const override; + int LoopNum() const override { return context_->info.loopNum; } 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; } + int Channels() const override { return context_->info.numChan; } + int BytesPerFrame() const override { return context_->info.sampleSize; } + int SetLoopNum(int loopNum) override; void GetStreamDataInfo(u32 *writePtr, u32 *writableBytes, u32 *readOffset) override; int AddStreamData(u32 bytesToAdd) override; @@ -34,6 +42,7 @@ public: u32 DecodeData(u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) override; int DecodeLowLevel(const u8 *srcData, int *bytesConsumed, s16 *dstData, int *bytesWritten) override; u32 GetNextSamples() override; + void InitLowLevel(u32 paramsAddr, bool jointStereo, int codecType) override; int GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const override; @@ -43,5 +52,8 @@ public: void NotifyGetContextAddress() override {} private: - int currentSample_ = 0; + // Just the current decoded frame, in order to be able to cut off the first part of it + // to write the initial partial frame. + // Does not need to be saved. + int16_t *decodeTemp_ = nullptr; }; diff --git a/Core/HLE/sceAtrac.h b/Core/HLE/sceAtrac.h index 316a1acb9c..040e5a66d1 100644 --- a/Core/HLE/sceAtrac.h +++ b/Core/HLE/sceAtrac.h @@ -58,7 +58,7 @@ struct SceAtracIdInfo { u32_le endSample; // 4 u32_le loopStart; // 8 u32_le loopEnd; // 12 - s32_le samplesPerChan; // 16 + s32_le samplesPerChan; // 16 // This rather seems to be the number of skipped samples at the start. (plus one frame?) char numFrame; // 20 // 2: all the stream data on the buffer // 6: looping -> second buffer needed @@ -79,7 +79,7 @@ struct SceAtracIdInfo { u32_le bufferByte; // 64 u32_le secondBufferByte; // 68 // make sure the size is 128 - u8 unk[52]; + u32_le unk[13]; u32_le atracID; };