From 9ebc9f695e45fc503a7aa73e7cf75a8af3930c8e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Nov 2015 11:27:06 -0800 Subject: [PATCH 1/9] Atrac: Clean up logging in sceAtracGetRemainFrame. --- Core/HLE/sceAtrac.cpp | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index a6410cf6e3..6569d5097d 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -1139,6 +1139,8 @@ static void AtracGetResetBufferInfo(Atrac *atrac, AtracResetBufferInfo *bufferIn bufferInfo->second.filePos = atrac->second.fileoffset; } +// Obtains information about what needs to be in the buffer to seek (or "reset") +// Generally called by games right before calling sceAtracResetPlayPosition(). static u32 sceAtracGetBufferInfoForResetting(int atracID, int sample, u32 bufferInfoAddr) { auto bufferInfo = PSPPointer::Create(bufferInfoAddr); @@ -1320,24 +1322,24 @@ static u32 sceAtracGetNextSample(int atracID, u32 outNAddr) { return 0; } +// Obtains the number of frames remaining in the buffer which can be decoded. +// When no more data would be needed, this returns a negative number. static u32 sceAtracGetRemainFrame(int atracID, u32 remainAddr) { + auto remainingFrames = PSPPointer::Create(remainAddr); + Atrac *atrac = getAtrac(atracID); if (!atrac) { - ERROR_LOG(ME, "sceAtracGetRemainFrame(%i, %08x): bad atrac ID", atracID, remainAddr); - return ATRAC_ERROR_BAD_ATRACID; + return hleLogError(ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); } else if (!atrac->data_buf) { - ERROR_LOG(ME, "sceAtracGetRemainFrame(%i, %08x): no data", atracID, remainAddr); - return ATRAC_ERROR_NO_DATA; + return hleLogError(ME, ATRAC_ERROR_NO_DATA, "no data"); + } else if (!remainingFrames.IsValid()) { + return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid remainingFrames pointer"); } else { - if (Memory::IsValidAddress(remainAddr)) { - Memory::Write_U32(atrac->getRemainFrames(), remainAddr); - DEBUG_LOG(ME, "sceAtracGetRemainFrame(%i, %08x[%d])", atracID, remainAddr, atrac->getRemainFrames()); - } - else - DEBUG_LOG_REPORT(ME, "sceAtracGetRemainFrame(%i, %08x[%d]) invalid address", atracID, remainAddr, atrac->getRemainFrames()); - // Let sceAtracGetStreamDataInfo() know to set the full filled buffer . - atrac->resetBuffer = true; + *remainingFrames = atrac->getRemainFrames(); + // Let sceAtracGetStreamDataInfo() know to set the full filled buffer. + atrac->resetBuffer = true; + return hleLogSuccessI(ME, 0); } return 0; } @@ -1437,6 +1439,9 @@ static u32 sceAtracReleaseAtracID(int atracID) { return deleteAtrac(atracID); } +// This is called when a game wants to seek (or "reset") to a specific position in the audio data. +// Normally, sceAtracGetBufferInfoForResetting() is called to determine how to buffer. +// The game must add sufficient packets to the buffer in order to complete the seek. static u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFirstBuf, int bytesWrittenSecondBuf) { Atrac *atrac = getAtrac(atracID); if (!atrac) { @@ -2346,7 +2351,7 @@ const HLEFunction sceAtrac3plus[] = { {0XD6A5F2F7, &WrapU_IU, "sceAtracGetMaxSample", 'x', "ix" }, {0XE23E3A35, &WrapU_IU, "sceAtracGetNextDecodePosition", 'x', "ix" }, {0X36FAABFB, &WrapU_IU, "sceAtracGetNextSample", 'x', "ix" }, - {0X9AE849A7, &WrapU_IU, "sceAtracGetRemainFrame", 'x', "ix" }, + {0X9AE849A7, &WrapU_IU, "sceAtracGetRemainFrame", 'x', "ip" }, {0X83E85EA0, &WrapU_IUU, "sceAtracGetSecondBufferInfo", 'x', "ixx" }, {0XA2BBA8BE, &WrapU_IUUU, "sceAtracGetSoundSample", 'x', "ixxx" }, {0X5D268707, &WrapU_IUUU, "sceAtracGetStreamDataInfo", 'x', "ixxx" }, From 26a81f5179268da7a72cc1b9594f35535f784cee Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Nov 2015 11:55:48 -0800 Subject: [PATCH 2/9] Atrac: Simplify USE_FFMPEG checks. Maybe we should just remove the option, but this way the behavior is a lot more similar. --- Core/HLE/sceAtrac.cpp | 64 ++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 6569d5097d..d47230d929 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -131,6 +131,14 @@ struct AtracLoopInfo { int playCount; }; +#ifndef USE_FFMPEG +struct AVPacket { + uint8_t *data; + int size; + int64_t pos; +}; +#endif + struct Atrac { Atrac() : atracID(-1), data_buf(0), decodePos(0), decodeEnd(0), bufferPos(0), atracChannels(0),atracOutputChannels(2), @@ -338,8 +346,10 @@ struct Atrac { AVCodecContext *pCodecCtx; SwrContext *pSwrCtx; AVFrame *pFrame; +#endif // USE_FFMPEG AVPacket *packet; +#ifdef USE_FFMPEG void ReleaseFFMPEGContext() { // All of these allow null pointers. av_freep(&pFrame); @@ -358,9 +368,12 @@ struct Atrac { delete packet; packet = nullptr; } +#endif // USE_FFMPEG void ForceSeekToSample(int sample) { +#ifdef USE_FFMPEG avcodec_flush_buffers(pCodecCtx); +#endif // Discard any pending packet data. packet->size = 0; @@ -381,15 +394,15 @@ struct Atrac { const u32 unalignedSamples = (offsetSamples + sample) % atracSamplesPerFrame; int seekFrame = sample + offsetSamples - unalignedSamples; - if (sample != currentSample) { +#ifdef USE_FFMPEG + if (sample != currentSample && pCodecCtx != nullptr) { avcodec_flush_buffers(pCodecCtx); } - currentSample = sample; - if (sample == 0) { + if (sample == 0 && pCodecCtx != nullptr) { // Prefill the decode buffer with packets before the first sample offset. avcodec_flush_buffers(pCodecCtx); - u32 off = getFileOffsetBySample(currentSample); + u32 off = getFileOffsetBySample(sample); for (u32 pos = dataOff; pos < off; pos += atracBytesPerFrame) { av_init_packet(packet); packet->data = data_buf + pos; @@ -400,12 +413,17 @@ struct Atrac { DecodePacket(); } } +#endif // USE_FFMPEG + + currentSample = sample; } bool FillPacket() { u32 off = getFileOffsetBySample(currentSample); if (off < first.filesize) { +#ifdef USE_FFMPEG av_init_packet(packet); +#endif // USE_FFMPEG packet->data = data_buf + off; packet->size = atracBytesPerFrame; packet->pos = off; @@ -419,7 +437,9 @@ struct Atrac { } bool FillLowLevelPacket() { +#ifdef USE_FFMPEG av_init_packet(packet); +#endif // USE_FFMPEG if (bufferPos < (u32)dataOff) { bufferPos = dataOff; } @@ -432,6 +452,11 @@ struct Atrac { } AtracDecodeResult DecodePacket() { +#ifdef USE_FFMPEG + if (pCodecCtx == nullptr) { + return ATDECODE_FAILED; + } + int got_frame = 0; int bytes_read = avcodec_decode_audio4(pCodecCtx, pFrame, &got_frame, packet); av_free_packet(packet); @@ -447,8 +472,10 @@ struct Atrac { } return got_frame ? ATDECODE_GOTFRAME : ATDECODE_FEEDME; - } +#else + return ATDECODE_BADFRAME; #endif // USE_FFMPEG + } private: void AnalyzeReset(); @@ -954,8 +981,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 skipSamples = unalignedSamples; } -#ifdef USE_FFMPEG - if (!atrac->failedDecode && (atrac->codecType == PSP_MODE_AT_3 || atrac->codecType == PSP_MODE_AT_3_PLUS) && atrac->pCodecCtx) { + if (!atrac->failedDecode && (atrac->codecType == PSP_MODE_AT_3 || atrac->codecType == PSP_MODE_AT_3_PLUS)) { atrac->SeekToSample(atrac->currentSample); AtracDecodeResult res = ATDECODE_FEEDME; @@ -969,6 +995,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 } if (res == ATDECODE_GOTFRAME) { +#ifdef USE_FFMPEG // got a frame // Use a small buffer and keep overwriting it with file data constantly atrac->first.writableBytes += atrac->atracBytesPerFrame; @@ -1006,6 +1033,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 ERROR_LOG(ME, "swr_convert: Error while converting %d", avret); } } +#endif // USE_FFMPEG } if (res == ATDECODE_GOTFRAME || res == ATDECODE_BADFRAME) { // We only want one frame per call, let's continue the next time. @@ -1024,7 +1052,6 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 } } } -#endif // USE_FFMPEG *SamplesNum = numSamples; // update current sample and decodePos @@ -1498,14 +1525,9 @@ static u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFi atrac->first.writableBytes = bufferInfo.first.writableBytes - bytesWrittenFirstBuf; atrac->first.offset = bytesWrittenFirstBuf; } -#ifdef USE_FFMPEG - if ((atrac->codecType == PSP_MODE_AT_3 || atrac->codecType == PSP_MODE_AT_3_PLUS) && atrac->pCodecCtx) { + + if (atrac->codecType == PSP_MODE_AT_3 || atrac->codecType == PSP_MODE_AT_3_PLUS) { atrac->SeekToSample(sample); - } else -#endif // USE_FFMPEG - { - atrac->currentSample = sample; - atrac->decodePos = atrac->getDecodePosBySample(sample); } return hleDelayResult(hleLogSuccessInfoI(ME, 0), "reset play pos", 3000); @@ -1643,12 +1665,10 @@ static int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize) { WARN_LOG(ME, "This is an atrac3 stereo audio"); } -#ifdef USE_FFMPEG atrac->data_buf = new u8[atrac->first.filesize]; u32 copybytes = std::min(bufferSize, atrac->first.filesize); Memory::Memcpy(atrac->data_buf, buffer, copybytes); return __AtracSetContext(atrac); -#endif // USE_FFMPEG } else if (atrac->codecType == PSP_MODE_AT_3_PLUS) { if (atrac->atracChannels == 1) { @@ -2188,7 +2208,7 @@ static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { atrac->CleanStuff(); INFO_LOG(ME, "Channels: %i outputChannels: %i bytesperFrame: %x", atrac->atracChannels, atrac->atracOutputChannels, atrac->atracBytesPerFrame); -#ifdef USE_FFMPEG + if (atrac->codecType == PSP_MODE_AT_3) { if (atrac->atracChannels == 1) { WARN_LOG(ME, "This is an atrac3 mono audio (low level)"); @@ -2238,7 +2258,6 @@ static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { __AtracSetContext(atrac); return 0; } -#endif // USE_FFMPEG } return 0; } @@ -2251,8 +2270,8 @@ static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesCo } DEBUG_LOG(ME, "UNIMPL sceAtracLowLevelDecode(%i, %08x, %08x, %08x, %08x)", atracID, sourceAddr, sourceBytesConsumedAddr, samplesAddr, sampleBytesAddr); -#ifdef USE_FFMPEG - if (atrac && atrac->pCodecCtx && Memory::IsValidAddress(sourceAddr) && Memory::IsValidAddress(sourceBytesConsumedAddr) && + + if (atrac && Memory::IsValidAddress(sourceAddr) && Memory::IsValidAddress(sourceBytesConsumedAddr) && Memory::IsValidAddress(samplesAddr) && Memory::IsValidAddress(sampleBytesAddr)) { u32 sourcebytes = atrac->first.writableBytes; if (sourcebytes > 0) { @@ -2275,6 +2294,7 @@ static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesCo } if (res == ATDECODE_GOTFRAME) { +#ifdef USE_FFMPEG // got a frame u8 *out = Memory::GetPointer(samplesAddr); numSamples = atrac->pFrame->nb_samples; @@ -2285,6 +2305,7 @@ static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesCo if (avret < 0) { ERROR_LOG(ME, "swr_convert: Error while converting %d", avret); } +#endif // USE_FFMPEG break; } else if (res == ATDECODE_BADFRAME) { break; @@ -2307,7 +2328,6 @@ static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesCo Memory::Write_U32(atrac->first.writableBytes, sourceBytesConsumedAddr); return hleDelayResult(0, "low level atrac decode data", atracDecodeDelay); } -#endif // USE_FFMPEG return 0; } From 91de8e46c1fb77d62b6e950cbe58067165ae5355 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Nov 2015 13:56:18 -0800 Subject: [PATCH 3/9] Atrac: Fix an internal typo. --- Core/HLE/sceAtrac.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index d47230d929..f1887bea8c 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -120,7 +120,7 @@ struct InputBuffer { struct Atrac; int __AtracSetContext(Atrac *atrac); -void _AtracGenarateContext(Atrac *atrac, SceAtracId *context); +void _AtracGenerateContext(Atrac *atrac, SceAtracId *context); struct AtracLoopInfo { int cuePointID; @@ -904,7 +904,7 @@ u32 _AtracAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd) { atrac->first.writableBytes = 0; if (atrac->atracContext.IsValid()) { // refresh atracContext - _AtracGenarateContext(atrac, atrac->atracContext); + _AtracGenerateContext(atrac, atrac->atracContext); } return 0; } @@ -1075,7 +1075,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 } if (atrac->atracContext.IsValid()) { // refresh atracContext - _AtracGenarateContext(atrac, atrac->atracContext); + _AtracGenerateContext(atrac, atrac->atracContext); } } @@ -2077,7 +2077,7 @@ int _AtracGetIDByContext(u32 contextAddr) { return atracID; } -void _AtracGenarateContext(Atrac *atrac, SceAtracId *context) { +void _AtracGenerateContext(Atrac *atrac, SceAtracId *context) { context->info.buffer = atrac->first.addr; context->info.bufferByte = atrac->atracBufSize; context->info.secondBuffer = atrac->second.addr; @@ -2133,7 +2133,7 @@ static int _sceAtracGetContextAddress(int atracID) { else WARN_LOG(ME, "%08x=_sceAtracGetContextAddress(%i)", atrac->atracContext.ptr, atracID); if (atrac->atracContext.IsValid()) - _AtracGenarateContext(atrac, atrac->atracContext); + _AtracGenerateContext(atrac, atrac->atracContext); return atrac->atracContext.ptr; } From 3f3700cb45512c772041ea4560cf1d779eb8eace Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Nov 2015 14:01:13 -0800 Subject: [PATCH 4/9] Atrac: Allow games to update buffer state. Because they can and do. This primarily only happens with low level and SAS streams, I think. --- Core/HLE/sceAtrac.cpp | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index f1887bea8c..f6bb8e5cc0 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -546,7 +546,15 @@ static Atrac *getAtrac(int atracID) { if (atracID < 0 || atracID >= PSP_NUM_ATRAC_IDS) { return NULL; } - return atracIDs[atracID]; + Atrac *atrac = atracIDs[atracID]; + + if (atrac && atrac->atracContext.IsValid()) { + // Read in any changes from the game to the context. + // TODO: Might be better to just always track in RAM. + atrac->bufferState = atrac->atracContext->info.state; + } + + return atrac; } static int createAtrac(Atrac *atrac) { @@ -941,6 +949,9 @@ static u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd) { atrac->first.size = atrac->first.filesize; if (atrac->bufferState == ATRAC_STATUS_HALFWAY_BUFFER) atrac->bufferState = ATRAC_STATUS_ALL_DATA_LOADED; + if (atrac->atracContext.IsValid()) { + _AtracGenerateContext(atrac, atrac->atracContext); + } } atrac->first.writableBytes -= bytesToAdd; atrac->first.offset += bytesToAdd; @@ -1530,6 +1541,10 @@ static u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFi atrac->SeekToSample(sample); } + if (atrac->atracContext.IsValid()) { + _AtracGenerateContext(atrac, atrac->atracContext); + } + return hleDelayResult(hleLogSuccessInfoI(ME, 0), "reset play pos", 3000); } } @@ -2086,15 +2101,11 @@ void _AtracGenerateContext(Atrac *atrac, SceAtracId *context) { context->info.loopNum = atrac->loopNum; context->info.loopStart = atrac->loopStartSample > 0 ? atrac->loopStartSample : 0; context->info.loopEnd = atrac->loopEndSample > 0 ? atrac->loopEndSample : 0; - if (context->info.endSample > 0) { - // do not change info.state if this was not called at first time - // In Sol Trigger, it would set info.state = 0x10 outside - // TODO: Should we just keep this in PSP ram then, or something? - } else if (!atrac->data_buf) { - context->info.state = ATRAC_STATUS_NO_DATA; - } else { - context->info.state = atrac->bufferState; - } + + // Note that we read in the state when loading the atrac object, so it's safe + // to update it back here all the time. Some games, like Sol Trigger, change it. + // TODO: Should we just keep this in PSP ram then, or something? + context->info.state = atrac->bufferState; if (atrac->firstSampleoffset != 0) { const u32 firstOffsetExtra = atrac->codecType == PSP_CODEC_AT3PLUS ? 368 : 69; context->info.samplesPerChan = atrac->firstSampleoffset + firstOffsetExtra; @@ -2233,6 +2244,10 @@ static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { atrac->currentSample = 0; // TODO: Check failure? __AtracSetContext(atrac); + + if (atrac->atracContext.IsValid()) { + _AtracGenerateContext(atrac, atrac->atracContext); + } return 0; } @@ -2256,6 +2271,10 @@ static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { memcpy(atrac->data_buf, at3plusHeader, headersize); atrac->currentSample = 0; __AtracSetContext(atrac); + + if (atrac->atracContext.IsValid()) { + _AtracGenerateContext(atrac, atrac->atracContext); + } return 0; } } From a932b0858c99067e9e66d0fa8b785a5356564dd9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Nov 2015 14:12:49 -0800 Subject: [PATCH 5/9] Atrac: Make sure NO_DATA is always set. This way we can move away from data_buf, which eventually we'll stop using entirely, in preference for PSP RAM. --- Core/HLE/sceAtrac.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index f6bb8e5cc0..98255aaf6a 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -169,6 +169,7 @@ struct Atrac { if (data_buf) delete [] data_buf; data_buf = 0; + bufferState = ATRAC_STATUS_NO_DATA; if (atracContext.IsValid()) kernelMemory.Free(atracContext.ptr); @@ -1695,6 +1696,9 @@ static int _AtracSetData(Atrac *atrac, u32 buffer, u32 bufferSize) { u32 copybytes = std::min(bufferSize, atrac->first.filesize); Memory::Memcpy(atrac->data_buf, buffer, copybytes); return __AtracSetContext(atrac); + } else { + // Should not get here, but just in case, force it. + atrac->bufferState = ATRAC_STATUS_NO_DATA; } return 0; From 61e530df91377a48b7174c42aae021691ec94a1a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Nov 2015 14:14:27 -0800 Subject: [PATCH 6/9] Atrac: Check more buffer states in GetRemainFrame. --- 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 98255aaf6a..9064125cf2 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -67,6 +67,8 @@ #define ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED 0x80630022 #define ATRAC_ERROR_BUFFER_IS_EMPTY 0x80630023 #define ATRAC_ERROR_ALL_DATA_DECODED 0x80630024 +#define ATRAC_ERROR_IS_LOW_LEVEL 0x80630031 +#define ATRAC_ERROR_IS_FOR_SCESAS 0x80630040 #define ATRAC_ERROR_AA3_INVALID_DATA 0x80631003 #define ATRAC_ERROR_AA3_SIZE_TOO_SMALL 0x80631004 @@ -1369,9 +1371,14 @@ static u32 sceAtracGetRemainFrame(int atracID, u32 remainAddr) { Atrac *atrac = getAtrac(atracID); if (!atrac) { return hleLogError(ME, ATRAC_ERROR_BAD_ATRACID, "bad atrac ID"); - } else if (!atrac->data_buf) { + } else if (atrac->bufferState == ATRAC_STATUS_NO_DATA) { return hleLogError(ME, ATRAC_ERROR_NO_DATA, "no data"); + } else if (atrac->bufferState == ATRAC_STATUS_LOW_LEVEL) { + return hleLogError(ME, ATRAC_ERROR_IS_LOW_LEVEL, "cannot use for low level stream"); + } else if (atrac->bufferState == ATRAC_STATUS_FOR_SCESAS) { + return hleLogError(ME, ATRAC_ERROR_IS_FOR_SCESAS, "cannot use for SAS stream"); } else if (!remainingFrames.IsValid()) { + // Would crash. return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid remainingFrames pointer"); } else { *remainingFrames = atrac->getRemainFrames(); From e28fa3c4269313215cf1dbbb2a33cb51c44de1b7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Nov 2015 16:17:10 -0800 Subject: [PATCH 7/9] Atrac: Correct transition to fully loaded. Normally it won't go over of course, oops. --- Core/HLE/sceAtrac.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 9064125cf2..6a24ae9c12 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -906,7 +906,7 @@ u32 _AtracAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd) { int addbytes = std::min(bytesToAdd, atrac->first.filesize - atrac->first.fileoffset); Memory::Memcpy(atrac->data_buf + atrac->first.fileoffset, bufPtr, addbytes); atrac->first.size += bytesToAdd; - if (atrac->first.size > atrac->first.filesize) { + if (atrac->first.size >= atrac->first.filesize) { atrac->first.size = atrac->first.filesize; if (atrac->bufferState == ATRAC_STATUS_HALFWAY_BUFFER) atrac->bufferState = ATRAC_STATUS_ALL_DATA_LOADED; @@ -948,7 +948,7 @@ static u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd) { atrac->first.fileoffset += addbytes; } atrac->first.size += bytesToAdd; - if (atrac->first.size > atrac->first.filesize) { + if (atrac->first.size >= atrac->first.filesize) { atrac->first.size = atrac->first.filesize; if (atrac->bufferState == ATRAC_STATUS_HALFWAY_BUFFER) atrac->bufferState = ATRAC_STATUS_ALL_DATA_LOADED; From 959887d407775990903c4ea48647f3d90ca5d261 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Nov 2015 16:35:20 -0800 Subject: [PATCH 8/9] Atrac: Correct remaining frames return value. Streaming buffers still not correct in some cases, primarily looping. --- Core/HLE/sceAtrac.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 6a24ae9c12..bc0f798368 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -111,12 +111,16 @@ enum AtracDecodeResult { }; struct InputBuffer { + // Address of the buffer. u32 addr; + // Size of data valid in the buffer from the start. u32 size; u32 offset; u32 writableBytes; u32 neededBytes; + // Total size of the entire file data. u32 filesize; + // Offset into the file at which the stream data ends. u32 fileoffset; }; @@ -290,20 +294,16 @@ struct Atrac { } int getRemainFrames() const { - // games would like to add atrac data when it wants. - // Do not try to guess when it want to add data. - // Just return current remainFrames. - int remainFrame; - if (first.fileoffset >= first.filesize || currentSample >= endSample) - remainFrame = PSP_ATRAC_ALLDATA_IS_ON_MEMORY; - else { - // guess the remain frames. - int atracSamplesPerFrame = (codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); - remainFrame = ((int)first.size - (int)getFileOffsetBySample(currentSample)) / atracBytesPerFrame - (firstSampleoffset / atracSamplesPerFrame); - if (remainFrame < 0) - remainFrame = 0; + if (bufferState == ATRAC_STATUS_ALL_DATA_LOADED) { + // Meaning, infinite I guess? We've got it all. + return PSP_ATRAC_ALLDATA_IS_ON_MEMORY; } - return remainFrame; + + // Since the first frame is shorter by this offset, add to round up at this offset. + const u32 firstOffsetExtra = codecType == PSP_CODEC_AT3PLUS ? 368 : 69; + int atracSamplesPerFrame = (codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES); + const int remainingBytes = first.fileoffset - getFileOffsetBySample(currentSample - atracSamplesPerFrame + firstOffsetExtra); + return remainingBytes / atracBytesPerFrame; } int atracID; From 9da62c1efcfcc8dd2b4f4c38e35b84e137855621 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 7 Nov 2015 23:24:02 -0800 Subject: [PATCH 9/9] Atrac: Use end codes for remaining when streaming. --- Core/HLE/sceAtrac.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index bc0f798368..5d3e739083 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -299,6 +299,14 @@ struct Atrac { return PSP_ATRAC_ALLDATA_IS_ON_MEMORY; } + if (currentSample >= endSample && loopNum == 0) { + if (bufferState == ATRAC_STATUS_STREAMED_WITHOUT_LOOP) { + return PSP_ATRAC_NONLOOP_STREAM_DATA_IS_ON_MEMORY; + } else if (bufferState == ATRAC_STATUS_STREAMED_LOOP_FROM_END || bufferState == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) { + return PSP_ATRAC_LOOP_STREAM_DATA_IS_ON_MEMORY; + } + } + // Since the first frame is shorter by this offset, add to round up at this offset. const u32 firstOffsetExtra = codecType == PSP_CODEC_AT3PLUS ? 368 : 69; int atracSamplesPerFrame = (codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);