diff --git a/src/DSP_HLE/AACUcode.cpp b/src/DSP_HLE/AACUcode.cpp index 6bc09827..09ffb5d6 100644 --- a/src/DSP_HLE/AACUcode.cpp +++ b/src/DSP_HLE/AACUcode.cpp @@ -16,7 +16,8 @@ with melonDS. If not, see http://www.gnu.org/licenses/. */ -#include +// TODO move faad stuff to Platform +#include #include "../DSi.h" #include "AACUcode.h" @@ -31,11 +32,26 @@ using Platform::LogLevel; namespace DSP_HLE { +NeAACDecHandle AACDec; + AACUcode::AACUcode(melonDS::DSi& dsi, int version) : UcodeBase(dsi) { DSi.RegisterEventFuncs(Event_DSi_DSPHLE, this, {MakeEventThunk(AACUcode, FinishCmd)}); + AACDec = NeAACDecOpen(); + + NeAACDecConfiguration* cfg = NeAACDecGetCurrentConfiguration(AACDec); + cfg->defObjectType = LC; + cfg->defSampleRate = 48000; + cfg->outputFormat = FAAD_FMT_16BIT; + NeAACDecSetConfiguration(AACDec, cfg); + + /*unsigned long freq = 48000; + unsigned char chan = 2; + int res = NeAACDecInit(AACDec, nullptr, 234, &freq, &chan); + printf("init = %d\n", res);*/ + if (version == -1) Log(LogLevel::Info, "DSP_HLE: initializing AAC decoder ucode (DSi sound app)\n"); else @@ -44,6 +60,8 @@ AACUcode::AACUcode(melonDS::DSi& dsi, int version) : UcodeBase(dsi) AACUcode::~AACUcode() { + NeAACDecClose(AACDec); + DSi.UnregisterEventFuncs(Event_DSi_DSPHLE); } @@ -55,6 +73,10 @@ void AACUcode::Reset() CmdIndex = 0; CmdParamCount = 0; memset(CmdParams, 0, sizeof(CmdParams)); + + memset(FrameBuf, 0, sizeof(FrameBuf)); + memset(LeftOutput, 0, sizeof(LeftOutput)); + memset(RightOutput, 0, sizeof(RightOutput)); } void AACUcode::DoSavestate(Savestate *file) @@ -71,7 +93,7 @@ void AACUcode::SendData(u8 index, u16 val) if (index == 1) { - printf("-- CMD1 = %04X, state=%d cmd=%d count=%d\n", val, CmdState,CmdIndex, CmdParamCount); + //printf("-- CMD1 = %04X, state=%d cmd=%d count=%d\n", val, CmdState,CmdIndex, CmdParamCount); RecvCmdWord(); } else if (index == 2) @@ -105,10 +127,7 @@ void AACUcode::RecvCmdWord() // might be different depending on sample rate etc CmdState = 2; - - // TODO actually decode shit - - DSi.ScheduleEvent(Event_DSi_DSPHLE, false, 115000, 0, 0); + CmdDecodeFrame(); } } else @@ -116,6 +135,134 @@ void AACUcode::RecvCmdWord() CmdWritten[1] = false; } +int pett = 0; +void AACUcode::CmdDecodeFrame() +{ + u16 framelen = CmdParams[0]; + u32 freq = (CmdParams[1] << 16) | CmdParams[2]; + u16 chan = CmdParams[3]; + u32 frameaddr = (CmdParams[4] << 16) | CmdParams[5]; + u32 leftaddr = (CmdParams[6] << 16) | CmdParams[7]; + u32 rightaddr = (CmdParams[8] << 16) | CmdParams[9]; + + printf("AAC: len=%d freq=%d chan=%d in=%08X out=%08X/%08X\n", + framelen, freq, chan, frameaddr, leftaddr, rightaddr); + + // verify the parameters + bool fail = false; + + if ((framelen == 0) || (framelen > 1700)) + fail = true; + if ((freq == 0) || (freq > 48000)) + fail = true; + if ((chan != 1) && (chan != 2)) + fail = true; + if (frameaddr == 0) + fail = true; + if (leftaddr == 0) + fail = true; + if ((chan != 1) && (rightaddr == 0)) + fail = true; + + // check input frequency + // this isn't entirely accurate + // in the ucode, any frequency not within the list below causes an init failure + // but the return value from the init function is ignored + u32 freqlist[9] = {48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000}; + u8 freqnum = 0xF; + for (int i = 0; i < 9; i++) + { + if (freq == freqlist[i]) + { + freqnum = 3 + i; + break; + } + } + if (freqnum == 0xF) + fail = true; + + if (fail) + { + // end the command with return code 1 (invalid parameters) + DSi.ScheduleEvent(Event_DSi_DSPHLE, false, 256, 0, 1); + return; + } + + printf("AAC: good, freq=%d\n", freqnum); + + // make an ADTS header + /* + * u32 adts[2]; + int freq = 4; + int ch = 2; + int framelen = fs & 0x1FFF; + int resv = 0x7FF; + databotte[0] = 0xFF; + databotte[1] = 0xF1; + databotte[2] = 0x40 | (freq << 2) | (ch >> 2); // freq + databotte[3] = (ch << 6) | (fs >> 11); + databotte[4] = (framelen >> 3); + databotte[5] = (framelen << 5) | (resv >> 6); + databotte[6] = (resv << 2);*/ + u32 totallen = framelen + 7; + u32 rsv = 0x7FF; + FrameBuf[0] = 0xFF; + FrameBuf[1] = 0xF1; + FrameBuf[2] = 0x40 | (freqnum << 2) | (chan >> 2); + FrameBuf[3] = (chan << 6) | (totallen >> 11); + FrameBuf[4] = (totallen >> 3); + FrameBuf[5] = (totallen << 5) | (rsv >> 6); + FrameBuf[6] = (rsv << 2); + +#define databotte FrameBuf + printf("%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + databotte[0],databotte[1],databotte[2],databotte[3], + databotte[4],databotte[5],databotte[6]); + + // read frame data + //ReadARM9Mem((u16*)&FrameBuf[7], frameaddr, framelen); + for (int i = 0; i < framelen; i++) + { + FrameBuf[7+i] = DSi.ARM9Read8(frameaddr + i); + } + + // init + // TODO only do if config changed! + if (pett < 2) + { + if (pett == 1) + { + unsigned long _freq = 0; + unsigned char _chan = 0; + int res = NeAACDecInit(AACDec, FrameBuf, totallen, &_freq, &_chan); + printf("init = %d, %ld, %d\n", res, _freq, _chan); + } + pett++; + } + + // decode + NeAACDecFrameInfo finfo; + /*void* samplebuf[2] = {LeftOutput, RightOutput}; + NeAACDecDecode2(AACDec, &finfo, FrameBuf, totallen, samplebuf, 1024*4); + printf("decode res = %d %d %d\n", finfo.error, finfo.bytesconsumed, finfo.samples); + + WriteARM9Mem((u16*)LeftOutput, leftaddr, 1024*2); + WriteARM9Mem((u16*)RightOutput, rightaddr, 1024*2); // checkme*/ + s16* dataout = (s16*)NeAACDecDecode(AACDec, &finfo, FrameBuf, totallen); + printf("decode res = %p %d %d/%d %d\n", dataout, finfo.error, (int)finfo.bytesconsumed, totallen, (int)finfo.samples); + if (dataout) + { + for (int i = 0; i < 1024; i++) + { + DSi.ARM9Write16(leftaddr, *dataout++); + DSi.ARM9Write16(rightaddr, *dataout++); + leftaddr += 2; + rightaddr += 2; + } + } + + DSi.ScheduleEvent(Event_DSi_DSPHLE, false, 115000, 0, 0); +} void AACUcode::FinishCmd(u32 param) { @@ -123,6 +270,9 @@ void AACUcode::FinishCmd(u32 param) CmdParamCount = 0; SendReply(0, param); + + if (CmdWritten[1]) + RecvCmdWord(); } diff --git a/src/DSP_HLE/AACUcode.h b/src/DSP_HLE/AACUcode.h index 2e1dbe09..04bd5a6c 100644 --- a/src/DSP_HLE/AACUcode.h +++ b/src/DSP_HLE/AACUcode.h @@ -43,7 +43,12 @@ protected: u8 CmdParamCount; u16 CmdParams[10]; + u8 FrameBuf[1707]; + s16 LeftOutput[1024]; + s16 RightOutput[1024]; + void RecvCmdWord(); + void CmdDecodeFrame(); void FinishCmd(u32 param); }; diff --git a/src/DSi_DSP.cpp b/src/DSi_DSP.cpp index 7265864c..41f37a10 100644 --- a/src/DSi_DSP.cpp +++ b/src/DSi_DSP.cpp @@ -589,8 +589,7 @@ void DSi_DSP::Write8(u32 addr, u8 val) // no REPx writes } } -bool fazil = false; -int state = 0; u32 aacaddr=0; u32 aaclen = 0; + void DSi_DSP::Write16(u32 addr, u16 val) { Log(LogLevel::Debug,"DSP WRITE16 %d %08X %08X %08X\n", IsDSPCoreEnabled(), addr, val, DSi.GetPC(0)); @@ -646,45 +645,17 @@ void DSi_DSP::Write16(u32 addr, u16 val) // SEM not writable case 0x20: // CMD0 - DSP_CMD[0] = val;printf("DSP: CMD0 = %04X\n", val); + DSP_CMD[0] = val; if (DSPCore) DSPCore->SendData(0, val); break; case 0x28: // CMD1 - DSP_CMD[1] = val;printf("DSP: CMD1 = %04X\n", val); + DSP_CMD[1] = val; if (DSPCore) DSPCore->SendData(1, val); - { - if (state==0 && val==1) - { - state = 1; - } - else if (state > 0) - { - if (state==1) aaclen = val; - if (state==5) aacaddr = val << 16; - if (state==6) aacaddr |= val; - if (state==10) - { - printf("AAC FRAME: addr=%08X len=%08X\n", aacaddr, aaclen); - - for (int i = 0; i < aaclen; i+=16) - { - printf("%08X: ", i); - int l = 16; - if ((i+l) > aaclen) l = aaclen-i; - for (int j = 0; j < l; j++) - printf("%02X ", DSi.ARM9Read8(aacaddr+i+j)); - printf("\n"); - } - } - state++; - if (state>10) state = 0; - } - } break; case 0x30: // CMD2 - DSP_CMD[2] = val;printf("DSP: CMD2 = %04X\n", val); + DSP_CMD[2] = val; if (DSPCore) DSPCore->SendData(2, val); break; diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index 08f41727..fe4d283f 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -837,7 +837,7 @@ void DSi_MMCStorage::Reset() memset(SCR, 0, 8); *(u32*)&SCR[0] = 0x012A0000; - memset(SSR, 0, 64); + memset(SD_SSR, 0, 64); BlockSize = 0; RWAddress = 0; @@ -855,7 +855,7 @@ void DSi_MMCStorage::DoSavestate(Savestate* file) file->Var32(&OCR); file->Var32(&RCA); file->VarArray(SCR, 8); - file->VarArray(SSR, 64); + file->VarArray(SD_SSR, 64); file->Var32(&BlockSize); file->Var64(&RWAddress); @@ -1014,7 +1014,7 @@ void DSi_MMCStorage::SendACMD(u8 cmd, u32 param) case 13: // get SSR Host->SendResponse(CSR, true); - Host->DataRX(SSR, 64); + Host->DataRX(SD_SSR, 64); return; case 41: // set operating conditions diff --git a/src/DSi_SD.h b/src/DSi_SD.h index 6b9b4fd8..28e2103f 100644 --- a/src/DSi_SD.h +++ b/src/DSi_SD.h @@ -200,7 +200,7 @@ private: u32 OCR; u32 RCA; u8 SCR[8]; - u8 SSR[64]; + u8 SD_SSR[64]; u32 BlockSize; u64 RWAddress; diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index b0b6e5ab..4a69b3fc 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -181,6 +181,7 @@ else() endif() target_link_libraries(melonDS PRIVATE core) target_link_libraries(melonDS PRIVATE PkgConfig::SDL2 PkgConfig::LibArchive PkgConfig::Zstd) +target_link_libraries(melonDS PRIVATE faad) # temporary hack target_link_libraries(melonDS PRIVATE ${QT_LINK_LIBS} ${CMAKE_DL_LIBS}) if (WIN32)