Files
ppsspp/Core/HLE/sceAac.cpp
T
Henrik Rydgård 86fcfdc60a Add some new function names that were cracked from NIDs by zecoxao
He used Claude, never thought of this use case, but it's logical - it
can go reverse engineer the functions to come up with likely names,
making it easier to match the SHA1 hash. (NIDs are truncated SHA1 hashes
of names, except in firmwares later than around 3.50).
2026-09-10 15:52:53 -06:00

226 lines
7.9 KiB
C++

// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Core/HLE/sceAac.h"
#include <algorithm>
#include "Common/Serialize/SerializeFuncs.h"
#include "Common/Serialize/SerializeMap.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/Reporting.h"
#include "Core/HW/SimpleAudioDec.h"
std::map<u32, AuCtx*> g_aacMap;
static AuCtx *getAacCtx(u32 id) {
if (g_aacMap.find(id) == g_aacMap.end())
return NULL;
return g_aacMap[id];
}
void __AACShutdown() {
for (auto it = g_aacMap.begin(), end = g_aacMap.end(); it != end; it++) {
delete it->second;
}
g_aacMap.clear();
}
void __AACDoState(PointerWrap &p) {
auto s = p.Section("sceAAC", 0, 1);
if (!s)
return;
Do(p, g_aacMap);
}
static u32 sceAacExit(u32 id) {
if (g_aacMap.find(id) != g_aacMap.end()) {
delete g_aacMap[id];
g_aacMap.erase(id);
} else {
return hleLogError(Log::ME, -1, "bad aac ID");
}
return hleLogInfo(Log::ME, 0);
}
static u32 sceAacInit(u32 id)
{
if (!Memory::IsValidRange(id, 36)) {
return hleLogError(Log::ME, ERROR_AAC_INVALID_ADDRESS, "AAC Invalid id address %08x", id);
}
AuCtx *aac = new AuCtx();
aac->startPos = Memory::ReadUnchecked_U64(id); // AUDIO stream start position.
aac->endPos = Memory::ReadUnchecked_U32(id + 8); // AUDIO stream end position.
aac->AuBuf = Memory::ReadUnchecked_U32(id + 16); // Input AAC data buffer.
aac->AuBufSize = Memory::ReadUnchecked_U32(id + 20); // Input AAC data buffer size.
aac->PCMBuf = Memory::ReadUnchecked_U32(id + 24); // Output PCM data buffer.
aac->PCMBufSize = Memory::ReadUnchecked_U32(id + 28); // Output PCM data buffer size.
aac->freq = Memory::ReadUnchecked_U32(id + 32); // Frequency.
if (aac->AuBuf == 0 || aac->PCMBuf == 0) {
ERROR_LOG(Log::ME, "sceAacInit() AAC INVALID ADDRESS AuBuf %08x PCMBuf %08x", aac->AuBuf, aac->PCMBuf);
delete aac;
return hleNoLog(ERROR_AAC_INVALID_ADDRESS);
}
if (aac->startPos > aac->endPos) {
ERROR_LOG(Log::ME, "sceAacInit() AAC INVALID startPos %lli endPos %lli", aac->startPos, aac->endPos);
delete aac;
return hleNoLog(ERROR_AAC_INVALID_PARAMETER);
}
if (aac->AuBufSize < 8192 || aac->PCMBufSize < 8192) {
ERROR_LOG(Log::ME, "sceAacInit() AAC INVALID PARAMETER, bufferSize %i outputSize %i", aac->AuBufSize, aac->PCMBufSize);
delete aac;
return hleNoLog(ERROR_AAC_INVALID_PARAMETER);
}
if (aac->freq != 24000 && aac->freq != 32000 && aac->freq != 44100 && aac->freq != 48000) {
ERROR_LOG(Log::ME, "sceAacInit() AAC INVALID freq %i", aac->freq);
delete aac;
return hleNoLog(ERROR_AAC_INVALID_PARAMETER);
}
DEBUG_LOG(Log::ME, "startPos %llx endPos %llx AuBuf %08x AuBufSize %08x PCMbuf %08x PCMbufSize %08x freq %d",
aac->startPos, aac->endPos, aac->AuBuf, aac->AuBufSize, aac->PCMBuf, aac->PCMBufSize, aac->freq);
aac->Channels = 2;
aac->MaxOutputSample = aac->PCMBufSize / 4;
aac->SetReadPos((int)aac->startPos);
// create aac decoder
aac->decoder = CreateAudioDecoder(PSP_CODEC_AAC);
// close the audio if id already exist.
if (g_aacMap.find(id) != g_aacMap.end()) {
delete g_aacMap[id];
g_aacMap.erase(id);
}
g_aacMap[id] = aac;
return hleNoLog(id);
}
static u32 sceAacInitResource(u32 numberIds) {
// Do nothing here
WARN_LOG_REPORT(Log::ME, "sceAacInitResource(%i)", numberIds);
return hleNoLog(0);
}
static u32 sceAacTermResource() {
return hleLogError(Log::ME, 0, "UNIMPL");
}
static u32 sceAacDecode(u32 id, u32 pcmAddr) {
// return the size of output pcm, <0 error
auto ctx = getAacCtx(id);
if (!ctx) {
return hleLogError(Log::ME, -1, "bad aac id");
}
return hleLogDebug(Log::ME, ctx->AuDecode(pcmAddr));
}
static u32 sceAacGetLoopNum(u32 id) {
auto ctx = getAacCtx(id);
if (!ctx) {
return hleLogError(Log::ME, -1, "bad aac id");
}
return hleLogInfo(Log::ME, ctx->LoopNum);
}
static u32 sceAacSetLoopNum(u32 id, int loop) {
auto ctx = getAacCtx(id);
if (!ctx) {
return hleLogError(Log::ME, -1, "bad aac id");
}
ctx->LoopNum = loop;
return hleLogInfo(Log::ME, 0);
}
static int sceAacCheckStreamDataNeeded(u32 id) {
// return 1 to read more data stream, 0 don't read, <0 error
auto ctx = getAacCtx(id);
if (!ctx) {
return hleLogError(Log::ME, -1, "bad aac id");
}
return hleLogDebug(Log::ME, ctx->AuCheckStreamDataNeeded());
}
static u32 sceAacNotifyAddStreamData(u32 id, int size) {
// check how many bytes we have read from source file
auto ctx = getAacCtx(id);
if (!ctx) {
return hleLogError(Log::ME, -1, "bad aac id");
}
return hleLogDebug(Log::ME, ctx->AuNotifyAddStreamData(size));
}
static u32 sceAacGetInfoToAddStreamData(u32 id, u32 buff, u32 size, u32 srcPos) {
// read from stream position srcPos of size bytes into buff
auto ctx = getAacCtx(id);
if (!ctx) {
return hleLogError(Log::ME, -1, "bad aac id");
}
return hleLogDebug(Log::ME, ctx->AuGetInfoToAddStreamData(buff, size, srcPos));
}
static u32 sceAacGetMaxOutputSample(u32 id) {
auto ctx = getAacCtx(id);
if (!ctx) {
return hleLogError(Log::ME, -1, "bad aac id");
}
return hleLogDebug(Log::ME, ctx->MaxOutputSample);
}
static u32 sceAacGetSumDecodedSample(u32 id) {
auto ctx = getAacCtx(id);
if (!ctx) {
return hleLogError(Log::ME, -1, "bad aac id");
}
return hleLogDebug(Log::ME, ctx->SumDecodedSamples);
}
static u32 sceAacResetPlayPosition(u32 id) {
INFO_LOG(Log::ME, "sceAacResetPlayPosition(id %i)", id);
auto ctx = getAacCtx(id);
if (!ctx) {
return hleLogError(Log::ME, -1, "bad aac id");
}
return hleLogInfo(Log::ME, ctx->AuResetPlayPosition());
}
const HLEFunction sceAac[] = {
{0XE0C89ACA, &WrapU_U<sceAacInit>, "sceAacInit", 'x', "x" },
{0X33B8C009, &WrapU_U<sceAacExit>, "sceAacExit", 'x', "x" },
{0X5CFFC57C, &WrapU_U<sceAacInitResource>, "sceAacInitResource", 'x', "x" },
{0X23D35CAE, &WrapU_V<sceAacTermResource>, "sceAacTermResource", 'x', "" },
{0X7E4CFEE4, &WrapU_UU<sceAacDecode>, "sceAacDecode", 'x', "xx" },
{0X523347D9, &WrapU_U<sceAacGetLoopNum>, "sceAacGetLoopNum", 'x', "x" },
{0XBBDD6403, &WrapU_UI<sceAacSetLoopNum>, "sceAacSetLoopNum", 'x', "xi" },
{0XD7C51541, &WrapI_U<sceAacCheckStreamDataNeeded>, "sceAacCheckStreamDataNeeded", 'i', "x" },
{0XAC6DCBE3, &WrapU_UI<sceAacNotifyAddStreamData>, "sceAacNotifyAddStreamData", 'x', "xi" },
{0X02098C69, &WrapU_UUUU<sceAacGetInfoToAddStreamData>, "sceAacGetInfoToAddStreamData", 'x', "xxxx" },
{0X6DC7758A, &WrapU_U<sceAacGetMaxOutputSample>, "sceAacGetMaxOutputSample", 'x', "x" },
{0X506BF66C, &WrapU_U<sceAacGetSumDecodedSample>, "sceAacGetSumDecodedSample", 'x', "x" },
{0XD2DA2BBA, &WrapU_U<sceAacResetPlayPosition>, "sceAacResetPlayPosition", 'x', "x" },
{0XE955E83A, nullptr, "sceAacLowLevelInit", '?', "" },
{0XFA01FCB6, nullptr, "sceAacLowLevelDecode", '?', "" }
};
void Register_sceAac() {
RegisterHLEModule("sceAac", ARRAY_SIZE(sceAac), sceAac);
}