diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index 97372e6522..3e12e91bd3 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -27,6 +27,11 @@ // cmd1> C:\dev\ppsspp\pspautotests\tests\audio\atrac>copy /Y ..\..\..\__testoutput.txt stream.expected // Then run the test, see above. +// Needs to support negative numbers, and to handle non-powers-of-two. +static int RoundDownToMultiple(int x, int n) { + return (x % n == 0) ? x : x - (x % n) - (n * (x < 0)); +} + Atrac2::Atrac2(int atracID, u32 contextAddr, int codecType) { context_ = PSPPointer::Create(contextAddr); track_.codecType = codecType; @@ -110,6 +115,7 @@ int Atrac2::GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSam int Atrac2::ResetPlayPosition(int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf, bool *delay) { *delay = false; + // This was mostly copied straight from the old impl. // Reuse the same calculation as before. @@ -231,7 +237,7 @@ int Atrac2::GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) { int sampleFileOffset = track_.FileOffsetBySample(sample - track_.firstSampleOffset - track_.SamplesPerFrame()); // Update the writable bytes. When streaming, this is just the number of bytes until the end. - const u32 bufSizeAligned = (info.bufferByte / track_.bytesPerFrame) * track_.bytesPerFrame; + const u32 bufSizeAligned = RoundDownToMultiple(info.bufferByte, track_.bytesPerFrame); const int needsMoreFrames = track_.FirstOffsetExtra(); // ? bufferInfo->first.writePosPtr = info.buffer; @@ -311,10 +317,6 @@ int Atrac2::AddStreamData(u32 bytesToAdd) { return 0; } -int RoundDownToMultiple(int x, int n) { - return (x % n == 0) ? x : x - (x % n) - (n * (x < 0)); -} - void Atrac2::GetStreamDataInfo(u32 *writePtr, u32 *bytesToRead, u32 *readFileOffset) { const SceAtracIdInfo &info = context_->info; @@ -391,9 +393,10 @@ void Atrac2::GetStreamDataInfo(u32 *writePtr, u32 *bytesToRead, u32 *readFileOff *writePtr = info.buffer + secondPart; *bytesToRead = std::min(spaceLeft, bytesLeftInFile); } else { - // We always start aligned at the start of the buffer. So, when computing the space left, - // we just shrink the buffer so it's an even number of frames, then compute the free space. - const int spaceLeft = RoundDownToMultiple(info.bufferByte, info.sampleSize) - writePos; + // In case the buffer is only partially filled at the start, we can be off packet alignment here! + // But otherwise, we normally are actually on alignment. + int size = info.streamOff + RoundDownToMultiple(info.bufferByte - info.streamOff, info.sampleSize); + const int spaceLeft = size - writePos; *writePtr = info.buffer + writePos; *bytesToRead = std::min(spaceLeft, bytesLeftInFile); @@ -582,16 +585,23 @@ int Atrac2::SetData(const Track &track, u32 bufferAddr, u32 readSize, u32 buffer discardedSamples_ -= outSamples; } - // We need to handle wrapping the overshot partial packet at the end. Let's start by computing it. + // We need to handle wrapping the overshot partial packet at the end. if (AtracStatusIsStreaming(info.state)) { - // curOff also works (instead of streamOff) of course since it's also packet aligned, unlike the buffer size. - const int cutLen = (info.bufferByte - info.streamOff) % info.sampleSize; - const int cutRest = info.sampleSize - cutLen; - - // Then, let's copy it. - if (cutLen > 0) { + // This logic is similar to GetStreamDataInfo. + const int lastPacketStart = info.bufferByte - info.sampleSize; // Last possible place in the buffer to put the next packet + const int writePos = info.streamOff + info.streamDataByte; + if (writePos > lastPacketStart) { + // curOff also works (instead of streamOff) of course since it's also packet aligned, unlike the buffer size. + const int cutLen = (info.bufferByte - info.streamOff) % info.sampleSize; + const int cutRest = info.sampleSize - cutLen; + _dbg_assert_(cutLen > 0); + // Then, let's copy it. INFO_LOG(Log::ME, "Streaming: Packets didn't fit evenly. Last packet got split into %d/%d (sum=%d). Copying to start of buffer.", cutLen, cutRest, cutLen, cutRest, info.sampleSize); Memory::Memcpy(info.buffer, info.buffer + info.bufferByte - cutLen, cutLen); + } else { + INFO_LOG(Log::ME, "Streaming: Packets fit into the buffer fully. %08x < %08x", readSize, bufferSize); + // In this case, seems we need to zero some bytes. In testing, this seems to be 336. + Memory::Memset(info.buffer, 0, 128); } } diff --git a/Core/HLE/sceAtrac.h b/Core/HLE/sceAtrac.h index 5509007c1f..64c69fb608 100644 --- a/Core/HLE/sceAtrac.h +++ b/Core/HLE/sceAtrac.h @@ -76,7 +76,7 @@ struct SceAtracIdInfo { u32_le dataEnd; // 36 s32_le loopNum; // 40 u32_le streamDataByte; // 44 // Amount of queued data. In half-way mode, this isn't decremented per block. - u32_le streamOff; // Previously unk48. this appears to possibly be the offset inside the buffer for streaming. + u32_le streamOff; // Previously unk48. this appears to possibly be the offset inside the buffer for streaming. Only points to even packets, never points between them! u32_le unk52; u32_le buffer; // 56 u32_le secondBuffer; // 60