diff --git a/Source/Plugins/Plugin_DSP_HLE/Plugin_DSP_HLE.vcproj b/Source/Plugins/Plugin_DSP_HLE/Plugin_DSP_HLE.vcproj index 1c16f33808..d285a1a1ab 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Plugin_DSP_HLE.vcproj +++ b/Source/Plugins/Plugin_DSP_HLE/Plugin_DSP_HLE.vcproj @@ -1,7 +1,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - @@ -616,7 +608,7 @@ /> + + @@ -817,22 +813,6 @@ UsePrecompiledHeader="1" /> - - - - - - @@ -841,6 +821,14 @@ UsePrecompiledHeader="1" /> + + + @@ -849,6 +837,14 @@ UsePrecompiledHeader="1" /> + + + diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/SConscript b/Source/Plugins/Plugin_DSP_HLE/Src/SConscript index 3e6f5a9683..d31141e0d2 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/SConscript +++ b/Source/Plugins/Plugin_DSP_HLE/Src/SConscript @@ -8,7 +8,7 @@ name = "Plugin_DSP_HLE" files = [ 'DSPHandler.cpp', 'MailHandler.cpp', - 'HLEMixer.cpp', + 'HLEMixer.cpp', 'main.cpp', 'Config.cpp', 'Globals.cpp', @@ -17,7 +17,6 @@ files = [ 'UCodes/UCode_AXWii.cpp', 'UCodes/UCode_CARD.cpp', 'UCodes/UCode_InitAudioSystem.cpp', - 'UCodes/UCode_Jac.cpp', 'UCodes/UCode_ROM.cpp', 'UCodes/UCodes.cpp', 'UCodes/UCode_Zelda.cpp', diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Jac.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Jac.cpp deleted file mode 100644 index 7d471565b3..0000000000 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Jac.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (C) 2003-2008 Dolphin 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. - -// 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 SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "../Globals.h" -#include "UCodes.h" -#include "UCode_Jac.h" -#include "../MailHandler.h" - -CUCode_Jac::CUCode_Jac(CMailHandler& _rMailHandler) - : IUCode(_rMailHandler) - , m_bListInProgress(false) -{ - DEBUG_LOG(DSPHLE, "CUCode_Jac: init"); - m_rMailHandler.PushMail(0xDCD10000); - m_rMailHandler.PushMail(0x80000000); -} - - -CUCode_Jac::~CUCode_Jac() -{ - m_rMailHandler.Clear(); -} - - -void CUCode_Jac::HandleMail(u32 _uMail) -{ - // this is prolly totally bullshit and should work like the zelda one... - // but i am to lazy to change it atm - - if (m_bListInProgress == false) - { - // get the command to find out how much steps it has - switch (_uMail & 0xFFFF) - { - // release halt - case 0x00: - // m_Mails.push(0x80000000); - g_dspInitialize.pGenerateDSPInterrupt(); - break; - - case 0x40: - m_step = 0; - ((u32*)m_Buffer)[m_step++] = _uMail; - m_bListInProgress = true; - m_numSteps = 5; - break; - - case 0x2000: - case 0x4000: - m_step = 0; - ((u32*)m_Buffer)[m_step++] = _uMail; - m_bListInProgress = true; - m_numSteps = 3; - break; - - default: - PanicAlert("UCode Jac"); - DEBUG_LOG(DSPHLE, "UCode Jac - unknown cmd: %x", _uMail & 0xFFFF); - break; - } - } - else - { - ((u32*)m_Buffer)[m_step] = _uMail; - m_step++; - - if (m_step == m_numSteps) - { - ExecuteList(); - m_bListInProgress = false; - } - } -} - - -void CUCode_Jac::Update(int cycles) -{ - // check if we have to sent something -/* if (!g_MailHandler.empty()) - { - g_dspInitialize.pGenerateDSPInterrupt(); - }*/ -} - - -void CUCode_Jac::ExecuteList() -{ - // begin with the list - m_readOffset = 0; - - u16 cmd = Read16(); - u16 sync = Read16(); - - DEBUG_LOG(DSPHLE, "=============================================================================="); - DEBUG_LOG(DSPHLE, "UCode Jac - execute dlist (cmd: 0x%04x : sync: 0x%04x)", cmd, sync); - - switch (cmd) - { - // ============================================================================== - // DsetupTable - // ============================================================================== - case 0x40: - { - u32 tmp[4]; - tmp[0] = Read32(); - tmp[1] = Read32(); - tmp[2] = Read32(); - tmp[3] = Read32(); - - DEBUG_LOG(DSPHLE, "DsetupTable"); - DEBUG_LOG(DSPHLE, "???: 0x%08x", tmp[0]); - DEBUG_LOG(DSPHLE, "DSPRES_FILTER (size: 0x40): 0x%08x", tmp[1]); - DEBUG_LOG(DSPHLE, "DSPADPCM_FILTER (size: 0x500): 0x%08x", tmp[2]); - DEBUG_LOG(DSPHLE, "???: 0x%08x", tmp[3]); - } - break; - - // ============================================================================== - // UpdateDSPChannel - // ============================================================================== - case 0x2000: - case 0x4000: // animal crossing - { - u32 tmp[3]; - tmp[0] = Read32(); - tmp[1] = Read32(); - tmp[2] = Read32(); - - DEBUG_LOG(DSPHLE, "UpdateDSPChannel"); - DEBUG_LOG(DSPHLE, "audiomemory: 0x%08x", tmp[0]); - DEBUG_LOG(DSPHLE, "audiomemory: 0x%08x", tmp[1]); - DEBUG_LOG(DSPHLE, "DSPADPCM_FILTER (size: 0x40): 0x%08x", tmp[2]); - } - break; - - default: - PanicAlert("UCode Jac unknown cmd: %s (size %i)", cmd, m_numSteps); - DEBUG_LOG(DSPHLE, "Jac UCode - unknown cmd: %x (size %i)", cmd, m_numSteps); - break; - } - - // sync, we are ready. - m_rMailHandler.PushMail(DSP_SYNC); - m_rMailHandler.PushMail(0xF3550000 | sync); -} - - diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Jac.h b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Jac.h deleted file mode 100644 index a65b96287a..0000000000 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Jac.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2003-2008 Dolphin 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. - -// 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 SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _UCODE_JAC -#define _UCODE_JAC - -#include "UCodes.h" - -// This uCode should be deleted and replaced with a small modification of the Zelda uCode. -// The big difference is that games using this one won't send "message counts" -// before sending the command data. - -class CUCode_Jac : public IUCode -{ -private: - - enum EDSP_Codes - { - DSP_INIT = 0xDCD10000, - DSP_RESUME = 0xDCD10001, - DSP_YIELD = 0xDCD10002, - DSP_DONE = 0xDCD10003, - DSP_SYNC = 0xDCD10004, - DSP_UNKN = 0xDCD10005, - }; - - bool m_bListInProgress; - int m_numSteps; - int m_step; - u8 m_Buffer[1024]; - void ExecuteList(); - - u32 m_readOffset; - - u8 Read8() - { - return(m_Buffer[m_readOffset++]); - } - - // Hmm, don't these need bswaps? - u16 Read16() - { - u16 res = *(u16*)&m_Buffer[m_readOffset]; - m_readOffset += 2; - return(res); - } - - u32 Read32() - { - u32 res = *(u32*)&m_Buffer[m_readOffset]; - m_readOffset += 4; - return(res); - } - -public: - CUCode_Jac(CMailHandler& _rMailHandler); - virtual ~CUCode_Jac(); - - void HandleMail(u32 _uMail); - void Update(int cycles); -}; - -#endif - diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp index 6ad0b50ac1..46150d52d3 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp @@ -34,12 +34,12 @@ CUCode_Zelda::CUCode_Zelda(CMailHandler& _rMailHandler, u32 _CRC) IUCode(_rMailHandler), m_CRC(_CRC), - m_bSyncInProgress(0), + m_bSyncInProgress(false), m_MaxVoice(0), m_NumVoices(0), - m_bSyncCmdPending(0), + m_bSyncCmdPending(false), m_CurVoice(0), m_CurBuffer(0), m_NumBuffers(0), @@ -55,7 +55,7 @@ CUCode_Zelda::CUCode_Zelda(CMailHandler& _rMailHandler, u32 _CRC) m_DMABaseAddr(0), m_numSteps(0), - m_bListInProgress(0), + m_bListInProgress(false), m_step(0), m_readOffset(0), @@ -67,9 +67,19 @@ CUCode_Zelda::CUCode_Zelda(CMailHandler& _rMailHandler, u32 _CRC) m_PBAddress2(0) { DEBUG_LOG(DSPHLE, "UCode_Zelda - add boot mails for handshake"); + if (LuigiStyle()) + NOTICE_LOG(DSPHLE, "Luigi Stylee!"); + m_rMailHandler.PushMail(DSP_INIT); - g_dspInitialize.pGenerateDSPInterrupt(); - m_rMailHandler.PushMail(0xF3551111); // handshake + if (LuigiStyle()) + { + m_rMailHandler.PushMail(0x80000000); + } + else + { + g_dspInitialize.pGenerateDSPInterrupt(); + m_rMailHandler.PushMail(0xF3551111); // handshake + } m_TempBuffer = new s32[256 * 1024]; m_LeftBuffer = new s32[256 * 1024]; @@ -90,10 +100,29 @@ CUCode_Zelda::~CUCode_Zelda() delete [] m_RightBuffer; } +bool CUCode_Zelda::LuigiStyle() const +{ + switch (m_CRC) + { + case 0x42f64ac4: // Luigi + case 0x0267d05a: // http://forums.dolphin-emu.com/thread-2134.html Pikmin PAL + case 0x4be6a5cb: // AC, Pikmin + case 0x088e38a5: // IPL - JAP + case 0xd73338cf: // IPL + return true; + default: + return false; + } +} + void CUCode_Zelda::Update(int cycles) { - if (!m_rMailHandler.IsEmpty()) - g_dspInitialize.pGenerateDSPInterrupt(); + // if (!m_rMailHandler.IsEmpty()) + + if (!LuigiStyle()) { + if (m_rMailHandler.GetNextMail() == DSP_FRAME_END) + g_dspInitialize.pGenerateDSPInterrupt(); + } /* if (m_bSyncCmdPending && (m_CurBuffer == m_NumBuffers) && (m_rMailHandler.IsEmpty())) { m_rMailHandler.PushMail(DSP_FRAME_END); @@ -110,7 +139,6 @@ void CUCode_Zelda::Update(int cycles) void CUCode_Zelda::HandleMail(u32 _uMail) { // WARN_LOG(DSPHLE, "Zelda uCode: Handle mail %08X", _uMail); - if (m_bSyncInProgress) { if (m_bSyncCmdPending) @@ -171,12 +199,12 @@ void CUCode_Zelda::HandleMail(u32 _uMail) } return; - } +reread: if (m_bListInProgress) { - if (m_step < 0 || m_step >= sizeof(m_Buffer)/4) + if (m_step < 0 || m_step >= sizeof(m_Buffer) / 4) PanicAlert("m_step out of range"); ((u32*)m_Buffer)[m_step] = _uMail; @@ -191,11 +219,19 @@ void CUCode_Zelda::HandleMail(u32 _uMail) return; } + // Here holds: m_bSyncInProgress == false && m_bListInProgress == false + if (_uMail == 0) { - m_bSyncInProgress = true; + if (!LuigiStyle()) + m_bSyncInProgress = true; + else { + soundStream->GetMixer()->SetHLEReady(true); + soundStream->Update(); //do it in this thread to avoid sync problems + g_dspInitialize.pGenerateDSPInterrupt(); + } } - else if ((_uMail >> 16) == 0) + else if (!LuigiStyle() && (_uMail >> 16) == 0) { m_bListInProgress = true; m_numSteps = _uMail; @@ -220,7 +256,35 @@ void CUCode_Zelda::HandleMail(u32 _uMail) return; } } - else + else if (LuigiStyle() && (_uMail >> 28) == 0x8) + { + m_bListInProgress = true; + m_step = 0; + m_numSteps = 0; + // We have to guess the message size. + int command = (_uMail & 0xFFFF); + switch (command) + { + case 0x0000: + g_dspInitialize.pGenerateDSPInterrupt(); + break; + case 0x0040: + m_numSteps = 5; + ERROR_LOG(DSPHLE, "WE GUESS STEPS: %i", m_numSteps); + break; + case 0x2000: + case 0x4000: + m_numSteps = 3; + ERROR_LOG(DSPHLE, "WE GUESS STEPS: %i", m_numSteps); + break; + default: + ERROR_LOG(DSPHLE, "LUIGI UNKNOWN: %i", command); + break; + } + // UGLY + goto reread; + } + else { WARN_LOG(DSPHLE, "Zelda uCode: unknown mail %08X", _uMail); } @@ -237,8 +301,27 @@ void CUCode_Zelda::ExecuteList() u32 Sync = CmdMail >> 16; u32 ExtraData = CmdMail & 0xFFFF; - DEBUG_LOG(DSPHLE, "=============================================================================="); - DEBUG_LOG(DSPHLE, "Zelda UCode - execute dlist (cmd: 0x%04x : sync: 0x%04x)", Command, Sync); + if (!LuigiStyle()) { + DEBUG_LOG(DSPHLE, "=============================================================================="); + DEBUG_LOG(DSPHLE, "Zelda UCode - execute dlist (cmd: 0x%04x : sync: 0x%04x)", Command, Sync); + } + else + { + Command = CmdMail & 0xFFFF; + DEBUG_LOG(DSPHLE, "=============================================================================="); + DEBUG_LOG(DSPHLE, "Zelda UCode L-mode - execute dlist (cmd: 0x%04x : sync: 0x%04x)", Command, Sync); + + // Translate Luigi commands + switch (Command) { + case 0x0040: Command = 0x01; break; + case 0x2000: + case 0x4000: Command = 2; break; + default: + DEBUG_LOG(DSPHLE, "Luigi translate: FAIL %04x", Command); + break; + } + } + switch (Command) { @@ -251,8 +334,13 @@ void CUCode_Zelda::ExecuteList() m_AFCCoefTableAddr = Read32() & 0x7FFFFFFF; m_ReverbPBsAddr = Read32() & 0x7FFFFFFF; // WARNING: reverb PBs are very different from voice PBs! + // Read the other table + u16 *TempPtr = (u16*) g_dspInitialize.pGetMemoryPointer(m_UnkTableAddr); + for (int i = 0; i < 0x280; i++) + m_MiscTable[i] = (s16)Common::swap16(TempPtr[i]); + // Read AFC coef table - u16 *TempPtr = (u16*) g_dspInitialize.pGetMemoryPointer(m_AFCCoefTableAddr); + TempPtr = (u16*) g_dspInitialize.pGetMemoryPointer(m_AFCCoefTableAddr); for (int i = 0; i < 32; i++) m_AFCCoefTable[i] = (s16)Common::swap16(TempPtr[i]); @@ -274,11 +362,13 @@ void CUCode_Zelda::ExecuteList() // SyncFrame ... zelda ww jumps to 0x0243 case 0x02: { - //soundStream->GetMixer()->SetHLEReady(true); + //soundStream->GetMixer()->SetHLEReady(true); // DEBUG_LOG(DSPHLE, "Update the SoundThread to be in sync"); //soundStream->Update(); //do it in this thread to avoid sync problems - m_bSyncCmdPending = true; + if (!LuigiStyle()) + m_bSyncCmdPending = true; + m_CurBuffer = 0; m_NumBuffers = (CmdMail >> 16) & 0xFF; @@ -294,8 +384,11 @@ void CUCode_Zelda::ExecuteList() DEBUG_LOG(DSPHLE, "Right buffer address: 0x%08x", m_RightBuffersAddr); DEBUG_LOG(DSPHLE, "Left buffer address: 0x%08x", m_LeftBuffersAddr); - } - return; + if (LuigiStyle()) + break; + else + return; + } // Simply sends the sync messages @@ -309,7 +402,7 @@ void CUCode_Zelda::ExecuteList() case 0x09: break; // dunno ... zelda ww jmps to 0x044d */ - // DsetDolbyDelay ... zelda ww jumps to 0x00b2 + // DsetDolbyDelay ... zelda ww jumps to 0x00b2 case 0x0d: { u32 tmp = Read32(); @@ -336,56 +429,11 @@ void CUCode_Zelda::ExecuteList() // sync, we are ready m_rMailHandler.PushMail(DSP_SYNC); - g_dspInitialize.pGenerateDSPInterrupt(); + if (!LuigiStyle()) + g_dspInitialize.pGenerateDSPInterrupt(); m_rMailHandler.PushMail(0xF3550000 | Sync); } -// size is in stereo samples. -void CUCode_Zelda::MixAdd(short* _Buffer, int _Size) -{ - if (_Size > 256 * 1024) - _Size = 256 * 1024; - - memset(m_LeftBuffer, 0, _Size * sizeof(s32)); - memset(m_RightBuffer, 0, _Size * sizeof(s32)); - - for (u32 i = 0; i < m_NumVoices; i++) - { - u32 flags = m_SyncFlags[(i >> 4) & 0xF]; - if (!(flags & 1 << (15 - (i & 0xF)))) - continue; - - ZeldaVoicePB pb; - ReadVoicePB(m_VoicePBsAddr + (i * 0x180), pb); - - if (pb.Status == 0) - continue; - if (pb.KeyOff != 0) - continue; - - RenderAddVoice(pb, m_LeftBuffer, m_RightBuffer, _Size); - WritebackVoicePB(m_VoicePBsAddr + (i * 0x180), pb); - } - - if (_Buffer) - { - for (u32 i = 0; i < _Size; i++) - { - s32 left = (s32)_Buffer[0] + m_LeftBuffer[i]; - s32 right = (s32)_Buffer[1] + m_RightBuffer[i]; - - if (left < -32768) left = -32768; - if (left > 32767) left = 32767; - _Buffer[0] = (short)left; - - if (right < -32768) right = -32768; - if (right > 32767) right = 32767; - _Buffer[1] = (short)right; - - _Buffer += 2; - } - } -} void CUCode_Zelda::DoState(PointerWrap &p) { p.Do(m_CRC); diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h index 34fb077bd7..96339072a4 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h @@ -26,84 +26,96 @@ // * L/R Pan // * (probably) choice of resampling algorithm (point, linear, cubic) -struct ZeldaVoicePB +union ZeldaVoicePB { - // Read-Write part - u16 Status; // 0x00 | 1 = play, 0 = stop - u16 KeyOff; // 0x01 | writing 1 stops voice? - u16 RatioInt; // 0x02 | Position delta (playback speed) - u16 Unk03; // 0x03 | unknown - u16 NeedsReset; // 0x04 | indicates if some values in PB need to be reset - u16 ReachedEnd; // 0x05 | set to 1 when end reached - u16 IsBlank; // 0x06 | 0 = normal sound, 1 = samples are always the same - u16 Unk07; // 0x07 | unknown, in zelda always 0x0010 - u16 SoundType; // 0x08 | Sound type: so far in zww: 0x0d00 for music, 0x4861 for sfx - u16 volumeLeft1; // 0x09 | Left Volume 1 // There's probably two of each because they should be ramped within each frame. - u16 volumeLeft2; // 0x0A | Left Volume 2 - u16 Unk0B[2]; // 0x0B | unknown - u16 volumeRight1; // 0x0D | Right Volume 1 - u16 volumeRight2; // 0x0E | Right Volume 2 - u16 Unk0F[2]; // 0x0F | unknown // Buffer / something, see 036e/ZWW. there's a pattern here - u16 volumeUnknown1_1; // 0x11 | Unknown Volume 1 - u16 volumeUnknown1_2; // 0x12 | Unknown Volume 1 - u16 Unk13[2]; // 0x13 | unknown - u16 volumeUnknown2_1; // 0x15 | Unknown Volume 2 - u16 volumeUnknown2_2; // 0x16 | Unknown Volume 2 - u16 Unk17; // 0x17 | unknown - u16 Unk18[0x10]; // 0x18 | unknown - u16 Unk28; // 0x28 | unknown - u16 Unk29; // 0x29 | unknown // multiplied by 0x2a @ 0d21/ZWW - u16 Unk2a; // 0x2A | unknown // loaded at 0d2e/ZWW - u16 Unk2b; // 0x2B | unknown - u16 Unk2C; // 0x2C | unknown // See 0337/ZWW - u16 Unk2D; // 0x2D | unknown - u16 Unk2E; // 0x2E | unknown - u16 Unk2F; // 0x2F | unknown - u16 CurSampleFrac; // 0x30 | Fractional part of the current sample position - u16 Unk31; // 0x31 | unknown / unused - u16 CurBlock; // 0x32 | current block? - u16 FixedSample; // 0x33 | sample value for "blank" voices - u32 RestartPos; // 0x34 | restart pos - u16 Unk36[2]; // 0x36 | unknown // loaded at 0adc/ZWW in 0x21 decoder - u32 CurAddr; // 0x38 | current address - u32 RemLength; // 0x3A | remaining length - u16 Unk3C; // 0x3C | something to do with the resampler - a DRAM address? - u16 Unk3D; // 0x3D | unknown - u16 Unk3E; // 0x3E | unknown - u16 Unk3F; // 0x3F | unknown - u16 Unk40[0x10]; // 0x40 | Used as some sort of buffer by IIR - u16 Unk50[0x8]; // 0x50 | Used as some sort of buffer by 06ff/ZWW - u16 Unk58[0x8]; // 0x58 | - u16 Unk60[0x6]; // 0x60 | - u16 YN2; // 0x66 | YN2 - u16 YN1; // 0x67 | YN1 - u16 Unk68[0x8]; // 0x68 | unknown - u16 Unk70[0x8]; // 0x70 | unknown // 034b/ZWW - weird - u16 Unk78; // 0x78 | unknown // ZWW: ModifySample loads and stores. Ramped volume? - u16 Unk79; // 0x79 | unknown // ZWW: ModifySample loads and stores. Ramped volume? - u16 Unk7A; // 0x7A | unknown - u16 Unk7B; // 0x7B | unknown - u16 Unk7C; // 0x7C | unknown - u16 Unk7D; // 0x7D | unknown - u16 Unk7E; // 0x7E | unknown - u16 Unk7F; // 0x7F | unknown + struct { + // Read-Write part + u16 Status; // 0x00 | 1 = play, 0 = stop + u16 KeyOff; // 0x01 | writing 1 stops voice? + u16 RatioInt; // 0x02 | Position delta (playback speed) + u16 Unk03; // 0x03 | unknown + u16 NeedsReset; // 0x04 | indicates if some values in PB need to be reset + u16 ReachedEnd; // 0x05 | set to 1 when end reached + u16 IsBlank; // 0x06 | 0 = normal sound, 1 = samples are always the same + u16 Unk07; // 0x07 | unknown, in zelda always 0x0010. Something to do with number of saved samples (0x68)? - // Read-only part - u16 Format; // 0x80 | audio format - u16 RepeatMode; // 0x81 | 0 = one-shot, non zero = loop - u16 Unk82; // 0x82 | unknown - u16 Unk83; // 0x83 | unknown - u16 Unk84; // 0x84 | IIR Filter # coefs? - u16 Unk85; // 0x85 | Decides the weird stuff at 035a/ZWW, alco 0cd3 - u16 Unk86; // 0x86 | unknown - u16 Unk87; // 0x87 | unknown - u32 LoopStartPos; // 0x88 | loopstart pos - u32 Length; // 0x8A | sound length - u32 StartAddr; // 0x8C | sound start address - u32 UnkAddr; // 0x8E | ??? - u16 Padding[0x10]; // 0x90 | padding - u16 Padding2[0x10]; // 0xa0 | FIR filter coefs of some sort - u16 Padding3[0x10]; // 0xb0 | padding + u16 SoundType; // 0x08 | "Sound type": so far in zww: 0x0d00 for music (volume mode 0), 0x4861 for sfx (volume mode 1) + u16 volumeLeft1; // 0x09 | Left Volume 1 // There's probably two of each because they should be ramped within each frame. + u16 volumeLeft2; // 0x0A | Left Volume 2 + u16 Unk0B; // 0x0B | unknown + + u16 SoundType2; // 0x0C | "Sound type" 2 (not really sound type) + u16 volumeRight1; // 0x0D | Right Volume 1 + u16 volumeRight2; // 0x0E | Right Volume 2 + u16 Unk0F; // 0x0F | unknown + + u16 SoundType3; // 0x10 | "Sound type" 3 (not really sound type) + u16 volumeUnknown1_1; // 0x11 | Unknown Volume 1 + u16 volumeUnknown1_2; // 0x12 | Unknown Volume 1 + u16 Unk13; // 0x13 | unknown + + u16 SoundType4; // 0x14 | "Sound type" 4 (not really sound type) + u16 volumeUnknown2_1; // 0x15 | Unknown Volume 2 + u16 volumeUnknown2_2; // 0x16 | Unknown Volume 2 + u16 Unk17; // 0x17 | unknown + + u16 Unk18[0x10]; // 0x18 | unknown + u16 Unk28; // 0x28 | unknown + u16 Unk29; // 0x29 | unknown // multiplied by 0x2a @ 0d21/ZWW + u16 Unk2a; // 0x2A | unknown // loaded at 0d2e/ZWW + u16 Unk2b; // 0x2B | unknown + u16 VolumeMode; // 0x2C | unknown // See 0337/ZWW + u16 Unk2D; // 0x2D | unknown + u16 Unk2E; // 0x2E | unknown + u16 Unk2F; // 0x2F | unknown + u16 CurSampleFrac; // 0x30 | Fractional part of the current sample position + u16 Unk31; // 0x31 | unknown / unused + u16 CurBlock; // 0x32 | current block? + u16 FixedSample; // 0x33 | sample value for "blank" voices + u32 RestartPos; // 0x34 | restart pos + u16 Unk36[2]; // 0x36 | unknown // loaded at 0adc/ZWW in 0x21 decoder + u32 CurAddr; // 0x38 | current address + u32 RemLength; // 0x3A | remaining length + u16 Unk3C; // 0x3C | something to do with the resampler - a DRAM address? + u16 Unk3D; // 0x3D | unknown + u16 Unk3E; // 0x3E | unknown + u16 Unk3F; // 0x3F | unknown + u16 Unk40[0x10]; // 0x40 | Used as some sort of buffer by IIR + u16 Unk50[0x8]; // 0x50 | Used as some sort of buffer by 06ff/ZWW + u16 Unk58[0x8]; // 0x58 | + u16 Unk60[0x6]; // 0x60 | + u16 YN2; // 0x66 | YN2 + u16 YN1; // 0x67 | YN1 + u16 Unk68[0x10]; // 0x68 | Saved samples from last decode? + u16 FilterState1; // 0x78 | unknown // ZWW: 0c84_FilterBufferInPlace loads and stores. Simply, the filter state. + u16 FilterState2; // 0x79 | unknown // ZWW: same as above. these two are active if 0x04a8 != 0. + u16 Unk7A; // 0x7A | unknown + u16 Unk7B; // 0x7B | unknown + u16 Unk7C; // 0x7C | unknown + u16 Unk7D; // 0x7D | unknown + u16 Unk7E; // 0x7E | unknown + u16 Unk7F; // 0x7F | unknown + + // Read-only part + u16 Format; // 0x80 | audio format + u16 RepeatMode; // 0x81 | 0 = one-shot, non zero = loop + u16 Unk82; // 0x82 | unknown + u16 Unk83; // 0x83 | unknown + u16 Unk84; // 0x84 | IIR Filter # coefs? + u16 StopOnSilence; // 0x85 | Stop on silence? (Flag for something volume related. Decides the weird stuff at 035a/ZWW, alco 0cd3) + u16 Unk86; // 0x86 | unknown + u16 Unk87; // 0x87 | unknown + u32 LoopStartPos; // 0x88 | loopstart pos + u32 Length; // 0x8A | sound length + u32 StartAddr; // 0x8C | sound start address + u32 UnkAddr; // 0x8E | ??? + u16 Padding[0x10]; // 0x90 | padding + u16 Padding2[0x8]; // 0xa0 | FIR filter coefs of some sort + u16 FilterEnable; // 0xa8 | FilterBufferInPlace enable. + u16 Padding3[0x7]; // 0xa9 | padding + u16 Padding4[0x10]; // 0xb0 | padding + }; + u16 raw[0xc0]; }; namespace { @@ -129,7 +141,7 @@ public: int *templbuffer; int *temprbuffer; - // simple dump ... + // Simple dump ... int DumpAFC(u8* pIn, const int size, const int srate); u32 Read32() @@ -150,6 +162,9 @@ private: DSP_FRAME_END = 0xDCD10005, }; + // These map CRC to behaviour. + bool LuigiStyle() const; + u32 m_CRC; // These are the only dynamically allocated things allowed in the ucode. @@ -161,6 +176,7 @@ private: // If you add variables, remember to keep DoState() and the constructor up to date. s16 m_AFCCoefTable[32]; + s16 m_MiscTable[0x280]; bool m_bSyncInProgress; u32 m_MaxVoice; diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Voice.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Voice.cpp index 9518077d67..28791e732e 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Voice.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Voice.cpp @@ -444,27 +444,182 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ PB.NeedsReset = 0; } +// ContinueWithBlock: + + if (PB.FilterEnable) + { // 0x04a8 + for (int i = 0; i < _Size; i++) + { + // TODO: Apply filter from ZWW: 0c84_FilterBufferInPlace + } + } + for (int i = 0; i < _Size; i++) { - /*if(PB.volumeLeft2) - lastLeft = PB.volumeLeft2; - if(PB.volumeRight2) - lastRight = PB.volumeRight2;*/ + + } + + if (PB.VolumeMode != 0) + { + // Complex volume mode. Let's see what we can do. + if (PB.StopOnSilence) { + PB.raw[0x2b] = PB.raw[0x2a] >> 1; + if (PB.raw[0x2b] == 0) + { + PB.KeyOff = 1; + } + } - // TODO: Some noises in Zelda WW (birds, etc) have a volume of 0 - // Really not sure about the masking here, but it seems to kill off some overly loud - // sounds in Zelda TP. Needs investigation. - s32 left = _LeftBuffer[i] + (m_TempBuffer[i] * (float)( - (PB.volumeLeft1 & 0x1FFF) + (PB.volumeLeft2 & 0x1FFF)) * 0.00005); - s32 right = _RightBuffer[i] + (m_TempBuffer[i] * (float)( - (PB.volumeRight1 & 0x1FFF) + (PB.volumeRight2 & 0x1FFF)) * 0.00005); + short AX0L = PB.raw[0x28] >> 8; + short AX0H = PB.raw[0x28] & 0x7F; + short AX1L = AX0L ^ 0x7F; + short AX1H = AX1L ^ 0x7F; + AX0L = m_MiscTable[0x200 + AX0L]; + AX0H = m_MiscTable[0x200 + AX0H]; + AX1L = m_MiscTable[0x200 + AX1L]; + AX1H = m_MiscTable[0x200 + AX1H]; - if (left < -32768) left = -32768; - if (left > 32767) left = 32767; - _LeftBuffer[i] = left; //(s32)(((float)left * (float)PB.volumeLeft) / 1000.f); + short b00[16]; + b00[0] = AX1L * AX1H >> 16; + b00[1] = AX0L * AX1H >> 16; + b00[2] = AX0H * AX1L >> 16; + b00[3] = AX0L * AX0H >> 16; + for (int i = 0; i < 4; i++) { + b00[i + 4] = b00[i] * PB.raw[0x2a] >> 16; + } - if (right < -32768) right = -32768; - if (right > 32767) right = 32767; - _RightBuffer[i] = right; //(s32)(((float)right * (float)PB.volumeRight) / 1000.0f); + // ... not done yet... + + for (int count = 0; count < 8; count++) + { + // The 8 buffers to mix to: 0d00, 0d60, 0f40 0ca0 0e80 0ee0 0c00 0c50 + + } + + // this should be scrapped + for (int i = 0; i < _Size; i++) + { + // arbitrary + s32 left = m_TempBuffer[i] >> 3; + s32 right = m_TempBuffer[i] >> 3; + + _LeftBuffer[i] += left; //(s32)(((float)left * (float)PB.volumeLeft) / 1000.f); + _RightBuffer[i] += right; //(s32)(((float)right * (float)PB.volumeRight) / 1000.0f); + } + } + else + { + // ZWW 0355 + if (PB.StopOnSilence) + { + int sum = 0; + int addr = 0x0a; + for (int i = 0; i < 6; i++) + { + u16 value = PB.raw[addr]; + addr--; + value >>= 1; + PB.raw[addr] = value; + sum += value; + addr += 5; + } + if (sum == 0) { + PB.KeyOff = 1; + } + } + + // Seems there are 6 temporary output buffers. + for (int count = 0; count < 6; count++) + { + int addr = 0x08; + + // we'll have to keep a map of buffers I guess... + u16 dest_buffer_address = PB.raw[addr++]; + + bool mix = dest_buffer_address ? true : false; + + u16 vol2 = PB.raw[addr++]; + u16 vol1 = PB.raw[addr++]; + + int delta = (vol2 - vol1) << 11; + + addr--; + + u32 ramp = vol1 << 16; + if (mix) { + // 0ca9_RampedMultiplyAddBuffer + for (int i = 0; i < _Size; i++) + { + int value = m_TempBuffer[i]; + + // TODO - add to buffer specified by dest_buffer_address + switch (count) + { + // These really should be 32. + case 0: _LeftBuffer[i] += (u64)value * ramp >> 29; break; + case 1: _RightBuffer[i] += (u64)value * ramp >> 29; break; + } + if ((i & 1) == 0 && i < 64) { + ramp += delta; + } + } + if (_Size < 32) + { + ramp += delta * (_Size - 32); + } + } + // Update the PB with the volume actually reached. + PB.raw[addr++] = ramp >> 16; + + addr++; + } } } + + +// size is in stereo samples. +void CUCode_Zelda::MixAdd(short* _Buffer, int _Size) +{ + if (_Size > 256 * 1024) + _Size = 256 * 1024; + + memset(m_LeftBuffer, 0, _Size * sizeof(s32)); + memset(m_RightBuffer, 0, _Size * sizeof(s32)); + + for (u32 i = 0; i < m_NumVoices; i++) + { + u32 flags = m_SyncFlags[(i >> 4) & 0xF]; + if (!(flags & 1 << (15 - (i & 0xF)))) + continue; + + ZeldaVoicePB pb; + ReadVoicePB(m_VoicePBsAddr + (i * 0x180), pb); + + if (pb.Status == 0) + continue; + if (pb.KeyOff != 0) + continue; + + RenderAddVoice(pb, m_LeftBuffer, m_RightBuffer, _Size); + WritebackVoicePB(m_VoicePBsAddr + (i * 0x180), pb); + } + + if (_Buffer) + { + for (u32 i = 0; i < _Size; i++) + { + s32 left = (s32)_Buffer[0] + m_LeftBuffer[i]; + s32 right = (s32)_Buffer[1] + m_RightBuffer[i]; + + if (left < -32768) left = -32768; + if (left > 32767) left = 32767; + _Buffer[0] = (short)left; + + if (right < -32768) right = -32768; + if (right > 32767) right = 32767; + _Buffer[1] = (short)right; + + _Buffer += 2; + } + } +} \ No newline at end of file diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp index e1e0be5765..2bfded6422 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp @@ -22,7 +22,6 @@ #include "UCode_AX.h" #include "UCode_AXWii.h" #include "UCode_Zelda.h" -#include "UCode_Jac.h" #include "UCode_ROM.h" #include "UCode_CARD.h" #include "UCode_InitAudioSystem.h" @@ -61,8 +60,7 @@ IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler) case 0x0267d05a: // http://forums.dolphin-emu.com/thread-2134.html Pikmin PAL case 0x4be6a5cb: // AC, Pikmin INFO_LOG(DSPHLE, "CRC %08x: JAC (early Zelda) ucode chosen", _CRC); - return new CUCode_Jac(_rMailHandler); -// return new CUCode_Zelda(_rMailHandler, _CRC); + return new CUCode_Zelda(_rMailHandler, _CRC); case 0x6CA33A6D: // DK Jungle Beat case 0x86840740: // Zelda WW - US