sceAudioCodec: Fix AT3 and AAC playback (possibly limited to certain bitrates) but fixes Kosmodrones

This commit is contained in:
Henrik Rydgård committed 2025-04-13 15:48:11 +02:00
1 parent 6eefe8c982
commit 3cd1f2f832
8 files changed
+116 -61

No files matched your search

-36
View File
@@ -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) {
-2
View File
@@ -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);
+88 -11
View File
@@ -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<SceAudiocodecCodec>::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>, "sceAudiocodecDecode", 'i', "xx"},
{0X5B37EB1D, &WrapI_UI<sceAudiocodecInit>, "sceAudiocodecInit", 'i', "xx"},
+2
View File
@@ -90,3 +90,5 @@ void __sceAudiocodecDoState(PointerWrap &p);
class AudioDecoder;
extern std::map<u32, AudioDecoder *> g_audioDecoderContexts;
bool IsAtrac3StreamJointStereo(int codecType, int bytesPerFrame, int channels);
+14 -10
View File
@@ -162,7 +162,7 @@ static int mpegLibVersion = 0;
static u32 mpegLibCrc = 0;
static u32 streamIdGen;
static int actionPostPut;
static std::map<u32, MpegContext *> mpegMap;
std::map<u32, MpegContext *> 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<u32, MpegContext *> &__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<u32, MpegContext *>::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);
}
+5
View File
@@ -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<u32, MpegContext *> &__MpegGetContexts();
+7 -1
View File
@@ -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);
}
}
}
-1
View File
@@ -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