From 70705d4a9df3556a0fcbfc50aaf78986831c81ba Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 21 Sep 2014 19:59:51 -0700 Subject: [PATCH 1/9] Remove incorrect atrac decode ptr nullcheck. Already shown in decode test to be valid. --- Core/HLE/sceAtrac.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 21392edece94..ea330a558de3 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -695,10 +695,8 @@ u32 _AtracDecodeData(int atracID, u8* outbuf, u32 *SamplesNum, u32* finish, int u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishFlagAddr, u32 remainAddr) { int ret = -1; - if (!Memory::IsValidAddress(outAddr)) { - ERROR_LOG(ME, "%08x=sceAtracDecodeData(%i, %08x, ...): Bad out addr, skipping", ret, atracID, outAddr); - return SCE_KERNEL_ERROR_ILLEGAL_ADDR; - } + + // Note that outAddr being null is completely valid here, used to skip data. u32 numSamples = 0; u32 finish = 0; From ac1fcdb26994eb960e01ebb196a298aba0202d25 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 21 Sep 2014 19:57:27 -0700 Subject: [PATCH 2/9] Skip samples in the first chunk of atrac output. This seems to be what the PSP actually does, although not sure. The first result is always smaller by this amount (numerous atrac files tested.) --- Core/HLE/sceAtrac.cpp | 87 ++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index ea330a558de3..6ed91460c81d 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -15,6 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" @@ -27,12 +28,22 @@ #include "Core/HW/BufferQueue.h" #include "Common/ChunkFile.h" -#include "sceKernel.h" -#include "sceUtility.h" -#include "sceKernelMemory.h" -#include "sceAtrac.h" - -#include +#include "Core/HLE/sceKernel.h" +#include "Core/HLE/sceUtility.h" +#include "Core/HLE/sceKernelMemory.h" +#include "Core/HLE/sceAtrac.h" + +// Notes about sceAtrac buffer management +// +// sceAtrac decodes from a buffer the game fills, where this buffer is one of: +// * Not yet initialized (state NO DATA = 1) +// * The entire size of the audio data, and filled with audio data (state ALL DATA LOADED = 2) +// * The entire size, but only partially filled so far (state HALFWAY BUFFER = 3) +// * Smaller than the audio, sliding without any loop (state STREAMED WITHOUT LOOP = 4) +// * Smaller than the audio, sliding with a loop at the end (state STREAMED WITH LOOP AT END = 5) +// * Smaller with a second buffer to help with a loop in the middle (state STREAMED WITH SECOND BUF = 6) +// * Not managed, decoding using "low level" manual looping etc. (LOW LEVEL = 8) +// * Not managed, reseved externally - possibly by sceSas - through low level (RESERVED = 16) #define ATRAC_ERROR_API_FAIL 0x80630002 #define ATRAC_ERROR_NO_ATRACID 0x80630003 @@ -108,7 +119,7 @@ struct AtracLoopInfo { struct Atrac { Atrac() : atracID(-1), data_buf(0), decodePos(0), decodeEnd(0), atracChannels(0), atracOutputChannels(2), atracBitrate(64), atracBytesPerFrame(0), atracBufSize(0), - currentSample(0), endSample(0), firstSampleoffset(0), + currentSample(0), endSample(0), firstSampleoffset(0), dataOff(0), loopinfoNum(0), loopStartSample(-1), loopEndSample(-1), loopNum(0), failedDecode(false), resetBuffer(false), codecType(0) { memset(&first, 0, sizeof(first)); @@ -142,7 +153,7 @@ struct Atrac { } void DoState(PointerWrap &p) { - auto s = p.Section("Atrac", 1 , 2); + auto s = p.Section("Atrac", 1, 3); if (!s) return; @@ -157,6 +168,11 @@ struct Atrac { p.Do(currentSample); p.Do(endSample); p.Do(firstSampleoffset); + if (s >= 3) { + p.Do(dataOff); + } else { + dataOff = firstSampleoffset; + } u32 has_data_buf = data_buf != NULL; p.Do(has_data_buf); @@ -229,8 +245,9 @@ struct Atrac { int currentSample; int endSample; - // Offset of the first sample in the input buffer int firstSampleoffset; + // Offset of the first sample in the input buffer + int dataOff; std::vector loopinfo; int loopinfoNum; @@ -421,7 +438,7 @@ int Atrac::Analyze() { first.filesize = Memory::Read_U32(first.addr + 4) + 8; u32 offset = 12; - int atracSampleoffset = 0; + firstSampleoffset = 0; this->decodeEnd = first.filesize; bool bfoundData = false; @@ -454,7 +471,7 @@ int Atrac::Analyze() { { if (chunkSize >= 8) { endSample = Memory::Read_U32(first.addr + offset); - atracSampleoffset = Memory::Read_U32(first.addr + offset + 4); + firstSampleoffset = Memory::Read_U32(first.addr + offset + 4); } } break; @@ -470,8 +487,8 @@ int Atrac::Analyze() { for (int i = 0; i < loopinfoNum; i++, loopinfoAddr += 24) { loopinfo[i].cuePointID = Memory::Read_U32(loopinfoAddr); loopinfo[i].type = Memory::Read_U32(loopinfoAddr + 4); - loopinfo[i].startSample = Memory::Read_U32(loopinfoAddr + 8) - atracSampleoffset; - loopinfo[i].endSample = Memory::Read_U32(loopinfoAddr + 12) - atracSampleoffset; + loopinfo[i].startSample = Memory::Read_U32(loopinfoAddr + 8) - firstSampleoffset; + loopinfo[i].endSample = Memory::Read_U32(loopinfoAddr + 12) - firstSampleoffset; loopinfo[i].fraction = Memory::Read_U32(loopinfoAddr + 16); loopinfo[i].playCount = Memory::Read_U32(loopinfoAddr + 20); @@ -484,7 +501,7 @@ int Atrac::Analyze() { case DATA_CHUNK_MAGIC: { bfoundData = true; - firstSampleoffset = offset; + dataOff = offset; } break; } @@ -603,6 +620,15 @@ u32 _AtracDecodeData(int atracID, u8* outbuf, u32 *SamplesNum, u32* finish, int // TODO: This isn't at all right, but at least it makes the music "last" some time. u32 numSamples = 0; u32 atracSamplesPerFrame = (atrac->codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); + + int skipSamples = 0; + if (atrac->currentSample == 0) { + // Some kind of header size? + u32 firstOffsetExtra = atrac->codecType == PSP_CODEC_AT3PLUS ? 368 : 69; + // It seems like the PSP aligns the sample position to 0x800...? + skipSamples = atrac->firstSampleoffset + firstOffsetExtra; + } + #ifdef USE_FFMPEG if (!atrac->failedDecode && (atrac->codecType == PSP_MODE_AT_3 || atrac->codecType == PSP_MODE_AT_3_PLUS) && atrac->pCodecCtx) { int forceseekSample = atrac->currentSample * 2 > atrac->endSample ? 0 : atrac->endSample; @@ -643,14 +669,31 @@ u32 _AtracDecodeData(int atracID, u8* outbuf, u32 *SamplesNum, u32* finish, int if (got_frame) { // got a frame // Use a small buffer and keep overwriting it with file data constantly - atrac->first.writableBytes += atrac->atracBytesPerFrame; - int decoded = av_samples_get_buffer_size(NULL, atrac->pFrame->channels, - atrac->pFrame->nb_samples, (AVSampleFormat)atrac->pFrame->format, 1); - u8 *out = outbuf; - if (out != NULL) { - numSamples = atrac->pFrame->nb_samples; - avret = swr_convert(atrac->pSwrCtx, &out, atrac->pFrame->nb_samples, - (const u8 **)atrac->pFrame->extended_data, atrac->pFrame->nb_samples); + atrac->first.writableBytes += atrac->atracBytesPerFrame; + int skipped = std::min(skipSamples, atrac->pFrame->nb_samples); + skipSamples -= skipped; + numSamples = atrac->pFrame->nb_samples - skipped; + atrac->currentSample += skipped; + + if (skipped > 0 && numSamples == 0) { + // Wait for the next one. + got_frame = 0; + } + + if (outbuf != NULL && numSamples != 0) { + int inbufOffset = 0; + if (skipped != 0) { + AVSampleFormat fmt = (AVSampleFormat)atrac->pFrame->format; + // We want the offset per channel. + inbufOffset = av_samples_get_buffer_size(NULL, 1, skipped, fmt, 1); + } + + u8 *out = outbuf; + const u8 *inbuf[2] = { + atrac->pFrame->extended_data[0] + inbufOffset, + atrac->pFrame->extended_data[1] + inbufOffset, + }; + avret = swr_convert(atrac->pSwrCtx, &out, numSamples, inbuf, numSamples); if (avret < 0) { ERROR_LOG(ME, "swr_convert: Error while converting %d", avret); } From 6b6bf3f8e6eecac8e3d73edae0de58eb873ee705 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 21 Sep 2014 20:11:05 -0700 Subject: [PATCH 3/9] Correct the dataOff member of atrac context. --- Core/HLE/sceAtrac.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 6ed91460c81d..3a4b7a61bf17 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -1663,7 +1663,7 @@ void _AtracGenarateContext(Atrac *atrac, SceAtracId *context) { context->info.samplesPerChan = (atrac->codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); context->info.sampleSize = atrac->atracBytesPerFrame; context->info.numChan = atrac->atracChannels; - context->info.dataOff = atrac->firstSampleoffset; + context->info.dataOff = atrac->dataOff; context->info.endSample = atrac->endSample; context->info.dataEnd = atrac->first.filesize; context->info.curOff = atrac->first.size; @@ -1815,6 +1815,7 @@ int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { } atrac->firstSampleoffset = headersize; + atrac->dataOff = headersize; atrac->first.size = headersize; atrac->first.filesize = headersize + atrac->atracBytesPerFrame; atrac->data_buf = new u8[atrac->first.filesize]; @@ -1839,6 +1840,7 @@ int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { } atrac->firstSampleoffset = headersize; + atrac->dataOff = headersize; atrac->first.size = headersize; atrac->first.filesize = headersize + atrac->atracBytesPerFrame; atrac->data_buf = new u8[atrac->first.filesize]; From 4702ae0e4192cd79bacee2506411268fe8aed609 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 22 Sep 2014 22:30:30 -0700 Subject: [PATCH 4/9] Add breakpoints to most sceAtrac mem access. --- Core/HLE/sceAtrac.cpp | 24 ++++++++++++++++++------ Core/HLE/sceAtrac.h | 4 ++-- Core/HLE/sceSas.cpp | 2 +- Core/HW/SasAudio.cpp | 6 +++--- Core/HW/SasAudio.h | 2 +- 5 files changed, 25 insertions(+), 13 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 3a4b7a61bf17..e33321ca9ef4 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -24,6 +24,7 @@ #include "Core/MemMap.h" #include "Core/Reporting.h" #include "Core/Config.h" +#include "Core/Debugger/Breakpoints.h" #include "Core/HW/MediaEngine.h" #include "Core/HW/BufferQueue.h" #include "Common/ChunkFile.h" @@ -549,12 +550,13 @@ u32 sceAtracGetAtracID(int codecType) { return atracID; } -u32 _AtracAddStreamData(int atracID, u8 *buf, u32 bytesToAdd) { +u32 _AtracAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd) { Atrac *atrac = getAtrac(atracID); if (!atrac) return 0; int addbytes = std::min(bytesToAdd, atrac->first.filesize - atrac->first.fileoffset); - memcpy(atrac->data_buf + atrac->first.fileoffset, buf, addbytes); + Memory::Memcpy(atrac->data_buf + atrac->first.fileoffset, bufPtr, addbytes); + CBreakPoints::ExecMemCheck(bufPtr, false, addbytes, currentMIPS->pc); atrac->first.size += bytesToAdd; if (atrac->first.size > atrac->first.filesize) atrac->first.size = atrac->first.filesize; @@ -590,6 +592,7 @@ u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd) { if (bytesToAdd > 0) { int addbytes = std::min(bytesToAdd, atrac->first.filesize - atrac->first.fileoffset); Memory::Memcpy(atrac->data_buf + atrac->first.fileoffset, atrac->first.addr + atrac->first.offset, addbytes); + CBreakPoints::ExecMemCheck(atrac->first.addr + atrac->first.offset, false, addbytes, currentMIPS->pc); } atrac->first.size += bytesToAdd; if (atrac->first.size > atrac->first.filesize) @@ -601,7 +604,7 @@ u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd) { return 0; } -u32 _AtracDecodeData(int atracID, u8* outbuf, u32 *SamplesNum, u32* finish, int *remains) { +u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u32 *finish, int *remains) { Atrac *atrac = getAtrac(atracID); u32 ret = 0; @@ -694,6 +697,10 @@ u32 _AtracDecodeData(int atracID, u8* outbuf, u32 *SamplesNum, u32* finish, int atrac->pFrame->extended_data[1] + inbufOffset, }; avret = swr_convert(atrac->pSwrCtx, &out, numSamples, inbuf, numSamples); + if (outbufPtr != 0) { + u32 outBytes = numSamples * atrac->atracOutputChannels * sizeof(s16); + CBreakPoints::ExecMemCheck(outbufPtr, true, outBytes, currentMIPS->pc); + } if (avret < 0) { ERROR_LOG(ME, "swr_convert: Error while converting %d", avret); } @@ -744,7 +751,7 @@ u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishF u32 numSamples = 0; u32 finish = 0; int remains = 0; - ret = _AtracDecodeData(atracID, Memory::GetPointer(outAddr), &numSamples, &finish, &remains); + ret = _AtracDecodeData(atracID, Memory::GetPointer(outAddr), outAddr, &numSamples, &finish, &remains); if (ret != (int)ATRAC_ERROR_BAD_ATRACID && ret != (int)ATRAC_ERROR_NO_DATA) { if (Memory::IsValidAddress(numSamplesAddr)) Memory::Write_U32(numSamples, numSamplesAddr); @@ -1237,7 +1244,9 @@ int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize) { #ifdef USE_FFMPEG atrac->data_buf = new u8[atrac->first.filesize]; - Memory::Memcpy(atrac->data_buf, buffer, std::min(bufferSize, atrac->first.filesize)); + u32 copybytes = std::min(bufferSize, atrac->first.filesize); + Memory::Memcpy(atrac->data_buf, buffer, copybytes); + CBreakPoints::ExecMemCheck(buffer, false, copybytes, currentMIPS->pc); return __AtracSetContext(atrac); #endif // USE_FFMPEG @@ -1248,7 +1257,9 @@ int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize) { WARN_LOG(ME, "This is an atrac3+ stereo audio"); } atrac->data_buf = new u8[atrac->first.filesize]; - Memory::Memcpy(atrac->data_buf, buffer, std::min(bufferSize, atrac->first.filesize)); + u32 copybytes = std::min(bufferSize, atrac->first.filesize); + Memory::Memcpy(atrac->data_buf, buffer, copybytes); + CBreakPoints::ExecMemCheck(buffer, false, copybytes, currentMIPS->pc); return __AtracSetContext(atrac); } @@ -1868,6 +1879,7 @@ int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesConsumedA u32 sourcebytes = atrac->first.writableBytes; if (sourcebytes > 0) { Memory::Memcpy(atrac->data_buf + atrac->first.size, sourceAddr, sourcebytes); + CBreakPoints::ExecMemCheck(sourceAddr, false, sourcebytes, currentMIPS->pc); if (atrac->decodePos >= atrac->first.size) { atrac->decodePos = atrac->first.size; } diff --git a/Core/HLE/sceAtrac.h b/Core/HLE/sceAtrac.h index 7039a02fe2f1..aa4d2789c3ef 100644 --- a/Core/HLE/sceAtrac.h +++ b/Core/HLE/sceAtrac.h @@ -66,6 +66,6 @@ typedef struct // provide some decoder interface -u32 _AtracAddStreamData(int atracID, u8 *buf, u32 bytesToAdd); -u32 _AtracDecodeData(int atracID, u8* outbuf, u32 *SamplesNum, u32* finish, int *remains); +u32 _AtracAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd); +u32 _AtracDecodeData(int atracID, u8* outbuf, u32 outbufPtr, u32 *SamplesNum, u32* finish, int *remains); int _AtracGetIDByContext(u32 contextAddr); \ No newline at end of file diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 08a4583bda12..af5c39208eb4 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -564,7 +564,7 @@ u32 __sceSasConcatenateATRAC3(u32 core, int voiceNum, u32 atrac3DataAddr, int at DEBUG_LOG_REPORT(SCESAS, "__sceSasConcatenateATRAC3(%08x, %i, %08x, %i)", core, voiceNum, atrac3DataAddr, atrac3DataLength); SasVoice &v = sas->voices[voiceNum]; if (Memory::IsValidAddress(atrac3DataAddr)) - v.atrac3.addStreamData(Memory::GetPointer(atrac3DataAddr), atrac3DataLength); + v.atrac3.addStreamData(atrac3DataAddr, atrac3DataLength); return 0; } diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index 6b9629625f92..e42137fe47ae 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -188,7 +188,7 @@ int SasAtrac3::getNextSamples(s16* outbuf, int wantedSamples) { u32 numSamples = 0; int remains = 0; static s16 buf[0x800]; - _AtracDecodeData(atracID, (u8*)buf, &numSamples, &finish, &remains); + _AtracDecodeData(atracID, (u8*)buf, 0, &numSamples, &finish, &remains); if (numSamples > 0) sampleQueue->push((u8*)buf, numSamples * sizeof(s16)); else @@ -198,9 +198,9 @@ int SasAtrac3::getNextSamples(s16* outbuf, int wantedSamples) { return finish; } -int SasAtrac3::addStreamData(u8* buf, u32 addbytes) { +int SasAtrac3::addStreamData(u32 bufPtr, u32 addbytes) { if (atracID > 0) { - _AtracAddStreamData(atracID, buf, addbytes); + _AtracAddStreamData(atracID, bufPtr, addbytes); } return 0; } diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index ac8daec92ac3..aa83623fc30d 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -126,7 +126,7 @@ class SasAtrac3 { ~SasAtrac3() { if (sampleQueue) delete sampleQueue; } int setContext(u32 context); int getNextSamples(s16* outbuf, int wantedSamples); - int addStreamData(u8* buf, u32 addbytes); + int addStreamData(u32 bufPtr, u32 addbytes); void DoState(PointerWrap &p); private: From 0aa7247feaaec564a4233ff502189a97a229d731 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 22 Sep 2014 23:18:33 -0700 Subject: [PATCH 5/9] Fix seeking in atrac after the start. Not sure the very start is right though, arg. --- Core/HLE/sceAtrac.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index e33321ca9ef4..4c42b6b3c253 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -624,19 +624,17 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 u32 numSamples = 0; u32 atracSamplesPerFrame = (atrac->codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); - int skipSamples = 0; - if (atrac->currentSample == 0) { - // Some kind of header size? - u32 firstOffsetExtra = atrac->codecType == PSP_CODEC_AT3PLUS ? 368 : 69; - // It seems like the PSP aligns the sample position to 0x800...? - skipSamples = atrac->firstSampleoffset + firstOffsetExtra; - } + // Some kind of header size? + u32 firstOffsetExtra = atrac->codecType == PSP_CODEC_AT3PLUS ? 368 : 69; + // It seems like the PSP aligns the sample position to 0x800...? + int offsetSamples = atrac->firstSampleoffset + firstOffsetExtra; + int skipSamples = atrac->currentSample == 0 ? offsetSamples : 0; #ifdef USE_FFMPEG if (!atrac->failedDecode && (atrac->codecType == PSP_MODE_AT_3 || atrac->codecType == PSP_MODE_AT_3_PLUS) && atrac->pCodecCtx) { int forceseekSample = atrac->currentSample * 2 > atrac->endSample ? 0 : atrac->endSample; atrac->SeekToSample(forceseekSample); - atrac->SeekToSample(atrac->currentSample); + atrac->SeekToSample(atrac->currentSample == 0 ? 0 : atrac->currentSample + offsetSamples); AVPacket packet; av_init_packet(&packet); int got_frame, avret; @@ -652,6 +650,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 if (avret == AVERROR_PATCHWELCOME) { ERROR_LOG(ME, "Unsupported feature in ATRAC audio."); // Let's try the next frame. + // TODO: Or actually, we should return a blank frame and pretend it worked. } else if (avret < 0) { ERROR_LOG(ME, "avcodec_decode_audio4: Error decoding audio %d", avret); av_free_packet(&packet); @@ -676,7 +675,6 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 int skipped = std::min(skipSamples, atrac->pFrame->nb_samples); skipSamples -= skipped; numSamples = atrac->pFrame->nb_samples - skipped; - atrac->currentSample += skipped; if (skipped > 0 && numSamples == 0) { // Wait for the next one. From 68f4a1e7f7f0826679f2d7afce1f950aca68b644 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 22 Sep 2014 23:19:03 -0700 Subject: [PATCH 6/9] Return the correct next sample at the beginning. --- Core/HLE/sceAtrac.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 4c42b6b3c253..c208e1d62e10 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -956,10 +956,18 @@ u32 sceAtracGetNextSample(int atracID, u32 outNAddr) { if (atrac->currentSample >= atrac->endSample) { if (Memory::IsValidAddress(outNAddr)) Memory::Write_U32(0, outNAddr); - return ATRAC_ERROR_ALL_DATA_DECODED; + return 0; } else { - u32 numSamples = atrac->endSample - atrac->currentSample; u32 atracSamplesPerFrame = (atrac->codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); + // Some kind of header size? + u32 firstOffsetExtra = atrac->codecType == PSP_CODEC_AT3PLUS ? 368 : 69; + // It seems like the PSP aligns the sample position to 0x800...? + u32 skipSamples = atrac->firstSampleoffset + firstOffsetExtra; + u32 firstSamples = (atracSamplesPerFrame - skipSamples) % atracSamplesPerFrame; + u32 numSamples = atrac->endSample - atrac->currentSample; + if (atrac->currentSample == 0) { + numSamples = firstSamples; + } if (numSamples > atracSamplesPerFrame) numSamples = atracSamplesPerFrame; if (Memory::IsValidAddress(outNAddr)) From fa42426d211159e0b413c97848ad2499047cd542 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 22 Sep 2014 23:21:08 -0700 Subject: [PATCH 7/9] Clamp the final sample count during decode. Some games depend on / expect this, or else they'll let important data get overwritten. --- Core/HLE/sceAtrac.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index c208e1d62e10..2949ef58979c 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -676,6 +676,9 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 skipSamples -= skipped; numSamples = atrac->pFrame->nb_samples - skipped; + // If we're at the end, clamp to samples we want. It always returns a full chunk. + numSamples = std::min((u32)atrac->endSample - (u32)atrac->currentSample, numSamples); + if (skipped > 0 && numSamples == 0) { // Wait for the next one. got_frame = 0; From e717a87f9fd5e6fbbaea3309c32d8fd326f1f9b7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 22 Sep 2014 23:21:08 -0700 Subject: [PATCH 8/9] Add extra frames if we run out of atrac data. We could probably insert frames instead for GHA phase shifting, but this will solve other bugs too, I think. --- Core/HLE/sceAtrac.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 2949ef58979c..7e4644adbbdb 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -637,7 +637,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 atrac->SeekToSample(atrac->currentSample == 0 ? 0 : atrac->currentSample + offsetSamples); AVPacket packet; av_init_packet(&packet); - int got_frame, avret; + int got_frame = 0, avret; while (av_read_frame(atrac->pFormatCtx, &packet) >= 0) { if (packet.stream_index != atrac->audio_stream_index) { av_free_packet(&packet); @@ -713,6 +713,15 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 break; } } + + if (!got_frame && atrac->currentSample < atrac->endSample) { + // Never got a frame. We may have dropped a GHA frame or otherwise have a bug. + // For now, let's try to provide an extra "frame" if possible so games don't infinite loop. + numSamples = std::min((u32)atrac->endSample - (u32)atrac->currentSample, atracSamplesPerFrame); + u32 outBytes = numSamples * atrac->atracOutputChannels * sizeof(s16); + memset(outbuf, 0, outBytes); + CBreakPoints::ExecMemCheck(outbufPtr, true, outBytes, currentMIPS->pc); + } } #endif // USE_FFMPEG From 0ebe5325d4cc749ca5e9a8db264e8cdfe1f37a24 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 23 Sep 2014 09:08:40 -0700 Subject: [PATCH 9/9] Correct the end from sceAtracGetSoundSample(). I think it's meant to be the last *valid* sample. --- Core/HLE/sceAtrac.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 7e4644adbbdb..fe0702220c64 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -1039,7 +1039,7 @@ u32 sceAtracGetSoundSample(int atracID, u32 outEndSampleAddr, u32 outLoopStartSa } else { DEBUG_LOG(ME, "sceAtracGetSoundSample(%i, %08x, %08x, %08x)", atracID, outEndSampleAddr, outLoopStartSampleAddr, outLoopEndSampleAddr); if (Memory::IsValidAddress(outEndSampleAddr)) - Memory::Write_U32(atrac->endSample, outEndSampleAddr); + Memory::Write_U32(atrac->endSample - 1, outEndSampleAddr); if (Memory::IsValidAddress(outLoopStartSampleAddr)) Memory::Write_U32(atrac->loopStartSample, outLoopStartSampleAddr); if (Memory::IsValidAddress(outLoopEndSampleAddr))