From 954c55e35afbb1191f97e6da2f2b05be3696e2c4 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Tue, 20 Nov 2012 03:13:55 +0100 Subject: [PATCH] New AXWii now working properly in some games I tested --- .../Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp | 61 +-- .../Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h | 104 ++-- .../Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp | 451 ++++++++++-------- .../Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h | 64 ++- .../Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h | 74 +-- 5 files changed, 429 insertions(+), 325 deletions(-) diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp index 8c2e05dce4..54bd50830d 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp @@ -16,9 +16,11 @@ // http://code.google.com/p/dolphin-emu/ #include "UCode_AX.h" -#include "UCode_AX_Voice.h" #include "../../DSP.h" +#define AX_GC +#include "UCode_AX_Voice.h" + CUCode_AX::CUCode_AX(DSPHLE* dsp_hle, u32 crc) : IUCode(dsp_hle, crc) , m_cmdlist_size(0) @@ -123,7 +125,7 @@ void CUCode_AX::HandleCommandList() addr_lo = m_cmdlist[curr_idx++]; addr2_hi = m_cmdlist[curr_idx++]; addr2_lo = m_cmdlist[curr_idx++]; - MixAUXSamples(cmd == CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2)); + MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2)); break; case CMD_UPLOAD_LRS: @@ -327,40 +329,41 @@ void CUCode_AX::ProcessPBList(u32 pb_addr) } } -void CUCode_AX::MixAUXSamples(bool AUXA, u32 write_addr, u32 read_addr) +void CUCode_AX::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr) { - int buffers[3][5 * 32]; + int temp[3][5 * 32]; + int* buffers[3] = { 0 }; + + switch (aux_id) + { + case 0: + buffers[0] = m_samples_auxA_left; + buffers[1] = m_samples_auxA_right; + buffers[2] = m_samples_auxA_surround; + break; + + case 1: + buffers[0] = m_samples_auxB_left; + buffers[1] = m_samples_auxB_right; + buffers[2] = m_samples_auxB_surround; + break; + } // First, we need to send the contents of our AUX buffers to the CPU. if (write_addr) { - for (u32 i = 0; i < 5 * 32; ++i) - { - if (AUXA) - { - buffers[0][i] = Common::swap32(m_samples_auxA_left[i]); - buffers[1][i] = Common::swap32(m_samples_auxA_right[i]); - buffers[2][i] = Common::swap32(m_samples_auxA_surround[i]); - } - else - { - buffers[0][i] = Common::swap32(m_samples_auxB_left[i]); - buffers[1][i] = Common::swap32(m_samples_auxB_right[i]); - buffers[2][i] = Common::swap32(m_samples_auxB_surround[i]); - } - } - memcpy(HLEMemory_Get_Pointer(write_addr), buffers, sizeof (buffers)); + for (u32 i = 0; i < 3 * 32; ++i) + for (u32 j = 0; j < 3; ++j) + temp[j][i] = Common::swap32(buffers[j][i]); + memcpy(HLEMemory_Get_Pointer(write_addr), temp, sizeof (temp)); } - // Then, we read the new buffers from the CPU and add to our current - // buffers. - memcpy(buffers, HLEMemory_Get_Pointer(read_addr), sizeof (buffers)); + // Then, we read the new temp from the CPU and add to our current + // temp. + memcpy(temp, HLEMemory_Get_Pointer(read_addr), sizeof (temp)); for (u32 i = 0; i < 5 * 32; ++i) - { - m_samples_left[i] += Common::swap32(buffers[0][i]); - m_samples_right[i] += Common::swap32(buffers[1][i]); - m_samples_surround[i] += Common::swap32(buffers[2][i]); - } + for (u32 j = 0; j < 3; ++j) + buffers[j][i] += Common::swap32(temp[j][i]); } void CUCode_AX::UploadLRS(u32 dst_addr) @@ -495,5 +498,7 @@ void CUCode_AX::DoState(PointerWrap& p) { std::lock_guard lk(m_processing); + // TODO + DoStateShared(p); } diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h index 29509661ed..23bc786111 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h @@ -29,7 +29,40 @@ #include "UCodes.h" #include "UCode_AXStructs.h" -#include "UCode_AX_Voice.h" + +// We can't directly use the mixer_control field from the PB because it does +// not mean the same in all AX versions. The AX UCode converts the +// mixer_control value to an AXMixControl bitfield. +enum AXMixControl +{ + MIX_L = 0x000001, + MIX_L_RAMP = 0x000002, + MIX_R = 0x000004, + MIX_R_RAMP = 0x000008, + MIX_S = 0x000010, + MIX_S_RAMP = 0x000020, + + MIX_AUXA_L = 0x000040, + MIX_AUXA_L_RAMP = 0x000080, + MIX_AUXA_R = 0x000100, + MIX_AUXA_R_RAMP = 0x000200, + MIX_AUXA_S = 0x000400, + MIX_AUXA_S_RAMP = 0x000800, + + MIX_AUXB_L = 0x001000, + MIX_AUXB_L_RAMP = 0x002000, + MIX_AUXB_R = 0x004000, + MIX_AUXB_R_RAMP = 0x008000, + MIX_AUXB_S = 0x010000, + MIX_AUXB_S_RAMP = 0x020000, + + MIX_AUXC_L = 0x040000, + MIX_AUXC_L_RAMP = 0x080000, + MIX_AUXC_R = 0x100000, + MIX_AUXC_R_RAMP = 0x200000, + MIX_AUXC_S = 0x400000, + MIX_AUXC_S_RAMP = 0x800000 +}; class CUCode_AX : public IUCode { @@ -37,16 +70,16 @@ public: CUCode_AX(DSPHLE* dsp_hle, u32 crc); virtual ~CUCode_AX(); - void HandleMail(u32 mail); - void MixAdd(short* out_buffer, int nsamples); - void Update(int cycles); - void DoState(PointerWrap& p); + virtual void HandleMail(u32 mail); + virtual void MixAdd(short* out_buffer, int nsamples); + virtual void Update(int cycles); + virtual void DoState(PointerWrap& p); // Needed because StdThread.h std::thread implem does not support member // pointers. static void SpawnAXThread(CUCode_AX* self); -private: +protected: enum MailType { MAIL_RESUME = 0xCDD10000, @@ -59,31 +92,7 @@ private: MAIL_CMDLIST_MASK = 0xFFFF0000 }; - enum CmdType - { - CMD_SETUP = 0x00, - CMD_UNK_01 = 0x01, - CMD_PB_ADDR = 0x02, - CMD_PROCESS = 0x03, - CMD_MIX_AUXA = 0x04, - CMD_MIX_AUXB = 0x05, - CMD_UPLOAD_LRS = 0x06, - CMD_SBUFFER_ADDR = 0x07, - CMD_UNK_08 = 0x08, - CMD_MIX_AUXB_NOWRITE = 0x09, - CMD_COMPRESSOR_TABLE_ADDR = 0x0A, - CMD_UNK_0B = 0x0B, - CMD_UNK_0C = 0x0C, - CMD_MORE = 0x0D, - CMD_OUTPUT = 0x0E, - CMD_END = 0x0F, - CMD_UNK_10 = 0x10, - CMD_UNK_11 = 0x11, - CMD_UNK_12 = 0x12, - CMD_UNK_13 = 0x13, - }; - - // 32 * 5 because 32 samples per millisecond, for 5 milliseconds. + // 32 * 5 because 32 samples per millisecond, for max 5 milliseconds. int m_samples_left[32 * 5]; int m_samples_right[32 * 5]; int m_samples_surround[32 * 5]; @@ -119,12 +128,39 @@ private: void NotifyAXThread(); void AXThread(); - void HandleCommandList(); - void SetupProcessing(u32 studio_addr); + + virtual void HandleCommandList(); + + void SetupProcessing(u32 init_addr); void ProcessPBList(u32 pb_addr); - void MixAUXSamples(bool AUXA, u32 write_addr, u32 read_addr); + void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr); void UploadLRS(u32 dst_addr); void OutputSamples(u32 out_addr); + +private: + enum CmdType + { + CMD_SETUP = 0x00, + CMD_UNK_01 = 0x01, + CMD_PB_ADDR = 0x02, + CMD_PROCESS = 0x03, + CMD_MIX_AUXA = 0x04, + CMD_MIX_AUXB = 0x05, + CMD_UPLOAD_LRS = 0x06, + CMD_SBUFFER_ADDR = 0x07, + CMD_UNK_08 = 0x08, + CMD_MIX_AUXB_NOWRITE = 0x09, + CMD_COMPRESSOR_TABLE_ADDR = 0x0A, + CMD_UNK_0B = 0x0B, + CMD_UNK_0C = 0x0C, + CMD_MORE = 0x0D, + CMD_OUTPUT = 0x0E, + CMD_END = 0x0F, + CMD_UNK_10 = 0x10, + CMD_UNK_11 = 0x11, + CMD_UNK_12 = 0x12, + CMD_UNK_13 = 0x13, + }; }; #endif // !_UCODE_AX_H diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp index 73abc392df..a47d9b279b 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp @@ -23,249 +23,294 @@ #include "UCodes.h" #include "UCode_AXStructs.h" #include "UCode_AXWii.h" + +#define AX_WII #include "UCode_AX_Voice.h" CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC) - : IUCode(dsp_hle, l_CRC) - , m_addressPBs(0xFFFFFFFF) + : CUCode_AX(dsp_hle, l_CRC) { - // we got loaded - m_rMailHandler.PushMail(DSP_INIT); - - templbuffer = new int[1024 * 1024]; - temprbuffer = new int[1024 * 1024]; - - wiisportsHack = m_CRC == 0xfa450138; + WARN_LOG(DSPHLE, "Instantiating CUCode_AXWii"); } CUCode_AXWii::~CUCode_AXWii() { - m_rMailHandler.Clear(); - delete [] templbuffer; - delete [] temprbuffer; } -void CUCode_AXWii::HandleMail(u32 _uMail) +void CUCode_AXWii::HandleCommandList() { - if (m_UploadSetupInProgress) + // Temp variables for addresses computation + u16 addr_hi, addr_lo; + u16 addr2_hi, addr2_lo; + u16 volume; + +// WARN_LOG(DSPHLE, "Command list:"); +// for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i) +// WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]); +// WARN_LOG(DSPHLE, "-------------"); + + u32 curr_idx = 0; + bool end = false; + while (!end) { - PrepareBootUCode(_uMail); - return; - } - else if ((_uMail & 0xFFFF0000) == MAIL_AX_ALIST) - { - // We are expected to get a new CmdBlock - DEBUG_LOG(DSPHLE, "GetNextCmdBlock (%ibytes)", (u16)_uMail); - } - else switch(_uMail) - { - case 0xCDD10000: // Action 0 - AX_ResumeTask() - m_rMailHandler.PushMail(DSP_RESUME); - break; + u16 cmd = m_cmdlist[curr_idx++]; - case 0xCDD10001: // Action 1 - new ucode upload - DEBUG_LOG(DSPHLE,"DSP IROM - New Ucode!"); - // TODO find a better way to protect from HLEMixer? - soundStream->GetMixer()->SetHLEReady(false); - m_UploadSetupInProgress = true; - break; - - case 0xCDD10002: // Action 2 - IROM_Reset(); ( WII: De Blob, Cursed Mountain,...) - DEBUG_LOG(DSPHLE,"DSP IROM - Reset!"); - m_DSPHLE->SetUCode(UCODE_ROM); - return; - - case 0xCDD10003: // Action 3 - AX_GetNextCmdBlock() - break; - - default: - DEBUG_LOG(DSPHLE, " >>>> u32 MAIL : AXTask Mail (%08x)", _uMail); - AXTask(_uMail); - break; - } -} - -void CUCode_AXWii::MixAdd(short* _pBuffer, int _iSize) -{ - AXPBWii PB; - - if (_iSize > 1024 * 1024) - _iSize = 1024 * 1024; - - memset(templbuffer, 0, _iSize * sizeof(int)); - memset(temprbuffer, 0, _iSize * sizeof(int)); - - u32 blockAddr = m_addressPBs; - if (!blockAddr) - return; - - AXBuffers buffers = {{ - templbuffer, - temprbuffer, - NULL - }}; - - for (int i = 0; i < NUMBER_OF_PBS; i++) - { - if (!ReadPB(blockAddr, PB)) - break; - -// if (wiisportsHack) -// MixAddVoice(*(AXPBWiiSports*)&PB, buffers, _iSize); -// else -// MixAddVoice(PB, buffers, _iSize); - - if (!WritePB(blockAddr, PB)) - break; - - // next PB, or done - blockAddr = (PB.next_pb_hi << 16) | PB.next_pb_lo; - if (!blockAddr) - break; - } - - // We write the sound to _pBuffer - if (_pBuffer) - { - for (int i = 0; i < _iSize; i++) + switch (cmd) { - // Clamp into 16-bit. Maybe we should add a volume compressor here. - int left = templbuffer[i] + _pBuffer[0]; - int right = temprbuffer[i] + _pBuffer[1]; - if (left < -32767) left = -32767; - else if (left > 32767) left = 32767; - if (right < -32767) right = -32767; - else if (right > 32767) right = 32767; - *_pBuffer++ = left; - *_pBuffer++ = right; + // Some of these commands are unknown, or unused in this AX HLE. + // We still need to skip their arguments using "curr_idx += N". + + case CMD_SETUP: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + SetupProcessing(HILO_TO_32(addr)); + break; + + case CMD_UNK_01: curr_idx += 2; break; + case CMD_UNK_02: curr_idx += 2; break; + case CMD_UNK_03: curr_idx += 2; break; + + case CMD_PROCESS: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + ProcessPBList(HILO_TO_32(addr)); + break; + + case CMD_MIX_AUXA: + case CMD_MIX_AUXB: + case CMD_MIX_AUXC: + curr_idx++; // TODO: Unknown u16 + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2)); + break; + + // These two go together and manipulate some AUX buffers. + case CMD_UNK_08: curr_idx += 13; break; + case CMD_UNK_09: curr_idx += 13; break; + + case CMD_UNK_0A: curr_idx += 4; break; + + case CMD_OUTPUT: + volume = m_cmdlist[curr_idx++]; + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), volume); + break; + + case CMD_UNK_0C: curr_idx += 5; break; + + case CMD_UNK_0D: + // Wiimote output? + curr_idx += 8; + break; + + case CMD_END: + end = true; + break; } } } - -void CUCode_AXWii::Update(int cycles) +void CUCode_AXWii::SetupProcessing(u32 init_addr) { - if (NeedsResumeMail()) + // TODO: should be easily factorizable with AX + s16 init_data[60]; + + for (u32 i = 0; i < 60; ++i) + init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i); + + // List of all buffers we have to initialize + int* buffers[] = { + m_samples_left, + m_samples_right, + m_samples_surround, + m_samples_auxA_left, + m_samples_auxA_right, + m_samples_auxA_surround, + m_samples_auxB_left, + m_samples_auxB_right, + m_samples_auxB_surround, + m_samples_auxC_left, + m_samples_auxC_right, + m_samples_auxC_surround + }; + + u32 init_idx = 0; + for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i) { - m_rMailHandler.PushMail(DSP_RESUME); - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); - } - // check if we have to send something - else if (!m_rMailHandler.IsEmpty()) - { - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]); + s16 delta = (s16)init_data[init_idx + 2]; + + init_idx += 3; + + if (!init_val) + memset(buffers[i], 0, 3 * 32 * sizeof (int)); + else + { + for (u32 j = 0; j < 3 * 32; ++j) + { + buffers[i][j] = init_val; + init_val += delta; + } + } } } -// AX seems to bootup one task only and waits for resume-callbacks -// everytime the DSP has "spare time" it sends a resume-mail to the CPU -// and the __DSPHandler calls a AX-Callback which generates a new AXFrame -bool CUCode_AXWii::AXTask(u32& _uMail) +AXMixControl CUCode_AXWii::ConvertMixerControl(u32 mixer_control) { - u32 uAddress = _uMail; - u32 Addr__AXStudio; - u32 Addr__AXOutSBuffer; - bool bExecuteList = true; + u32 ret = 0; -/* - for (int i=0;i<64;i++) { - NOTICE_LOG(DSPHLE,"%x - %08x",uAddress+(i*4),HLEMemory_Read_U32(uAddress+(i*4))); - } -*/ + if (mixer_control & 0x00000001) ret |= MIX_L; + if (mixer_control & 0x00000002) ret |= MIX_R; + if (mixer_control & 0x00000004) ret |= MIX_L_RAMP | MIX_R_RAMP; + if (mixer_control & 0x00000008) ret |= MIX_S; + if (mixer_control & 0x00000010) ret |= MIX_S_RAMP; + if (mixer_control & 0x00010000) ret |= MIX_AUXA_L; + if (mixer_control & 0x00020000) ret |= MIX_AUXA_R; + if (mixer_control & 0x00040000) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; + if (mixer_control & 0x00080000) ret |= MIX_AUXA_S; + if (mixer_control & 0x00100000) ret |= MIX_AUXA_S_RAMP; + if (mixer_control & 0x00200000) ret |= MIX_AUXB_L; + if (mixer_control & 0x00400000) ret |= MIX_AUXB_R; + if (mixer_control & 0x00800000) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; + if (mixer_control & 0x01000000) ret |= MIX_AUXB_S; + if (mixer_control & 0x02000000) ret |= MIX_AUXB_S_RAMP; + if (mixer_control & 0x04000000) ret |= MIX_AUXC_L; + if (mixer_control & 0x08000000) ret |= MIX_AUXC_R; + if (mixer_control & 0x10000000) ret |= MIX_AUXC_L_RAMP | MIX_AUXC_R_RAMP; + if (mixer_control & 0x20000000) ret |= MIX_AUXC_S; + if (mixer_control & 0x40000000) ret |= MIX_AUXC_S_RAMP; - while (bExecuteList) + return (AXMixControl)ret; +} + +void CUCode_AXWii::ProcessPBList(u32 pb_addr) +{ + const u32 spms = 32; + + AXPBWii pb; + + while (pb_addr) { - u16 iCommand = HLEMemory_Read_U16(uAddress); - uAddress += 2; - //NOTICE_LOG(DSPHLE,"AXWII - AXLIST CMD %X",iCommand); + AXBuffers buffers = {{ + m_samples_left, + m_samples_right, + m_samples_surround, + m_samples_auxA_left, + m_samples_auxA_right, + m_samples_auxA_surround, + m_samples_auxB_left, + m_samples_auxB_right, + m_samples_auxB_surround, + m_samples_auxC_left, + m_samples_auxC_right, + m_samples_auxC_surround + }}; - switch (iCommand) + if (!ReadPB(pb_addr, pb)) + break; + + for (int curr_ms = 0; curr_ms < 3; ++curr_ms) { - case 0x0000: - Addr__AXStudio = HLEMemory_Read_U32(uAddress); - uAddress += 4; - break; + Process1ms(pb, buffers, ConvertMixerControl(HILO_TO_32(pb.mixer_control))); - case 0x0001: - uAddress += 4; - break; - - case 0x0003: - uAddress += 4; - break; - - case 0x0004: - // PBs are here now - m_addressPBs = HLEMemory_Read_U32(uAddress); - soundStream->GetMixer()->SetHLEReady(true); -// soundStream->Update(); - uAddress += 4; - break; - - case 0x0005: - if (!wiisportsHack) - uAddress += 10; - break; - - case 0x0006: - uAddress += 10; - break; - - case 0x0007: // AXLIST_SBUFFER - Addr__AXOutSBuffer = HLEMemory_Read_U32(uAddress); - uAddress += 10; - break; - - case 0x0008: - uAddress += 26; - break; - - case 0x000a: - uAddress += wiisportsHack ? 4 : 8; // AXLIST_COMPRESSORTABLE - break; - - case 0x000b: - uAddress += wiisportsHack ? 2 : 10; - break; - - case 0x000c: - uAddress += wiisportsHack ? 8 : 10; - break; - - case 0x000d: - uAddress += 16; - break; - - case 0x000e: - if (wiisportsHack) - uAddress += 16; - else - bExecuteList = false; - break; - - case 0x000f: // only for Wii Sports uCode - bExecuteList = false; - break; - - default: - INFO_LOG(DSPHLE,"DSPHLE - AXwii - AXLIST - Unknown CMD: %x",iCommand); - // unknown command so stop the execution of this TaskList - bExecuteList = false; - break; + // Forward the buffers + for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i) + buffers.ptrs[i] += spms; } + + WritePB(pb_addr, pb); + pb_addr = HILO_TO_32(pb.next_pb); + } +} + +void CUCode_AXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr) +{ + int temp[3][3 * 32]; + int* buffers[3] = { 0 }; + + switch (aux_id) + { + case 0: + buffers[0] = m_samples_auxA_left; + buffers[1] = m_samples_auxA_right; + buffers[2] = m_samples_auxA_surround; + break; + + case 1: + buffers[0] = m_samples_auxB_left; + buffers[1] = m_samples_auxB_right; + buffers[2] = m_samples_auxB_surround; + break; + + case 2: + buffers[0] = m_samples_auxC_left; + buffers[1] = m_samples_auxC_right; + buffers[2] = m_samples_auxC_surround; + break; } - m_rMailHandler.PushMail(DSP_YIELD); //its here in case there is a CMD fuckup - return true; + // Send the content of AUX buffers to the CPU + if (write_addr) + { + for (u32 i = 0; i < 3 * 32; ++i) + for (u32 j = 0; j < 3; ++j) + temp[j][i] = Common::swap32(buffers[j][i]); + memcpy(HLEMemory_Get_Pointer(write_addr), temp, sizeof (temp)); + } + + // Then read the buffers from the CPU and add to our current buffers. + memcpy(temp, HLEMemory_Get_Pointer(read_addr), sizeof (temp)); + for (u32 i = 0; i < 3 * 32; ++i) + for (u32 j = 0; j < 3; ++j) + buffers[j][i] += Common::swap32(temp[j][i]); +} + +void CUCode_AXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume) +{ + int surround_buffer[3 * 32] = { 0 }; + + for (u32 i = 0; i < 3 * 32; ++i) + surround_buffer[i] = Common::swap32(m_samples_surround[i]); + memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer)); + + short buffer[3 * 32 * 2]; + + // Clamp internal buffers to 16 bits. + for (u32 i = 0; i < 3 * 32; ++i) + { + int left = m_samples_left[i]; + int right = m_samples_right[i]; + + if (left < -32767) left = -32767; + if (left > 32767) left = 32767; + if (right < -32767) right = -32767; + if (right > 32767) right = 32767; + + m_samples_left[i] = left; + m_samples_right[i] = right; + } + + for (u32 i = 0; i < 3 * 32; ++i) + { + buffer[2 * i] = Common::swap16(m_samples_left[i]); + buffer[2 * i + 1] = Common::swap16(m_samples_right[i]); + } + + memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer)); } void CUCode_AXWii::DoState(PointerWrap &p) { std::lock_guard lk(m_csMix); - p.Do(m_addressPBs); - p.Do(wiisportsHack); + // TODO DoStateShared(p); } diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h index 1e6cffcba0..d488bd046c 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h @@ -12,44 +12,58 @@ // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ -// Official SVN repository and contact information can be found at +// Official Git repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -#ifndef _UCODE_AXWII -#define _UCODE_AXWII +#ifndef _UCODE_AXWII_H +#define _UCODE_AXWII_H -#include "UCode_AXStructs.h" +#include "UCode_AX.h" -#define NUMBER_OF_PBS 128 - -class CUCode_AXWii : public IUCode +class CUCode_AXWii : public CUCode_AX { public: CUCode_AXWii(DSPHLE *dsp_hle, u32 _CRC); virtual ~CUCode_AXWii(); - void HandleMail(u32 _uMail); - void MixAdd(short* _pBuffer, int _iSize); - void Update(int cycles); - void DoState(PointerWrap &p); + virtual void DoState(PointerWrap &p); + +protected: + int m_samples_auxC_left[32 * 3]; + int m_samples_auxC_right[32 * 3]; + int m_samples_auxC_surround[32 * 3]; + + // Convert a mixer_control bitfield to our internal representation for that + // value. Required because that bitfield has a different meaning in some + // versions of AX. + AXMixControl ConvertMixerControl(u32 mixer_control); + + virtual void HandleCommandList(); + + void SetupProcessing(u32 init_addr); + void ProcessPBList(u32 pb_addr); + void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr); + void OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume); private: - enum + enum CmdType { - MAIL_AX_ALIST = 0xBABE0000, + CMD_SETUP = 0x00, + CMD_UNK_01 = 0x01, + CMD_UNK_02 = 0x02, + CMD_UNK_03 = 0x03, + CMD_PROCESS = 0x04, + CMD_MIX_AUXA = 0x05, + CMD_MIX_AUXB = 0x06, + CMD_MIX_AUXC = 0x07, + CMD_UNK_08 = 0x08, + CMD_UNK_09 = 0x09, + CMD_UNK_0A = 0x0A, + CMD_OUTPUT = 0x0B, + CMD_UNK_0C = 0x0C, + CMD_UNK_0D = 0x0D, + CMD_END = 0x0E }; - - // PBs - u32 m_addressPBs; - - bool wiisportsHack; - - int *templbuffer; - int *temprbuffer; - - // ax task message handler - bool AXTask(u32& _uMail); - void SendMail(u32 _uMail); }; #endif // _UCODE_AXWII diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h index 20fea41677..22ef0583ce 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h @@ -15,13 +15,27 @@ // Official Git repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ +// This file is UGLY (full of #ifdef) so that it can be used with both GC and +// Wii version of AX. Maybe it would be better to abstract away the parts that +// can be made common. + #ifndef _UCODE_AX_VOICE_H #define _UCODE_AX_VOICE_H +#if !defined(AX_GC) && !defined(AX_WII) +#error UCode_AX_Voice.h included without specifying version +#endif + #include "Common.h" #include "UCode_AXStructs.h" #include "../../DSP.h" +#ifdef AX_GC +# define PB_TYPE AXPB +#else +# define PB_TYPE AXPBWii +#endif + // Useful macro to convert xxx_hi + xxx_lo to xxx for 32 bits. #define HILO_TO_32(name) \ ((name##_hi << 16) | name##_lo) @@ -42,41 +56,23 @@ union AXBuffers int* auxB_left; int* auxB_right; int* auxB_surround; + +#ifdef AX_WII + int* auxC_left; + int* auxC_right; + int* auxC_surround; +#endif }; +#ifdef AX_GC int* ptrs[9]; -}; - -// We can't directly use the mixer_control field from the PB because it does -// not mean the same in all AX versions. The AX UCode converts the -// mixer_control value to an AXMixControl bitfield. -enum AXMixControl -{ - MIX_L = 0x00001, - MIX_L_RAMP = 0x00002, - MIX_R = 0x00004, - MIX_R_RAMP = 0x00008, - MIX_S = 0x00010, - MIX_S_RAMP = 0x00020, - - MIX_AUXA_L = 0x00040, - MIX_AUXA_L_RAMP = 0x00080, - MIX_AUXA_R = 0x00100, - MIX_AUXA_R_RAMP = 0x00200, - MIX_AUXA_S = 0x00400, - MIX_AUXA_S_RAMP = 0x00800, - - MIX_AUXB_L = 0x01000, - MIX_AUXB_L_RAMP = 0x02000, - MIX_AUXB_R = 0x04000, - MIX_AUXB_R_RAMP = 0x08000, - MIX_AUXB_S = 0x10000, - MIX_AUXB_S_RAMP = 0x20000 +#else + int* ptrs[12]; +#endif }; // Read a PB from MRAM/ARAM -template -bool ReadPB(u32 addr, PBType& pb) +bool ReadPB(u32 addr, PB_TYPE& pb) { u16* dst = (u16*)&pb; const u16* src = (const u16*)Memory::GetPointer(addr); @@ -90,8 +86,7 @@ bool ReadPB(u32 addr, PBType& pb) } // Write a PB back to MRAM/ARAM -template -inline bool WritePB(u32 addr, const PBType& pb) +inline bool WritePB(u32 addr, const PB_TYPE& pb) { const u16* src = (const u16*)&pb; u16* dst = (u16*)Memory::GetPointer(addr); @@ -107,10 +102,10 @@ inline bool WritePB(u32 addr, const PBType& pb) // Simulated accelerator state. static u32 acc_loop_addr, acc_end_addr; static u32* acc_cur_addr; -static AXPB* acc_pb; +static PB_TYPE* acc_pb; // Sets up the simulated accelerator. -inline void AcceleratorSetup(AXPB* pb, u32* cur_addr) +inline void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr) { acc_pb = pb; acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr); @@ -216,7 +211,7 @@ inline u16 AcceleratorGetSample() } // Read 32 input samples from ARAM, decoding and converting rate if required. -inline void GetInputSamples(AXPB& pb, s16* samples) +inline void GetInputSamples(PB_TYPE& pb, s16* samples) { u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr); AcceleratorSetup(&pb, &cur_addr); @@ -319,7 +314,7 @@ inline void MixAdd(int* out, const s16* input, u16* pvol, bool ramp) } // Process 1ms of audio (32 samples) from a PB and mix it to the buffers. -inline void Process1ms(AXPB& pb, const AXBuffers& buffers, AXMixControl mctrl) +void Process1ms(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl) { // If the voice is not running, nothing to do. if (!pb.running) @@ -370,6 +365,15 @@ inline void Process1ms(AXPB& pb, const AXBuffers& buffers, AXMixControl mctrl) if (mctrl & MIX_AUXB_S) MixAdd(buffers.auxB_surround, samples, &pb.mixer.auxB_surround, mctrl & MIX_AUXB_S_RAMP); +#ifdef AX_WII + if (mctrl & MIX_AUXC_L) + MixAdd(buffers.auxC_left, samples, &pb.mixer.auxC_left, mctrl & MIX_AUXC_L_RAMP); + if (mctrl & MIX_AUXC_R) + MixAdd(buffers.auxC_right, samples, &pb.mixer.auxC_right, mctrl & MIX_AUXC_R_RAMP); + if (mctrl & MIX_AUXC_S) + MixAdd(buffers.auxC_surround, samples, &pb.mixer.auxC_surround, mctrl & MIX_AUXC_S_RAMP); +#endif + // Optionally, phase shift left or right channel to simulate 3D sound. if (pb.initial_time_delay.on) {