Mp3: Return total frame count in sceMp3GetFrameNum.

This might fix games failing to play mp3s correctly.
This commit is contained in:
Unknown W. Brackets
2019-04-27 07:54:58 -07:00
parent 95d3d99343
commit bc1e6e12f5
2 changed files with 31 additions and 30 deletions

View File

@@ -416,6 +416,13 @@ static int sceMp3Init(u32 mp3) {
ctx->decoder->SetResampleFrequency(ctx->freq);
}
// Based on bitrate, we can calculate the frame size in bytes.
// Note: this doesn't correctly handling padding or slot size, but the PSP doesn't either.
uint32_t bytesPerSecond = (ctx->MaxOutputSample / 8) * ctx->BitRate * 1000;
// The frame count ignores the upper bits of these sizes, although they are used in cases.
uint64_t totalBytes = (ctx->endPos & 0xFFFFFFFF) - (ctx->startPos & 0xFFFFFFFF);
ctx->FrameNum = (int)((totalBytes * ctx->SamplingRate) / bytesPerSecond);
// For mp3 file, if ID3 tag is detected, we must move startPos to 0x400 (stream start position), remove 0x400 bytes of the sourcebuff, and reduce the available buffer size by 0x400
// this is very important for ID3 tag mp3, since our universal audio decoder is for decoding stream part only.
if (hasID3Tag) {
@@ -603,13 +610,16 @@ static u32 sceMp3StartEntry() {
}
static u32 sceMp3GetFrameNum(u32 mp3) {
INFO_LOG(ME, "sceMp3GetFrameNum(%08x)", mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
if (mp3 >= MP3_MAX_HANDLES)
return hleLogError(ME, ERROR_MP3_INVALID_HANDLE, "invalid handle");
return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "unreserved handle");
} else if (ctx->Version < 0 || ctx->AuBuf == 0) {
return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init");
}
return ctx->AuGetFrameNum();
return hleLogSuccessI(ME, ctx->AuGetFrameNum());
}
static u32 sceMp3GetMPEGVersion(u32 mp3) {
@@ -712,7 +722,7 @@ const HLEFunction sceMp3[] = {
{0XD8F54A51, &WrapI_U<sceMp3GetLoopNum>, "sceMp3GetLoopNum", 'i', "x" },
{0XF5478233, &WrapI_U<sceMp3ReleaseMp3Handle>, "sceMp3ReleaseMp3Handle", 'i', "x" },
{0XAE6D2027, &WrapU_U<sceMp3GetMPEGVersion>, "sceMp3GetMPEGVersion", 'x', "x" },
{0X3548AEC8, &WrapU_U<sceMp3GetFrameNum>, "sceMp3GetFrameNum", 'x', "x" },
{0X3548AEC8, &WrapU_U<sceMp3GetFrameNum>, "sceMp3GetFrameNum", 'i', "x" },
{0X0840E808, &WrapU_UI<sceMp3ResetPlayPositionByFrame>, "sceMp3ResetPlayPositionByFrame", 'x', "xi" },
{0X1B839B83, &WrapU_UU<sceMp3LowLevelInit>, "sceMp3LowLevelInit", 'x', "xx" },
{0XE3EE2C81, &WrapU_UUUUU<sceMp3LowLevelDecode>, "sceMp3LowLevelDecode", 'x', "xxxxx"}

View File

@@ -321,39 +321,30 @@ u32 AuCtx::AuDecode(u32 pcmAddr)
auto outbuf = Memory::GetPointer(PCMBuf);
memset(outbuf, 0, PCMBufSize); // important! empty outbuf to avoid noise
u32 outpcmbufsize = 0;
int outpcmbufsize = 0;
// decode frames in sourcebuff and output into PCMBuf, making sure it's filled
while (sourcebuff.size() > 0 && outpcmbufsize < PCMBufSize) {
int pcmframesize;
// decode
decoder->Decode((void*)sourcebuff.c_str(), (int)sourcebuff.size(), outbuf, &pcmframesize);
if (pcmframesize == 0){
// Decode a single frame in sourcebuff and output into PCMBuf.
if (!sourcebuff.empty()) {
decoder->Decode((void *)sourcebuff.c_str(), (int)sourcebuff.size(), outbuf, &outpcmbufsize);
if (outpcmbufsize == 0) {
// no output pcm, we are at the end of the stream
AuBufAvailable = 0;
sourcebuff.clear();
if (LoopNum != 0){
if (LoopNum != 0) {
// if we loop, reset readPos
readPos = startPos;
}
break;
} else {
// count total output samples
SumDecodedSamples += decoder->GetOutSamples();
// get consumed source length
int srcPos = decoder->GetSourcePos();
// remove the consumed source
sourcebuff.erase(0, srcPos);
// reduce the available Aubuff size
// (the available buff size is now used to know if we can read again from file and how many to read)
AuBufAvailable -= srcPos;
}
// count total output pcm size
outpcmbufsize += pcmframesize;
// count total output samples
SumDecodedSamples += decoder->GetOutSamples();
// get consumed source length
int srcPos = decoder->GetSourcePos();
// remove the consumed source
sourcebuff.erase(0, srcPos);
// reduce the available Aubuff size
// (the available buff size is now used to know if we can read again from file and how many to read)
AuBufAvailable -= srcPos;
// move outbuff position to the current end of output
outbuf += pcmframesize;
// increase FrameNum count
FrameNum++;
break;
}
Memory::Write_U32(PCMBuf, pcmAddr);
return outpcmbufsize;