From 3cd1f2f8323de10fbc3885e53b83d8759cd14f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 13 Apr 2025 15:47:39 +0200 Subject: [PATCH] sceAudioCodec: Fix AT3 and AAC playback (possibly limited to certain bitrates) but fixes Kosmodrones --- Core/HLE/sceAtrac.cpp | 36 -------------- Core/HLE/sceAtrac.h | 2 - Core/HLE/sceAudiocodec.cpp | 99 +++++++++++++++++++++++++++++++++----- Core/HLE/sceAudiocodec.h | 2 + Core/HLE/sceMpeg.cpp | 24 +++++---- Core/HLE/sceMpeg.h | 5 ++ Core/HW/MediaEngine.cpp | 8 ++- Core/Util/AtracTrack.cpp | 1 - 8 files changed, 116 insertions(+), 61 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index d3f5f523cc..0467dfc36a 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -1023,42 +1023,6 @@ static u32 _sceAtracGetContextAddress(int atracID) { return hleLogDebug(Log::ME, atrac->context_.ptr); } -struct At3HeaderMap { - u16 bytes; - u16 channels; - u8 jointStereo; - - bool Matches(int bytesPerFrame, int encodedChannels) const { - return this->bytes == bytesPerFrame && this->channels == encodedChannels; - } -}; - -// These should represent all possible supported bitrates (66, 104, and 132 for stereo.) -static const At3HeaderMap at3HeaderMap[] = { - { 0x00C0, 1, 0 }, // 132/2 (66) kbps mono - { 0x0098, 1, 0 }, // 105/2 (52.5) kbps mono - { 0x0180, 2, 0 }, // 132 kbps stereo - { 0x0130, 2, 0 }, // 105 kbps stereo - // At this size, stereo can only use joint stereo. - { 0x00C0, 2, 1 }, // 66 kbps stereo -}; - -bool IsAtrac3StreamJointStereo(int codecType, int bytesPerFrame, int channels) { - if (codecType != PSP_CODEC_AT3) { - // Well, might actually be, but it's not used in codec setup. - return false; - } - - for (size_t i = 0; i < ARRAY_SIZE(at3HeaderMap); ++i) { - if (at3HeaderMap[i].Matches(bytesPerFrame, channels)) { - return at3HeaderMap[i].jointStereo; - } - } - - // Not found? Should we log? - return false; -} - static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { AtracBase *atrac = getAtrac(atracID); if (!atrac) { diff --git a/Core/HLE/sceAtrac.h b/Core/HLE/sceAtrac.h index e04e045538..594b68c194 100644 --- a/Core/HLE/sceAtrac.h +++ b/Core/HLE/sceAtrac.h @@ -136,8 +136,6 @@ class AtracBase; // For debugger use ONLY. const AtracBase *__AtracGetCtx(int i, u32 *type); -bool IsAtrac3StreamJointStereo(int codecType, int bytesPerFrame, int channels); - // External interface used by sceSas, see ATRAC_STATUS_FOR_SCESAS. u32 AtracSasAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd); void AtracSasDecodeData(int atracID, u8* outbuf, int *SamplesNum, int *finish); diff --git a/Core/HLE/sceAudiocodec.cpp b/Core/HLE/sceAudiocodec.cpp index 3ab6bbd122..168f06ab57 100644 --- a/Core/HLE/sceAudiocodec.cpp +++ b/Core/HLE/sceAudiocodec.cpp @@ -49,6 +49,19 @@ static_assert(sizeof(SceAudiocodecCodec) == 128); // // Known byte values. +// Atrac3 (0x1001) +// ------------------------------------------------ + +// AAC (0x1003) +// ------------------------------------------------ +// Sample rate is at offset 0x28. +// srcBytesConsumed can be very small the first frames. +// 0x1000 is always the frame size. + +// MP3 (0x1002) +// ------------------------------------------------ + + void CalculateInputBytesAndChannelsAt3Plus(const SceAudiocodecCodec *ctx, int *inputBytes, int *channels) { *inputBytes = 0; *channels = 2; @@ -125,9 +138,12 @@ static int __AudioCodecInitCommon(u32 ctxPtr, int codec, bool mono) { ctx->unk_init = 0x5100601; // Firmware version indicator? ctx->err = 0; - int inFrameBytes = 0; + int bytesPerFrame = 0; int channels = 2; + uint8_t extraData[14]{}; + + SceAudiocodecCodec *ptr = ctx; // Special actions for some codecs. switch (audioType) { case PSP_CODEC_MP3: @@ -140,15 +156,31 @@ static int __AudioCodecInitCommon(u32 ctxPtr, int codec, bool mono) { // neededMem has been set to 0x18f20. break; case PSP_CODEC_AT3PLUS: - CalculateInputBytesAndChannelsAt3Plus(ctx, &inFrameBytes, &channels); + CalculateInputBytesAndChannelsAt3Plus(ctx, &bytesPerFrame, &channels); break; + case PSP_CODEC_AT3: + { + // See AtracBase::CreateDecoder. Need to properly understand this one day.. + // + // TODO: How do we get the bytesPerFrame? + bytesPerFrame = 384; // TODO: Calculate from params. + bool jointStereo = IsAtrac3StreamJointStereo(PSP_CODEC_AT3, bytesPerFrame, channels); + // The only thing that changes are the jointStereo_ values. + extraData[0] = 1; + extraData[3] = channels << 3; + extraData[6] = jointStereo; + extraData[8] = jointStereo; + extraData[10] = 1; + break; + } default: break; } // Create audio decoder for given audio codec and push it into AudioList - INFO_LOG(Log::ME, "sceAudioDecoder: Creating codec with %04x frame size and %d channels, codec %04x", inFrameBytes, channels, codec); - AudioDecoder *decoder = CreateAudioDecoder(audioType, 44100, channels, inFrameBytes); + INFO_LOG(Log::ME, "sceAudioDecoder: Creating codec with %04x frame size and %d channels, codec %04x", bytesPerFrame, channels, codec); + // We send in extra data with all codec, most ignore it. + AudioDecoder *decoder = CreateAudioDecoder(audioType, 44100, channels, bytesPerFrame, extraData, sizeof(extraData)); decoder->SetCtxPtr(ctxPtr); g_audioDecoderContexts[ctxPtr] = decoder; return hleLogDebug(Log::ME, 0); @@ -177,15 +209,23 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) { auto ctx = PSPPointer::Create(ctxPtr); // On game-owned heap, no need to allocate. - int inFrameBytes = 0; + int bytesPerFrame = 0; int channels = 2; + int sampleRate = 0; switch (codec) { case PSP_CODEC_AT3PLUS: - CalculateInputBytesAndChannelsAt3Plus(ctx, &inFrameBytes, &channels); + CalculateInputBytesAndChannelsAt3Plus(ctx, &bytesPerFrame, &channels); break; case PSP_CODEC_MP3: - inFrameBytes = ctx->srcBytesRead; + bytesPerFrame = ctx->srcBytesRead; + break; + case PSP_CODEC_AAC: + bytesPerFrame = ctx->srcBytesRead; + sampleRate = ctx->formatOutSamples; + break; + case PSP_CODEC_AT3: + bytesPerFrame = 384; break; } @@ -195,7 +235,7 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) { if (!decoder && oldStateLoaded) { // We must have loaded an old state that did not have sceAudiocodec information. // Fake it by creating the desired context. - decoder = CreateAudioDecoder(audioType, 44100, channels, inFrameBytes); + decoder = CreateAudioDecoder(audioType, 44100, channels, bytesPerFrame); decoder->SetCtxPtr(ctxPtr); g_audioDecoderContexts[ctxPtr] = decoder; } @@ -206,11 +246,11 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) { int inDataConsumed = 0; int outSamples = 0; - INFO_LOG(Log::ME, "decoder. in: %08x out: %08x unk40: %d unk41: %d", ctx->inBuf, ctx->outBuf, ctx->unk40, ctx->unk41); + DEBUG_LOG(Log::ME, "decoder. in: %08x out: %08x unk40: %02x unk41: %02x", ctx->inBuf, ctx->outBuf, ctx->unk40, ctx->unk41); int16_t *outBuf = (int16_t *)Memory::GetPointerWrite(ctx->outBuf); - bool result = decoder->Decode(Memory::GetPointer(ctx->inBuf), inFrameBytes, &inDataConsumed, 2, outBuf, &outSamples); + bool result = decoder->Decode(Memory::GetPointer(ctx->inBuf), bytesPerFrame, &inDataConsumed, 2, outBuf, &outSamples); if (!result) { ctx->err = 0x20b; ERROR_LOG(Log::ME, "AudioCodec decode failed. Setting error to %08x", ctx->err); @@ -219,7 +259,7 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) { ctx->srcBytesRead = inDataConsumed; ctx->dstSamplesWritten = outSamples; } - return hleLogInfo(Log::ME, 0, "codec %s", GetCodecName(codec)); + return hleLogDebug(Log::ME, 0, "codec %s", GetCodecName(codec)); } // This is used by sceMp3, in Beats. @@ -331,6 +371,43 @@ static int sceAudiocodecGetOutputBytes(u32 ctxPtr, int codec, u32 outBytesAddr) return hleLogInfo(Log::ME, 0); } +struct At3HeaderMap { + u16 bytes; + u16 channels; + u8 jointStereo; + + bool Matches(int bytesPerFrame, int encodedChannels) const { + return this->bytes == bytesPerFrame && this->channels == encodedChannels; + } +}; + +// These should represent all possible supported bitrates (66, 104, and 132 for stereo.) +static const At3HeaderMap at3HeaderMap[] = { + { 0x00C0, 1, 0 }, // 132/2 (66) kbps mono + { 0x0098, 1, 0 }, // 105/2 (52.5) kbps mono + { 0x0180, 2, 0 }, // 132 kbps stereo + { 0x0130, 2, 0 }, // 105 kbps stereo + // At this size, stereo can only use joint stereo. + { 0x00C0, 2, 1 }, // 66 kbps stereo +}; + +bool IsAtrac3StreamJointStereo(int codecType, int bytesPerFrame, int channels) { + if (codecType != PSP_CODEC_AT3) { + // Well, might actually be, but it's not used in codec setup. + return false; + } + + for (size_t i = 0; i < ARRAY_SIZE(at3HeaderMap); ++i) { + if (at3HeaderMap[i].Matches(bytesPerFrame, channels)) { + return at3HeaderMap[i].jointStereo; + } + } + + // Not found? Should we log? + return false; +} + + const HLEFunction sceAudiocodec[] = { {0X70A703F8, &WrapI_UI, "sceAudiocodecDecode", 'i', "xx"}, {0X5B37EB1D, &WrapI_UI, "sceAudiocodecInit", 'i', "xx"}, diff --git a/Core/HLE/sceAudiocodec.h b/Core/HLE/sceAudiocodec.h index 086fa99a93..4d24a98e2b 100644 --- a/Core/HLE/sceAudiocodec.h +++ b/Core/HLE/sceAudiocodec.h @@ -90,3 +90,5 @@ void __sceAudiocodecDoState(PointerWrap &p); class AudioDecoder; extern std::map g_audioDecoderContexts; + +bool IsAtrac3StreamJointStereo(int codecType, int bytesPerFrame, int channels); diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 1f822f322b..17caa60c7d 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -162,7 +162,7 @@ static int mpegLibVersion = 0; static u32 mpegLibCrc = 0; static u32 streamIdGen; static int actionPostPut; -static std::map mpegMap; +std::map g_mpegCtxs; MpegContext::MpegContext() { memcpy(mpegheader, defaultMpegheader, 2048); @@ -215,8 +215,8 @@ static MpegContext *getMpegCtx(u32 mpegAddr) { return nullptr; u32 mpeg = Memory::Read_U32(mpegAddr); - auto found = mpegMap.find(mpeg); - if (found == mpegMap.end()) + auto found = g_mpegCtxs.find(mpeg); + if (found == g_mpegCtxs.end()) return nullptr; MpegContext *res = found->second; @@ -229,6 +229,10 @@ static MpegContext *getMpegCtx(u32 mpegAddr) { return res; } +const std::map &__MpegGetContexts() { + return g_mpegCtxs; +} + static u32 convertTimestampToDate(u32 ts) { return ts; // TODO } @@ -366,15 +370,15 @@ void __MpegDoState(PointerWrap &p) { Do(p, actionPostPut); __KernelRestoreActionType(actionPostPut, PostPutAction::Create); - Do(p, mpegMap); + Do(p, g_mpegCtxs); } void __MpegShutdown() { std::map::iterator it, end; - for (it = mpegMap.begin(), end = mpegMap.end(); it != end; ++it) { + for (it = g_mpegCtxs.begin(), end = g_mpegCtxs.end(); it != end; ++it) { delete it->second; } - mpegMap.clear(); + g_mpegCtxs.clear(); } void __MpegLoadModule(int version,u32 crc) { @@ -486,12 +490,12 @@ static u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr Memory::Write_U32(ringbuffer->dataUpperBound, mpegHandle + 20); } MpegContext *ctx = new MpegContext(); - if (mpegMap.find(mpegHandle) != mpegMap.end()) { + if (g_mpegCtxs.find(mpegHandle) != g_mpegCtxs.end()) { WARN_LOG_REPORT(Log::HLE, "Replacing existing mpeg context at %08x", mpegAddr); // Otherwise, it would leak. - delete mpegMap[mpegHandle]; + delete g_mpegCtxs[mpegHandle]; } - mpegMap[mpegHandle] = ctx; + g_mpegCtxs[mpegHandle] = ctx; // Initialize mpeg values. ctx->mpegRingbufferAddr = ringbufferAddr; @@ -526,7 +530,7 @@ static int sceMpegDelete(u32 mpeg) { } delete ctx; - mpegMap.erase(Memory::Read_U32(mpeg)); + g_mpegCtxs.erase(Memory::Read_U32(mpeg)); return hleDelayResult(hleLogDebug(Log::ME, 0), "mpeg delete", 40000); } diff --git a/Core/HLE/sceMpeg.h b/Core/HLE/sceMpeg.h index bfeeed3822..0361365fc4 100644 --- a/Core/HLE/sceMpeg.h +++ b/Core/HLE/sceMpeg.h @@ -88,6 +88,9 @@ struct MpegContext { MpegContext(); ~MpegContext(); + MpegContext(const MpegContext &) = delete; + void operator=(const MpegContext &) = delete; + void DoState(PointerWrap &p); u8 mpegheader[2048]; @@ -140,3 +143,5 @@ void Register_sceMpegbase(); void __VideoPmpInit(); void __VideoPmpDoState(PointerWrap &p); void __VideoPmpShutdown(); + +const std::map &__MpegGetContexts(); diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index 0d636feab5..59013aa7cb 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -17,6 +17,7 @@ #include "Common/Serialize/SerializeFuncs.h" #include "Common/Math/SIMDHeaders.h" +#include "Common/StringUtils.h" #include "Core/System.h" #include "Core/Debugger/MemBlockInfo.h" #include "Core/HW/MediaEngine.h" @@ -86,7 +87,12 @@ void ffmpeg_logger(void *, int level, const char *format, va_list va_args) { } else if (level >= AV_LOG_VERBOSE) { DEBUG_LOG(Log::ME, "FF: %s", tmp); } else { - INFO_LOG(Log::ME, "FF: %s", tmp); + // Downgrade some log messages we don't care about + if (startsWith(tmp, "No accelerated colorspace") || startsWith(tmp, "SEI type 1 size 40 truncated at 36")) { + VERBOSE_LOG(Log::ME, "FF: %s", tmp); + } else { + INFO_LOG(Log::ME, "FF: %s", tmp); + } } } diff --git a/Core/Util/AtracTrack.cpp b/Core/Util/AtracTrack.cpp index 9755112278..86586ba863 100644 --- a/Core/Util/AtracTrack.cpp +++ b/Core/Util/AtracTrack.cpp @@ -148,7 +148,6 @@ int AnalyzeAtracTrack(const u8 *buffer, u32 size, Track *track, std::string *err } else if (at3fmt->fmtTag == AT3_PLUS_MAGIC) { _dbg_assert_(at3fmt->fmtTag == 0xFFFE); // It's in an "Extensible" wave format. Let's read some more. - } if (chunkSize > 16) { // Read and format extra bytes as hexadecimal