From 52deb125999ce0c84ad43826ccc65881ee6542f7 Mon Sep 17 00:00:00 2001 From: nakeee Date: Mon, 26 Jan 2009 16:58:01 +0000 Subject: [PATCH] updated dsp null some clean up as well. Please test on windows git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2018 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Plugins/Plugin_DSP_NULL/Src/SConscript | 1 + .../Plugin_DSP_NULL/Src/UCodes/UCode_AX.cpp | 10 +- .../Src/UCodes/UCode_AXWii.cpp | 738 ++++++++--------- .../Plugin_DSP_NULL/Src/UCodes/UCode_AXWii.h | 128 +-- .../Src/UCodes/UCode_AX_ADPCM.h | 184 ++--- .../Src/UCodes/UCode_AX_Voice.h | 781 +++++++++--------- 6 files changed, 919 insertions(+), 923 deletions(-) diff --git a/Source/Plugins/Plugin_DSP_NULL/Src/SConscript b/Source/Plugins/Plugin_DSP_NULL/Src/SConscript index 8123ae755e..ba6980e6a1 100644 --- a/Source/Plugins/Plugin_DSP_NULL/Src/SConscript +++ b/Source/Plugins/Plugin_DSP_NULL/Src/SConscript @@ -11,6 +11,7 @@ files = [ "main.cpp", "Globals.cpp", "UCodes/UCode_AX.cpp", + "UCodes/UCode_AXWii.cpp", "UCodes/UCode_CARD.cpp", "UCodes/UCode_InitAudioSystem.cpp", "UCodes/UCode_Jac.cpp", diff --git a/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX.cpp b/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX.cpp index 3d980a46fd..39a550d1cf 100644 --- a/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX.cpp +++ b/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX.cpp @@ -17,7 +17,6 @@ #include "FileUtil.h" // For IsDirectory() #include "StringUtil.h" // For StringFromFormat() - #include #include "../MailHandler.h" @@ -27,7 +26,6 @@ #include "UCode_AX.h" #include "UCode_AX_Voice.h" - // ------------------------------------------------------------------ // Externals // ----------- @@ -95,8 +93,9 @@ void CUCode_AX::SaveLog_(bool Wii, const char* _fmt, va_list ap) char Msg[512]; vsprintf(Msg, _fmt, ap); - TmpMailLog += Msg; - TmpMailLog += "\n"; + TmpMailLog += Msg; + TmpMailLog += "\n"; + } // ---------------- @@ -125,6 +124,7 @@ int ReadOutPBs(u32 pbs_address, AXParamBlock* _pPBs, int _num) for (size_t p = 0; p < sizeof(AXParamBlock) / 2; p++) { pDest[p] = Common::swap16(pSrc[p]); + } blockAddr = (_pPBs[i].next_pb_hi << 16) | _pPBs[i].next_pb_lo; count++; @@ -236,6 +236,7 @@ void CUCode_AX::MixAdd(short* _pBuffer, int _iSize) *_pBuffer++ = left; *_pBuffer++ = right; } + } @@ -343,7 +344,6 @@ bool CUCode_AX::AXTask(u32& _uMail) m_addressPBs = Memory_Read_U32(uAddress); uAddress += 4; - SaveLog("%08x : AXLIST PB address: %08x", uAddress, m_addressPBs); } break; diff --git a/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AXWii.cpp b/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AXWii.cpp index bf262b8a8f..bc0cf5af75 100644 --- a/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AXWii.cpp +++ b/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AXWii.cpp @@ -1,372 +1,366 @@ -// 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 "StringUtil.h" - -#include "../MailHandler.h" - -#include "UCodes.h" -#include "UCode_AXStructs.h" -#include "UCode_AX.h" // for some functions in CUCode_AX -#include "UCode_AXWii.h" -#include "UCode_AX_Voice.h" - - -// ------------------------------------------------------------------ -// Declarations -// ----------- -extern bool gSequenced; - -// ----------- - - -CUCode_AXWii::CUCode_AXWii(CMailHandler& _rMailHandler, u32 l_CRC) - : IUCode(_rMailHandler) - , m_addressPBs(0xFFFFFFFF) - , _CRC(l_CRC) -{ - // we got loaded - m_rMailHandler.PushMail(0xDCD10000); - m_rMailHandler.PushMail(0x80000000); // handshake ??? only (crc == 0xe2136399) needs it ... - - templbuffer = new int[1024 * 1024]; - temprbuffer = new int[1024 * 1024]; - - lCUCode_AX = new CUCode_AX(_rMailHandler); - lCUCode_AX->_CRC = l_CRC; -} - -CUCode_AXWii::~CUCode_AXWii() -{ - m_rMailHandler.Clear(); - delete [] templbuffer; - delete [] temprbuffer; -} - -void CUCode_AXWii::HandleMail(u32 _uMail) -{ - if ((_uMail & 0xFFFF0000) == MAIL_AX_ALIST) - { - // a new List - } - else - { - AXTask(_uMail); - } -} - - -void CUCode_AXWii::MixAdd(short* _pBuffer, int _iSize) -{ - if(_CRC == 0xfa450138) - { - AXParamBlockWii PBs[NUMBER_OF_PBS]; - MixAdd_( _pBuffer, _iSize, PBs); - } - else - { - AXParamBlockWii_ PBs[NUMBER_OF_PBS]; - MixAdd_(_pBuffer, _iSize, PBs); - } -} - - -template -void CUCode_AXWii::MixAdd_(short* _pBuffer, int _iSize, ParamBlockType &PBs) -{ - //AXParamBlockWii PBs[NUMBER_OF_PBS]; - - // read out pbs - int numberOfPBs = ReadOutPBsWii(m_addressPBs, PBs, NUMBER_OF_PBS); - - if (_iSize > 1024 * 1024) - _iSize = 1024 * 1024; - - // write zeroes to the beginning of templbuffer - memset(templbuffer, 0, _iSize * sizeof(int)); - memset(temprbuffer, 0, _iSize * sizeof(int)); - - // ------------------------------------------- - // write logging data to debugger - - // --------------------------------------------------------------------------------------- - /* Make the updates we are told to do. See comments to the GC version in UCode_AX.cpp */ - // ------------ - for (int i = 0; i < numberOfPBs; i++) - { - u16 *pDest = (u16 *)&PBs[i]; - u16 upd0 = pDest[41]; u16 upd1 = pDest[42]; u16 upd2 = pDest[43]; // num_updates - u16 upd_hi = pDest[44]; // update addr - u16 upd_lo = pDest[45]; - int numupd = upd0 + upd1 + upd2; - if(numupd > 64) numupd = 64; // prevent to high values - const u32 updaddr = (u32)(upd_hi << 16) | upd_lo; - int on = false, off = false; - for (int j = 0; j < numupd; j++) // make alll updates - { - const u16 updpar = Memory_Read_U16(updaddr); - const u16 upddata = Memory_Read_U16(updaddr + 2); - // some safety checks, I hope it's enough - if( ( (updaddr > 0x80000000 && updaddr < 0x817fffff) - || (updaddr > 0x90000000 && updaddr < 0x93ffffff) ) - && updpar < 127 && updpar > 3 && upddata >= 0 // updpar > 3 because we don't want to change - // 0-3, those are important - //&& (upd0 || upd1 || upd2) // We should use these in some way to I think - // but I don't know how or when - && gSequenced) // on and off option - { - //PanicAlert("Update %i: %i = %04x", i, updpar, upddata); - //DebugLog("Update: %i = %04x", updpar, upddata); - pDest[updpar] = upddata; - } - if (updpar == 7 && upddata == 1) on++; - if (updpar == 7 && upddata == 1) off++; - } - // hack: if we get both an on and an off select on rather than off - if (on > 0 && off > 0) pDest[7] = 1; - } - - //PrintFile(1, "%08x %04x %04x\n", updaddr, updpar, upddata); - // ------------ - - - for (int i = 0; i < numberOfPBs; i++) - { - MixAddVoice(PBs[i], templbuffer, temprbuffer, _iSize, true); - } - - WriteBackPBsWii(m_addressPBs, PBs, numberOfPBs); - // We write the sound to _pBuffer - for (int i = 0; i < _iSize; i++) - { - // 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; - if (left > 32767) left = 32767; - if (right < -32767) right = -32767; - if (right > 32767) right = 32767; - *_pBuffer++ = left; - *_pBuffer++ = right; - } - -} - - -void CUCode_AXWii::Update() -{ - // check if we have to sent something - if (!m_rMailHandler.IsEmpty()) - { - g_dspInitialize.pGenerateDSPInterrupt(); - } -} - - -// Shortcut -void CUCode_AXWii::SaveLog(const char* _fmt, ...) -{ -} - - -// 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) -{ - u32 uAddress = _uMail; - SaveLog("Begin"); - SaveLog("====================================================================="); - SaveLog("%08x: AXTask - AXCommandList-Addr", uAddress); - - u32 Addr__AXStudio; - u32 Addr__AXOutSBuffer; - // u32 Addr__AXOutSBuffer_1; - // u32 Addr__AXOutSBuffer_2; - u32 Addr__A; - // u32 Addr__12; - u32 Addr__5_1; - u32 Addr__5_2; - u32 Addr__6; - // u32 Addr__9; - - bool bExecuteList = true; - - if (false) - { - // PanicAlert("%i", sizeof(AXParamBlockWii)); // 252 ?? - FILE *f = fopen("D:\\axdump.txt", "a"); - if (!f) - f = fopen("D:\\axdump.txt", "w"); - - u32 addr = uAddress; - for (int i = 0; i < 100; i++) { - fprintf(f, "%02x\n", Memory_Read_U16(addr + i * 2)); - } - fprintf(f, "===========------------------------------------------------=\n"); - fclose(f); - } - else - { - // PanicAlert("%i", sizeof(AXParamBlock)); // 192 - } - - while (bExecuteList) - { - static int last_valid_command = 0; - u16 iCommand = Memory_Read_U16(uAddress); - uAddress += 2; - switch (iCommand) - { - case 0x0000: //00 - Addr__AXStudio = Memory_Read_U32(uAddress); - uAddress += 4; - SaveLog("%08x : AXLIST studio address: %08x", uAddress, Addr__AXStudio); - break; - - case 0x0001: - { - u32 address = Memory_Read_U32(uAddress); - uAddress += 4; - SaveLog("%08x : AXLIST 1: %08x", uAddress, address); - } - break; - - case 0x0003: - { - u32 address = Memory_Read_U32(uAddress); - uAddress += 4; - SaveLog("%08x : AXLIST 3: %08x", uAddress, address); - } - break; - - case 0x0004: // PBs are here now - m_addressPBs = Memory_Read_U32(uAddress); - lCUCode_AX->m_addressPBs = m_addressPBs; // for the sake of logging - SaveLog("%08x : AXLIST PB address: %08x", uAddress, m_addressPBs); - uAddress += 4; - break; - - case 0x0005: - if(Memory_Read_U16(uAddress) > 25) // this occured in Wii Sports - { - Addr__5_1 = Memory_Read_U32(uAddress); - uAddress += 4; - Addr__5_2 = Memory_Read_U32(uAddress); - uAddress += 4; - - uAddress += 2; - SaveLog("%08x : AXLIST 5_1 5_2 addresses: %08x %08x", uAddress, Addr__5_1, Addr__5_2); - } - else - { - uAddress += 2; - SaveLog("%08x : AXLIST Empty 0x0005", uAddress); - } - break; - - case 0x0006: - Addr__6 = Memory_Read_U32(uAddress); - uAddress += 10; - SaveLog("%08x : AXLIST 6 address: %08x", uAddress, Addr__6); - break; - -/**/ case 0x0007: // AXLIST_SBUFFER - Addr__AXOutSBuffer = Memory_Read_U32(uAddress); - uAddress += 10; - // uAddress += 12; - SaveLog("%08x : AXLIST OutSBuffer (0x0007) address: %08x", uAddress, Addr__AXOutSBuffer); - break; - -/* case 0x0009: - Addr__9 = Memory_Read_U32(uAddress); - uAddress += 4; - DebugLog("AXLIST 6 address: %08x", Addr__9); - break;*/ - - case 0x000a: // AXLIST_COMPRESSORTABLE - Addr__A = Memory_Read_U32(uAddress); - uAddress += 4; - //Addr__A = Memory_Read_U32(uAddress); - uAddress += 4; - SaveLog("%08x : AXLIST CompressorTable address: %08x", uAddress, Addr__A); - break; - - case 0x000b: - uAddress += 2; // one 0x8000 in rabbids - uAddress += 4 * 2; // then two RAM addressses - break; - - case 0x000c: - uAddress += 2; // one 0x8000 in rabbids - uAddress += 4 * 2; // then two RAM addressses - break; - - case 0x000d: - uAddress += 4 * 4; - break; - - case 0x000e: - // This is the end. - bExecuteList = false; - SaveLog("%08x : AXLIST end, wii stylee.", uAddress); - break; - - default: - { - static bool bFirst = true; - if (bFirst == true) - { - // A little more descreet way to say that there is a problem, that also let you - // take a look at the mail (and possible previous mails) in the debugger - SaveLog("%08x : Unknown AX-Command 0x%04x", uAddress, iCommand); - bExecuteList = false; - break; - - char szTemp[2048]; - sprintf(szTemp, "Unknown AX-Command 0x%04x (address: 0x%08x). Last valid: %02x\n", - iCommand, uAddress - 2, last_valid_command); - int num = -32; - while (num < 64+32) - { - char szTemp2[128] = ""; - sprintf(szTemp2, "%s0x%04x\n", num == 0 ? ">>" : " ", Memory_Read_U16(uAddress + num)); - strcat(szTemp, szTemp2); - num += 2; - } - - // Wii AX will always show this - PanicAlert(szTemp); - // bFirst = false; - } - - // unknown command so stop the execution of this TaskList - bExecuteList = false; - } - break; - } - if (bExecuteList) - last_valid_command = iCommand; - } - SaveLog("AXTask - done, send resume"); - SaveLog("====================================================================="); - SaveLog("End"); - - // i hope resume is okay AX - m_rMailHandler.PushMail(0xDCD10001); - return true; -} +// 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 "StringUtil.h" + +#include "../MailHandler.h" + +#include "UCodes.h" +#include "UCode_AXStructs.h" +#include "UCode_AX.h" // for some functions in CUCode_AX +#include "UCode_AXWii.h" +#include "UCode_AX_Voice.h" + + +// ------------------------------------------------------------------ +// Declarations +// ----------- +extern bool gSequenced; + +// ----------- + + +CUCode_AXWii::CUCode_AXWii(CMailHandler& _rMailHandler, u32 l_CRC) + : IUCode(_rMailHandler) + , m_addressPBs(0xFFFFFFFF) + , _CRC(l_CRC) +{ + // we got loaded + m_rMailHandler.PushMail(0xDCD10000); + m_rMailHandler.PushMail(0x80000000); // handshake ??? only (crc == 0xe2136399) needs it ... + + templbuffer = new int[1024 * 1024]; + temprbuffer = new int[1024 * 1024]; + + lCUCode_AX = new CUCode_AX(_rMailHandler); + lCUCode_AX->_CRC = l_CRC; +} + +CUCode_AXWii::~CUCode_AXWii() +{ + m_rMailHandler.Clear(); + delete [] templbuffer; + delete [] temprbuffer; +} + +void CUCode_AXWii::HandleMail(u32 _uMail) +{ + if ((_uMail & 0xFFFF0000) == MAIL_AX_ALIST) + { + // a new List + } + else + { + AXTask(_uMail); + } +} + + +void CUCode_AXWii::MixAdd(short* _pBuffer, int _iSize) +{ + if(_CRC == 0xfa450138) + { + AXParamBlockWii PBs[NUMBER_OF_PBS]; + MixAdd_( _pBuffer, _iSize, PBs); + } + else + { + AXParamBlockWii_ PBs[NUMBER_OF_PBS]; + MixAdd_(_pBuffer, _iSize, PBs); + } +} + + +template +void CUCode_AXWii::MixAdd_(short* _pBuffer, int _iSize, ParamBlockType &PBs) +{ + //AXParamBlockWii PBs[NUMBER_OF_PBS]; + + // read out pbs + int numberOfPBs = ReadOutPBsWii(m_addressPBs, PBs, NUMBER_OF_PBS); + + if (_iSize > 1024 * 1024) + _iSize = 1024 * 1024; + + // write zeroes to the beginning of templbuffer + memset(templbuffer, 0, _iSize * sizeof(int)); + memset(temprbuffer, 0, _iSize * sizeof(int)); + + // ------------------------------------------- + // write logging data to debugger + /* Make the updates we are told to do. See comments to the GC version in UCode_AX.cpp */ + // ------------ + for (int i = 0; i < numberOfPBs; i++) + { + u16 *pDest = (u16 *)&PBs[i]; + u16 upd0 = pDest[41]; u16 upd1 = pDest[42]; u16 upd2 = pDest[43]; // num_updates + u16 upd_hi = pDest[44]; // update addr + u16 upd_lo = pDest[45]; + int numupd = upd0 + upd1 + upd2; + if(numupd > 64) numupd = 64; // prevent to high values + const u32 updaddr = (u32)(upd_hi << 16) | upd_lo; + int on = false, off = false; + for (int j = 0; j < numupd; j++) // make alll updates + { + const u16 updpar = Memory_Read_U16(updaddr); + const u16 upddata = Memory_Read_U16(updaddr + 2); + // some safety checks, I hope it's enough + if( ( (updaddr > 0x80000000 && updaddr < 0x817fffff) + || (updaddr > 0x90000000 && updaddr < 0x93ffffff) ) + && updpar < 127 && updpar > 3 && upddata >= 0 // updpar > 3 because we don't want to change + // 0-3, those are important + //&& (upd0 || upd1 || upd2) // We should use these in some way to I think + // but I don't know how or when + && gSequenced) // on and off option + { + //PanicAlert("Update %i: %i = %04x", i, updpar, upddata); + //DebugLog("Update: %i = %04x", updpar, upddata); + pDest[updpar] = upddata; + } + if (updpar == 7 && upddata == 1) on++; + if (updpar == 7 && upddata == 1) off++; + } + // hack: if we get both an on and an off select on rather than off + if (on > 0 && off > 0) pDest[7] = 1; + } + + //PrintFile(1, "%08x %04x %04x\n", updaddr, updpar, upddata); + // ------------ + + + for (int i = 0; i < numberOfPBs; i++) + { + MixAddVoice(PBs[i], templbuffer, temprbuffer, _iSize, true); + } + + WriteBackPBsWii(m_addressPBs, PBs, numberOfPBs); + // We write the sound to _pBuffer + for (int i = 0; i < _iSize; i++) + { + // 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; + if (left > 32767) left = 32767; + if (right < -32767) right = -32767; + if (right > 32767) right = 32767; + *_pBuffer++ = left; + *_pBuffer++ = right; + } + +} + + +void CUCode_AXWii::Update() +{ + // check if we have to sent something + if (!m_rMailHandler.IsEmpty()) + { + g_dspInitialize.pGenerateDSPInterrupt(); + } +} + + +// Shortcut +void CUCode_AXWii::SaveLog(const char* _fmt, ...) +{ +} + + +// 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) +{ + u32 uAddress = _uMail; + SaveLog("Begin"); + SaveLog("====================================================================="); + SaveLog("%08x: AXTask - AXCommandList-Addr", uAddress); + + u32 Addr__AXStudio; + u32 Addr__AXOutSBuffer; + // u32 Addr__AXOutSBuffer_1; + // u32 Addr__AXOutSBuffer_2; + u32 Addr__A; + // u32 Addr__12; + u32 Addr__5_1; + u32 Addr__5_2; + u32 Addr__6; + // u32 Addr__9; + + bool bExecuteList = true; + if (false) + { + // PanicAlert("%i", sizeof(AXParamBlockWii)); // 252 ?? + FILE *f = fopen("D:\\axdump.txt", "a"); + if (!f) + f = fopen("D:\\axdump.txt", "w"); + + u32 addr = uAddress; + for (int i = 0; i < 100; i++) { + fprintf(f, "%02x\n", Memory_Read_U16(addr + i * 2)); + } + fprintf(f, "===========------------------------------------------------=\n"); + fclose(f); + } + else + { + // PanicAlert("%i", sizeof(AXParamBlock)); // 192 + } + + while (bExecuteList) + { + static int last_valid_command = 0; + u16 iCommand = Memory_Read_U16(uAddress); + uAddress += 2; + switch (iCommand) + { + case 0x0000: //00 + Addr__AXStudio = Memory_Read_U32(uAddress); + uAddress += 4; + SaveLog("%08x : AXLIST studio address: %08x", uAddress, Addr__AXStudio); + break; + + case 0x0001: + { + u32 address = Memory_Read_U32(uAddress); + uAddress += 4; + } + break; + + case 0x0003: + { + u32 address = Memory_Read_U32(uAddress); + uAddress += 4; + } + break; + + case 0x0004: // PBs are here now + m_addressPBs = Memory_Read_U32(uAddress); + lCUCode_AX->m_addressPBs = m_addressPBs; // for the sake of logging + + uAddress += 4; + break; + + case 0x0005: + if(Memory_Read_U16(uAddress) > 25) // this occured in Wii Sports + { + Addr__5_1 = Memory_Read_U32(uAddress); + uAddress += 4; + Addr__5_2 = Memory_Read_U32(uAddress); + uAddress += 4; + + uAddress += 2; + } + else + { + uAddress += 2; + SaveLog("%08x : AXLIST Empty 0x0005", uAddress); + } + break; + + case 0x0006: + Addr__6 = Memory_Read_U32(uAddress); + uAddress += 10; + SaveLog("%08x : AXLIST 6 address: %08x", uAddress, Addr__6); + break; + +/**/ case 0x0007: // AXLIST_SBUFFER + Addr__AXOutSBuffer = Memory_Read_U32(uAddress); + uAddress += 10; + // uAddress += 12; + SaveLog("%08x : AXLIST OutSBuffer (0x0007) address: %08x", uAddress, Addr__AXOutSBuffer); + break; + +/* case 0x0009: + Addr__9 = Memory_Read_U32(uAddress); + uAddress += 4; + DebugLog("AXLIST 6 address: %08x", Addr__9); + break;*/ + + case 0x000a: // AXLIST_COMPRESSORTABLE + Addr__A = Memory_Read_U32(uAddress); + uAddress += 4; + //Addr__A = Memory_Read_U32(uAddress); + uAddress += 4; + SaveLog("%08x : AXLIST CompressorTable address: %08x", uAddress, Addr__A); + break; + + case 0x000b: + uAddress += 2; // one 0x8000 in rabbids + uAddress += 4 * 2; // then two RAM addressses + break; + + case 0x000c: + uAddress += 2; // one 0x8000 in rabbids + uAddress += 4 * 2; // then two RAM addressses + break; + + case 0x000d: + uAddress += 4 * 4; + break; + + case 0x000e: + // This is the end. + bExecuteList = false; + SaveLog("%08x : AXLIST end, wii stylee.", uAddress); + break; + + default: + { + static bool bFirst = true; + if (bFirst == true) + { + // A little more descreet way to say that there is a problem, that also let you + // take a look at the mail (and possible previous mails) in the debugger + SaveLog("%08x : Unknown AX-Command 0x%04x", uAddress, iCommand); + bExecuteList = false; + break; + + char szTemp[2048]; + sprintf(szTemp, "Unknown AX-Command 0x%04x (address: 0x%08x). Last valid: %02x\n", + iCommand, uAddress - 2, last_valid_command); + int num = -32; + while (num < 64+32) + { + char szTemp2[128] = ""; + sprintf(szTemp2, "%s0x%04x\n", num == 0 ? ">>" : " ", Memory_Read_U16(uAddress + num)); + strcat(szTemp, szTemp2); + num += 2; + } + + // Wii AX will always show this + PanicAlert(szTemp); + // bFirst = false; + } + + // unknown command so stop the execution of this TaskList + bExecuteList = false; + } + break; + } + if (bExecuteList) + last_valid_command = iCommand; + } + SaveLog("AXTask - done, send resume"); + SaveLog("====================================================================="); + SaveLog("End"); + + // i hope resume is okay AX + m_rMailHandler.PushMail(0xDCD10001); + return true; +} diff --git a/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AXWii.h b/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AXWii.h index 477426cc91..0e847fc5d8 100644 --- a/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AXWii.h +++ b/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AXWii.h @@ -1,64 +1,64 @@ -// 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_AXWII -#define _UCODE_AXWII - -#include "UCode_AXStructs.h" - -#define NUMBER_OF_PBS 128 - -class CUCode_AXWii : public IUCode -{ -public: - CUCode_AXWii(CMailHandler& _rMailHandler, u32 _CRC); - virtual ~CUCode_AXWii(); - - void HandleMail(u32 _uMail); - void MixAdd(short* _pBuffer, int _iSize); - template - //void Logging(short* _pBuffer, int _iSize, int a, bool Wii, ParamBlockType &PBs, int numberOfPBs); - void MixAdd_(short* _pBuffer, int _iSize, ParamBlockType &PBs); - void Update(); - - // The logging function for the debugger - void Logging(short* _pBuffer, int _iSize, int a); - CUCode_AX * lCUCode_AX; // we need the logging functions in there - -private: - enum - { - MAIL_AX_ALIST = 0xBABE0000, - }; - - // PBs - u32 m_addressPBs; - u32 _CRC; - - int *templbuffer; - int *temprbuffer; - - // ax task message handler - bool AXTask(u32& _uMail); - void SaveLog(const char* _fmt, ...); - void SendMail(u32 _uMail); -}; - -//int ReadOutPBsWii(u32 pbs_address, AXParamBlockWii* _pPBs, int _num); -//void WriteBackPBsWii(u32 pbs_address, AXParamBlockWii* _pPBs, int _num); - -#endif // _UCODE_AXWII +// 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_AXWII +#define _UCODE_AXWII + +#include "UCode_AXStructs.h" + +#define NUMBER_OF_PBS 128 + +class CUCode_AXWii : public IUCode +{ +public: + CUCode_AXWii(CMailHandler& _rMailHandler, u32 _CRC); + virtual ~CUCode_AXWii(); + + void HandleMail(u32 _uMail); + void MixAdd(short* _pBuffer, int _iSize); + template + //void Logging(short* _pBuffer, int _iSize, int a, bool Wii, ParamBlockType &PBs, int numberOfPBs); + void MixAdd_(short* _pBuffer, int _iSize, ParamBlockType &PBs); + void Update(); + + // The logging function for the debugger + void Logging(short* _pBuffer, int _iSize, int a); + CUCode_AX * lCUCode_AX; // we need the logging functions in there + +private: + enum + { + MAIL_AX_ALIST = 0xBABE0000, + }; + + // PBs + u32 m_addressPBs; + u32 _CRC; + + int *templbuffer; + int *temprbuffer; + + // ax task message handler + bool AXTask(u32& _uMail); + void SaveLog(const char* _fmt, ...); + void SendMail(u32 _uMail); +}; + +//int ReadOutPBsWii(u32 pbs_address, AXParamBlockWii* _pPBs, int _num); +//void WriteBackPBsWii(u32 pbs_address, AXParamBlockWii* _pPBs, int _num); + +#endif // _UCODE_AXWII diff --git a/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX_ADPCM.h b/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX_ADPCM.h index acad346b3e..2fa9c613cb 100644 --- a/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX_ADPCM.h +++ b/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX_ADPCM.h @@ -1,92 +1,92 @@ -// 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_AX_ADPCM_H -#define _UCODE_AX_ADPCM_H -#include "../Globals.h" - -inline s16 ADPCM_Step(PBADPCMInfo &adpcm, u32& samplePos, u32 newSamplePos, u16 frac) -{ - while (samplePos < newSamplePos) - { - if ((samplePos & 15) == 0) - { - adpcm.pred_scale = g_dspInitialize.pARAM_Read_U8((samplePos & ~15) >> 1); - samplePos += 2; - newSamplePos += 2; - } - - int scale = 1 << (adpcm.pred_scale & 0xF); - int coef_idx = adpcm.pred_scale >> 4; - - s32 coef1 = adpcm.coefs[coef_idx * 2 + 0]; - s32 coef2 = adpcm.coefs[coef_idx * 2 + 1]; - - int temp = (samplePos & 1) ? - (g_dspInitialize.pARAM_Read_U8(samplePos >> 1) & 0xF) : - (g_dspInitialize.pARAM_Read_U8(samplePos >> 1) >> 4); - - if (temp >= 8) - temp -= 16; - - // 0x400 = 0.5 in 11-bit fixed point - int val = (scale * temp) + ((0x400 + coef1 * adpcm.yn1 + coef2 * adpcm.yn2) >> 11); - - if (val > 0x7FFF) - val = 0x7FFF; - else if (val < -0x7FFF) - val = -0x7FFF; - - adpcm.yn2 = adpcm.yn1; - adpcm.yn1 = val; - - samplePos++; - } - - return adpcm.yn1; -} - -// ======================================================================================= -// Volume control (ramping) -// -------------- -inline u16 ADPCM_Vol(u16 vol, u16 delta) -{ - int x = vol; - if (delta && delta < 0x5000) - x += delta * 20 * 8; // unsure what the right step is - //x += 1 * 20 * 8; - else if (delta && delta > 0x5000) - //x -= (0x10000 - delta); // this is to small, it's often 1 - x -= (0x10000 - delta) * 20 * 16; // if this was 20 * 8 the sounds in Fire Emblem and Paper Mario - // did not have time to go to zero before the were closed - //x -= 1 * 20 * 16; - - // make lower limits - if (x < 0) x = 0; - //if (pb.mixer_control < 1000 && x < pb.mixer_control) x = pb.mixer_control; // does this make - // any sense? - - // make upper limits - //if (mixer_control > 1000 && x > mixer_control) x = mixer_control; // maybe mixer_control also - // has a volume target? - //if (x >= 0x7fff) x = 0x7fff; // this seems a little high - if (x >= 0x4e20) x = 0x4e20; // add a definitive limit at 20 000 - return x; // update volume -} -// ============== - -#endif // _UCODE_AX_ADPCM_H +// 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_AX_ADPCM_H +#define _UCODE_AX_ADPCM_H +#include "../Globals.h" + +inline s16 ADPCM_Step(PBADPCMInfo &adpcm, u32& samplePos, u32 newSamplePos, u16 frac) +{ + while (samplePos < newSamplePos) + { + if ((samplePos & 15) == 0) + { + adpcm.pred_scale = g_dspInitialize.pARAM_Read_U8((samplePos & ~15) >> 1); + samplePos += 2; + newSamplePos += 2; + } + + int scale = 1 << (adpcm.pred_scale & 0xF); + int coef_idx = adpcm.pred_scale >> 4; + + s32 coef1 = adpcm.coefs[coef_idx * 2 + 0]; + s32 coef2 = adpcm.coefs[coef_idx * 2 + 1]; + + int temp = (samplePos & 1) ? + (g_dspInitialize.pARAM_Read_U8(samplePos >> 1) & 0xF) : + (g_dspInitialize.pARAM_Read_U8(samplePos >> 1) >> 4); + + if (temp >= 8) + temp -= 16; + + // 0x400 = 0.5 in 11-bit fixed point + int val = (scale * temp) + ((0x400 + coef1 * adpcm.yn1 + coef2 * adpcm.yn2) >> 11); + + if (val > 0x7FFF) + val = 0x7FFF; + else if (val < -0x7FFF) + val = -0x7FFF; + + adpcm.yn2 = adpcm.yn1; + adpcm.yn1 = val; + + samplePos++; + } + + return adpcm.yn1; +} + +// ======================================================================================= +// Volume control (ramping) +// -------------- +inline u16 ADPCM_Vol(u16 vol, u16 delta) +{ + int x = vol; + if (delta && delta < 0x5000) + x += delta * 20 * 8; // unsure what the right step is + //x += 1 * 20 * 8; + else if (delta && delta > 0x5000) + //x -= (0x10000 - delta); // this is to small, it's often 1 + x -= (0x10000 - delta) * 20 * 16; // if this was 20 * 8 the sounds in Fire Emblem and Paper Mario + // did not have time to go to zero before the were closed + //x -= 1 * 20 * 16; + + // make lower limits + if (x < 0) x = 0; + //if (pb.mixer_control < 1000 && x < pb.mixer_control) x = pb.mixer_control; // does this make + // any sense? + + // make upper limits + //if (mixer_control > 1000 && x > mixer_control) x = mixer_control; // maybe mixer_control also + // has a volume target? + //if (x >= 0x7fff) x = 0x7fff; // this seems a little high + if (x >= 0x4e20) x = 0x4e20; // add a definitive limit at 20 000 + return x; // update volume +} +// ============== + +#endif // _UCODE_AX_ADPCM_H diff --git a/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX_Voice.h b/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX_Voice.h index 8ae708b538..cda852c71d 100644 --- a/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX_Voice.h +++ b/Source/Plugins/Plugin_DSP_NULL/Src/UCodes/UCode_AX_Voice.h @@ -1,390 +1,391 @@ -// 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_AX_VOICE_H -#define _UCODE_AX_VOICE_H - -#include "UCode_AX_ADPCM.h" -#include "UCode_AX.h" - -// ---------------------------------------------------- -// Externals -// ----------- -extern bool gSSBM; -extern bool gSSBMremedy1; -extern bool gSSBMremedy2; -extern bool gSequenced; -extern bool gVolume; -extern bool gReset; -extern bool gSequenced; -extern float ratioFactor; - - -template -inline int ReadOutPBsWii(u32 pbs_address, ParamBlockType& _pPBs, int _num) -{ - int count = 0; - u32 blockAddr = pbs_address; - u32 pAddr = 0; - - // reading and 'halfword' swap - for (int i = 0; i < _num; i++) - { - const short *pSrc = (const short *)g_dspInitialize.pGetMemoryPointer(blockAddr); - pAddr = blockAddr; - - if (pSrc != NULL) - { - short *pDest = (short *)&_pPBs[i]; - for (u32 p = 0; p < sizeof(AXParamBlockWii) / 2; p++) - { - if(p == 6 || p == 7) pDest[p] = pSrc[p]; // control for the u32 - else pDest[p] = Common::swap16(pSrc[p]); - } - - _pPBs[i].mixer_control = Common::swap32(_pPBs[i].mixer_control); - blockAddr = (_pPBs[i].next_pb_hi << 16) | _pPBs[i].next_pb_lo; - count++; - - // Detect the last mail by checking when next_pb = 0 - u32 next_pb = (Common::swap16(pSrc[0]) << 16) | Common::swap16(pSrc[1]); - if(next_pb == 0) break; - } - else - break; - } - - // return the number of read PBs - return count; -} - -template -inline void WriteBackPBsWii(u32 pbs_address, ParamBlockType& _pPBs, int _num) -//void WriteBackPBsWii(u32 pbs_address, AXParamBlockWii* _pPBs, int _num) -{ - u32 blockAddr = pbs_address; - - // write back and 'halfword'swap - for (int i = 0; i < _num; i++) - { - short* pSrc = (short*)&_pPBs[i]; - short* pDest = (short*)g_dspInitialize.pGetMemoryPointer(blockAddr); - _pPBs[i].mixer_control = Common::swap32(_pPBs[i].mixer_control); - for (size_t p = 0; p < sizeof(AXParamBlockWii) / 2; p++) - { - if(p == 6 || p == 7) pDest[p] = pSrc[p]; // control for the u32 - else pDest[p] = Common::swap16(pSrc[p]); - } - - // next block - blockAddr = (_pPBs[i].next_pb_hi << 16) | _pPBs[i].next_pb_lo; - } -} - - -template -inline void MixAddVoice(ParamBlockType &pb, int *templbuffer, int *temprbuffer, int _iSize, bool Wii) -{ - DoVoiceHacks(pb, Wii); - - // ============= - if (pb.running) - { - - // ======================================================================================= - // Read initial parameters - // ------------ - //constants - const u32 ratio = (u32)(((pb.src.ratio_hi << 16) + pb.src.ratio_lo) * ratioFactor); - u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo; - u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo; - - //variables - u32 samplePos = (pb.audio_addr.cur_addr_hi << 16) | pb.audio_addr.cur_addr_lo; - u32 frac = pb.src.cur_addr_frac; - // ============= - - // ======================================================================================= - // Handle No-SRC streams - No src streams have pb.src_type == 2 and have pb.src.ratio_hi = 0 - // and pb.src.ratio_lo = 0. We handle that by setting the sampling ratio integer to 1. This - // makes samplePos update in the correct way. I'm unsure how we are actually supposed to - // detect that this setting. Updates did not fix this automatically. - // --------------------------------------------------------------------------------------- - // Stream settings - // src_type = 2 (most other games have src_type = 0) - // ------------ - // Affected games: - // Baten Kaitos - Eternal Wings (2003) - // Baten Kaitos - Origins (2006)? - // Soul Calibur 2: The movie music use src_type 2 but it needs no adjustment, perhaps - // the sound format plays in to, Baten use ADPCM, SC2 use PCM16 - // ------------ - //if (pb.src_type == 2 && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0)) - if (pb.running && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0)) - { - pb.src.ratio_hi = 1; - } - // ============= - - - // ======================================================================================= - // Games that use looping to play non-looping music streams - SSBM has info in all - // pb.adpcm_loop_info parameters but has pb.audio_addr.looping = 0. If we treat these streams - // like any other looping streams the music works. I'm unsure how we are actually supposed to - // detect that these kinds of blocks should be looping. It seems like pb.mixer_control == 0 may - // identify these types of blocks. Updates did not write any looping values. - // -------------- - if ( - (pb.adpcm_loop_info.pred_scale || pb.adpcm_loop_info.yn1 || pb.adpcm_loop_info.yn2) - && pb.mixer_control == 0 - ) - { - pb.audio_addr.looping = 1; - } - // ============== - - // Top Spin 3 Wii - if(pb.audio_addr.sample_format > 25) pb.audio_addr.sample_format = 0; - - // ======================================================================================= - // Walk through _iSize. _iSize = numSamples. If the game goes slow _iSize will be higher to - // compensate for that. _iSize can be as low as 100 or as high as 2000 some cases. - for (int s = 0; s < _iSize; s++) - { - int sample = 0; - frac += ratio; - u32 newSamplePos = samplePos + (frac >> 16); //whole number of frac - - // ======================================================================================= - // Process sample format - // -------------- - switch (pb.audio_addr.sample_format) - { - case AUDIOFORMAT_PCM8: - // TODO - the linear interpolation code below is somewhat suspicious - pb.adpcm.yn2 = pb.adpcm.yn1; //save last sample - pb.adpcm.yn1 = ((s8)g_dspInitialize.pARAM_Read_U8(samplePos)) << 8; - - if (pb.src_type == SRCTYPE_NEAREST) - { - sample = pb.adpcm.yn1; - } - else //linear interpolation - { - sample = (pb.adpcm.yn1 * (u16)frac + pb.adpcm.yn2 * (u16)(0xFFFF - frac)) >> 16; - } - - samplePos = newSamplePos; - break; - - case AUDIOFORMAT_PCM16: - // TODO - the linear interpolation code below is somewhat suspicious - pb.adpcm.yn2 = pb.adpcm.yn1; //save last sample - pb.adpcm.yn1 = (s16)(u16)((g_dspInitialize.pARAM_Read_U8(samplePos * 2) << 8) | (g_dspInitialize.pARAM_Read_U8((samplePos * 2 + 1)))); - if (pb.src_type == SRCTYPE_NEAREST) - sample = pb.adpcm.yn1; - else //linear interpolation - sample = (pb.adpcm.yn1 * (u16)frac + pb.adpcm.yn2 * (u16)(0xFFFF - frac)) >> 16; - - samplePos = newSamplePos; - break; - - case AUDIOFORMAT_ADPCM: - sample = ADPCM_Step(pb.adpcm, samplePos, newSamplePos, frac); - break; - - default: - break; - } - // ================ - - // =================================================================== - // Overall volume control. In addition to this there is also separate volume settings to - // different channels (left, right etc). - frac &= 0xffff; - - int vol = pb.vol_env.cur_volume >> 9; - sample = sample * vol >> 8; - - if (pb.mixer_control & MIXCONTROL_RAMPING) - { - int x = pb.vol_env.cur_volume; - x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game - // that use this? Or how does it work? - if (x < 0) x = 0; - if (x >= 0x7fff) x = 0x7fff; - pb.vol_env.cur_volume = x; // maybe not per sample?? :P - } - - int leftmix = pb.mixer.volume_left >> 5; - int rightmix = pb.mixer.volume_right >> 5; - int left = sample * leftmix >> 8; - int right = sample * rightmix >> 8; - //adpcm has to walk from oldSamplePos to samplePos here - templbuffer[s] += left; - temprbuffer[s] += right; - // =============== - - - // =================================================================== - // Control the behavior when we reach the end of the sample - if (samplePos >= sampleEnd) - { - if (pb.audio_addr.looping == 1) - { - samplePos = loopPos; - if (pb.audio_addr.sample_format == AUDIOFORMAT_ADPCM) - { - if (!pb.is_stream) - { - pb.adpcm.yn1 = pb.adpcm_loop_info.yn1; - pb.adpcm.yn2 = pb.adpcm_loop_info.yn2; - pb.adpcm.pred_scale = pb.adpcm_loop_info.pred_scale; - } - } - } - else - { - pb.running = 0; - break; - } - } - // =============== - } // end of the _iSize loop - - // Update volume - //if (sizeof(ParamBlockType) == sizeof(AXParamBlock)) // this is not needed anymore I think - if (gVolume) // allow us to turn this off in the debugger - { - pb.mixer.volume_left = ADPCM_Vol(pb.mixer.volume_left, pb.mixer.unknown); - pb.mixer.volume_right = ADPCM_Vol(pb.mixer.volume_right, pb.mixer.unknown2); - } - - pb.src.cur_addr_frac = (u16)frac; - pb.audio_addr.cur_addr_hi = samplePos >> 16; - pb.audio_addr.cur_addr_lo = (u16)samplePos; - - } // if (pb.running) -} - - - -// ================================================ -// Voice hacks -// -------------- -template -inline void DoVoiceHacks(ParamBlockType &pb, bool Wii) -{ - // get necessary values - const u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo; - const u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo; - const u32 updaddr = (u32)(pb.updates.data_hi << 16) | pb.updates.data_lo; - const u16 updpar = Memory_Read_U16(updaddr); - const u16 upddata = Memory_Read_U16(updaddr + 2); - - // ======================================================================================= - /* Fix problems introduced with the SSBM fix. Sometimes when a music stream ended sampleEnd - would end up outside of bounds while the block was still playing resulting in noise - a strange noise. This should take care of that. - */ - // ------------ - if ( - (sampleEnd > (0x017fffff * 2) || loopPos > (0x017fffff * 2)) // ARAM bounds in nibbles - && gSSBMremedy1 - && !Wii - ) - { - pb.running = 0; - - // also reset all values if it makes any difference - pb.audio_addr.cur_addr_hi = 0; pb.audio_addr.cur_addr_lo = 0; - pb.audio_addr.end_addr_hi = 0; pb.audio_addr.end_addr_lo = 0; - pb.audio_addr.loop_addr_hi = 0; pb.audio_addr.loop_addr_lo = 0; - - pb.src.cur_addr_frac = 0; pb.src.ratio_hi = 0; pb.src.ratio_lo = 0; - pb.adpcm.pred_scale = 0; pb.adpcm.yn1 = 0; pb.adpcm.yn2 = 0; - - pb.audio_addr.looping = 0; - pb.adpcm_loop_info.pred_scale = 0; - pb.adpcm_loop_info.yn1 = 0; pb.adpcm_loop_info.yn2 = 0; - } - - /* - // the fact that no settings are reset (except running) after a SSBM type music stream or another - looping block (for example in Battle Stadium DON) has ended could cause loud garbled sound to be - played from one or more blocks. Perhaps it was in conjunction with the old sequenced music fix below, - I'm not sure. This was an attempt to prevent that anyway by resetting all. But I'm not sure if this - is needed anymore. Please try to play SSBM without it and see if it works anyway. - */ - if ( - // detect blocks that have recently been running that we should reset - pb.running == 0 && pb.audio_addr.looping == 1 - //pb.running == 0 && pb.adpcm_loop_info.pred_scale - - // this prevents us from ruining sequenced music blocks, may not be needed - /* - && !(pb.updates.num_updates[0] || pb.updates.num_updates[1] || pb.updates.num_updates[2] - || pb.updates.num_updates[3] || pb.updates.num_updates[4]) - */ - && !(updpar || upddata) - - && pb.mixer_control == 0 // only use this in SSBM - - && gSSBMremedy2 // let us turn this fix on and off - && !Wii - ) - { - // reset the detection values - pb.audio_addr.looping = 0; - pb.adpcm_loop_info.pred_scale = 0; - pb.adpcm_loop_info.yn1 = 0; pb.adpcm_loop_info.yn2 = 0; - - //pb.audio_addr.cur_addr_hi = 0; pb.audio_addr.cur_addr_lo = 0; - //pb.audio_addr.end_addr_hi = 0; pb.audio_addr.end_addr_lo = 0; - //pb.audio_addr.loop_addr_hi = 0; pb.audio_addr.loop_addr_lo = 0; - - //pb.src.cur_addr_frac = 0; PBs[i].src.ratio_hi = 0; PBs[i].src.ratio_lo = 0; - //pb.adpcm.pred_scale = 0; pb.adpcm.yn1 = 0; pb.adpcm.yn2 = 0; - } - - // ============= - - - // ======================================================================================= - // Reset all values - // ------------ - if (gReset - && (pb.running || pb.audio_addr.looping || pb.adpcm_loop_info.pred_scale) - ) - { - pb.running = 0; - - pb.audio_addr.cur_addr_hi = 0; pb.audio_addr.cur_addr_lo = 0; - pb.audio_addr.end_addr_hi = 0; pb.audio_addr.end_addr_lo = 0; - pb.audio_addr.loop_addr_hi = 0; pb.audio_addr.loop_addr_lo = 0; - - pb.src.cur_addr_frac = 0; pb.src.ratio_hi = 0; pb.src.ratio_lo = 0; - pb.adpcm.pred_scale = 0; pb.adpcm.yn1 = 0; pb.adpcm.yn2 = 0; - - pb.audio_addr.looping = 0; - pb.adpcm_loop_info.pred_scale = 0; - pb.adpcm_loop_info.yn1 = 0; pb.adpcm_loop_info.yn2 = 0; - } -} - - -#endif // _UCODE_AX_VOICE_H +// 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_AX_VOICE_H +#define _UCODE_AX_VOICE_H + +#include "UCode_AX_ADPCM.h" +#include "UCode_AX.h" + +// ---------------------------------------------------- +// Externals +// ----------- +extern bool gSSBM; +extern bool gSSBMremedy1; +extern bool gSSBMremedy2; +extern bool gSequenced; +extern bool gVolume; +extern bool gReset; +extern bool gSequenced; +extern float ratioFactor; + + +template +inline int ReadOutPBsWii(u32 pbs_address, ParamBlockType& _pPBs, int _num) +{ + int count = 0; + u32 blockAddr = pbs_address; + u32 pAddr = 0; + + // reading and 'halfword' swap + for (int i = 0; i < _num; i++) + { + const short *pSrc = (const short *)g_dspInitialize.pGetMemoryPointer(blockAddr); + pAddr = blockAddr; + + if (pSrc != NULL) + { + short *pDest = (short *)&_pPBs[i]; + for (u32 p = 0; p < sizeof(AXParamBlockWii) / 2; p++) + { + if(p == 6 || p == 7) pDest[p] = pSrc[p]; // control for the u32 + else pDest[p] = Common::swap16(pSrc[p]); + + } + + _pPBs[i].mixer_control = Common::swap32(_pPBs[i].mixer_control); + blockAddr = (_pPBs[i].next_pb_hi << 16) | _pPBs[i].next_pb_lo; + count++; + + // Detect the last mail by checking when next_pb = 0 + u32 next_pb = (Common::swap16(pSrc[0]) << 16) | Common::swap16(pSrc[1]); + if(next_pb == 0) break; + } + else + break; + } + + // return the number of read PBs + return count; +} + +template +inline void WriteBackPBsWii(u32 pbs_address, ParamBlockType& _pPBs, int _num) +//void WriteBackPBsWii(u32 pbs_address, AXParamBlockWii* _pPBs, int _num) +{ + u32 blockAddr = pbs_address; + + // write back and 'halfword'swap + for (int i = 0; i < _num; i++) + { + short* pSrc = (short*)&_pPBs[i]; + short* pDest = (short*)g_dspInitialize.pGetMemoryPointer(blockAddr); + _pPBs[i].mixer_control = Common::swap32(_pPBs[i].mixer_control); + for (size_t p = 0; p < sizeof(AXParamBlockWii) / 2; p++) + { + if(p == 6 || p == 7) pDest[p] = pSrc[p]; // control for the u32 + else pDest[p] = Common::swap16(pSrc[p]); + } + + // next block + blockAddr = (_pPBs[i].next_pb_hi << 16) | _pPBs[i].next_pb_lo; + } +} + + +template +inline void MixAddVoice(ParamBlockType &pb, int *templbuffer, int *temprbuffer, int _iSize, bool Wii) +{ + DoVoiceHacks(pb, Wii); + + // ============= + if (pb.running) + { + + // ======================================================================================= + // Read initial parameters + // ------------ + //constants + const u32 ratio = (u32)(((pb.src.ratio_hi << 16) + pb.src.ratio_lo) * ratioFactor); + u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo; + u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo; + + //variables + u32 samplePos = (pb.audio_addr.cur_addr_hi << 16) | pb.audio_addr.cur_addr_lo; + u32 frac = pb.src.cur_addr_frac; + // ============= + + // ======================================================================================= + // Handle No-SRC streams - No src streams have pb.src_type == 2 and have pb.src.ratio_hi = 0 + // and pb.src.ratio_lo = 0. We handle that by setting the sampling ratio integer to 1. This + // makes samplePos update in the correct way. I'm unsure how we are actually supposed to + // detect that this setting. Updates did not fix this automatically. + // --------------------------------------------------------------------------------------- + // Stream settings + // src_type = 2 (most other games have src_type = 0) + // ------------ + // Affected games: + // Baten Kaitos - Eternal Wings (2003) + // Baten Kaitos - Origins (2006)? + // Soul Calibur 2: The movie music use src_type 2 but it needs no adjustment, perhaps + // the sound format plays in to, Baten use ADPCM, SC2 use PCM16 + // ------------ + //if (pb.src_type == 2 && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0)) + if (pb.running && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0)) + { + pb.src.ratio_hi = 1; + } + // ============= + + + // ======================================================================================= + // Games that use looping to play non-looping music streams - SSBM has info in all + // pb.adpcm_loop_info parameters but has pb.audio_addr.looping = 0. If we treat these streams + // like any other looping streams the music works. I'm unsure how we are actually supposed to + // detect that these kinds of blocks should be looping. It seems like pb.mixer_control == 0 may + // identify these types of blocks. Updates did not write any looping values. + // -------------- + if ( + (pb.adpcm_loop_info.pred_scale || pb.adpcm_loop_info.yn1 || pb.adpcm_loop_info.yn2) + && pb.mixer_control == 0 + ) + { + pb.audio_addr.looping = 1; + } + // ============== + + // Top Spin 3 Wii + if(pb.audio_addr.sample_format > 25) pb.audio_addr.sample_format = 0; + + // ======================================================================================= + // Walk through _iSize. _iSize = numSamples. If the game goes slow _iSize will be higher to + // compensate for that. _iSize can be as low as 100 or as high as 2000 some cases. + for (int s = 0; s < _iSize; s++) + { + int sample = 0; + frac += ratio; + u32 newSamplePos = samplePos + (frac >> 16); //whole number of frac + + // ======================================================================================= + // Process sample format + // -------------- + switch (pb.audio_addr.sample_format) + { + case AUDIOFORMAT_PCM8: + // TODO - the linear interpolation code below is somewhat suspicious + pb.adpcm.yn2 = pb.adpcm.yn1; //save last sample + pb.adpcm.yn1 = ((s8)g_dspInitialize.pARAM_Read_U8(samplePos)) << 8; + + if (pb.src_type == SRCTYPE_NEAREST) + { + sample = pb.adpcm.yn1; + } + else //linear interpolation + { + sample = (pb.adpcm.yn1 * (u16)frac + pb.adpcm.yn2 * (u16)(0xFFFF - frac)) >> 16; + } + + samplePos = newSamplePos; + break; + + case AUDIOFORMAT_PCM16: + // TODO - the linear interpolation code below is somewhat suspicious + pb.adpcm.yn2 = pb.adpcm.yn1; //save last sample + pb.adpcm.yn1 = (s16)(u16)((g_dspInitialize.pARAM_Read_U8(samplePos * 2) << 8) | (g_dspInitialize.pARAM_Read_U8((samplePos * 2 + 1)))); + if (pb.src_type == SRCTYPE_NEAREST) + sample = pb.adpcm.yn1; + else //linear interpolation + sample = (pb.adpcm.yn1 * (u16)frac + pb.adpcm.yn2 * (u16)(0xFFFF - frac)) >> 16; + + samplePos = newSamplePos; + break; + + case AUDIOFORMAT_ADPCM: + sample = ADPCM_Step(pb.adpcm, samplePos, newSamplePos, frac); + break; + + default: + break; + } + // ================ + + // =================================================================== + // Overall volume control. In addition to this there is also separate volume settings to + // different channels (left, right etc). + frac &= 0xffff; + + int vol = pb.vol_env.cur_volume >> 9; + sample = sample * vol >> 8; + + if (pb.mixer_control & MIXCONTROL_RAMPING) + { + int x = pb.vol_env.cur_volume; + x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game + // that use this? Or how does it work? + if (x < 0) x = 0; + if (x >= 0x7fff) x = 0x7fff; + pb.vol_env.cur_volume = x; // maybe not per sample?? :P + } + + int leftmix = pb.mixer.volume_left >> 5; + int rightmix = pb.mixer.volume_right >> 5; + int left = sample * leftmix >> 8; + int right = sample * rightmix >> 8; + //adpcm has to walk from oldSamplePos to samplePos here + templbuffer[s] += left; + temprbuffer[s] += right; + // =============== + + + // =================================================================== + // Control the behavior when we reach the end of the sample + if (samplePos >= sampleEnd) + { + if (pb.audio_addr.looping == 1) + { + samplePos = loopPos; + if (pb.audio_addr.sample_format == AUDIOFORMAT_ADPCM) + { + if (!pb.is_stream) + { + pb.adpcm.yn1 = pb.adpcm_loop_info.yn1; + pb.adpcm.yn2 = pb.adpcm_loop_info.yn2; + pb.adpcm.pred_scale = pb.adpcm_loop_info.pred_scale; + } + } + } + else + { + pb.running = 0; + break; + } + } + // =============== + } // end of the _iSize loop + + // Update volume + //if (sizeof(ParamBlockType) == sizeof(AXParamBlock)) // this is not needed anymore I think + if (gVolume) // allow us to turn this off in the debugger + { + pb.mixer.volume_left = ADPCM_Vol(pb.mixer.volume_left, pb.mixer.unknown); + pb.mixer.volume_right = ADPCM_Vol(pb.mixer.volume_right, pb.mixer.unknown2); + } + + pb.src.cur_addr_frac = (u16)frac; + pb.audio_addr.cur_addr_hi = samplePos >> 16; + pb.audio_addr.cur_addr_lo = (u16)samplePos; + + } // if (pb.running) +} + + + +// ================================================ +// Voice hacks +// -------------- +template +inline void DoVoiceHacks(ParamBlockType &pb, bool Wii) +{ + // get necessary values + const u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo; + const u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo; + const u32 updaddr = (u32)(pb.updates.data_hi << 16) | pb.updates.data_lo; + const u16 updpar = Memory_Read_U16(updaddr); + const u16 upddata = Memory_Read_U16(updaddr + 2); + + // ======================================================================================= + /* Fix problems introduced with the SSBM fix. Sometimes when a music stream ended sampleEnd + would end up outside of bounds while the block was still playing resulting in noise + a strange noise. This should take care of that. + */ + // ------------ + if ( + (sampleEnd > (0x017fffff * 2) || loopPos > (0x017fffff * 2)) // ARAM bounds in nibbles + && gSSBMremedy1 + && !Wii + ) + { + pb.running = 0; + + // also reset all values if it makes any difference + pb.audio_addr.cur_addr_hi = 0; pb.audio_addr.cur_addr_lo = 0; + pb.audio_addr.end_addr_hi = 0; pb.audio_addr.end_addr_lo = 0; + pb.audio_addr.loop_addr_hi = 0; pb.audio_addr.loop_addr_lo = 0; + + pb.src.cur_addr_frac = 0; pb.src.ratio_hi = 0; pb.src.ratio_lo = 0; + pb.adpcm.pred_scale = 0; pb.adpcm.yn1 = 0; pb.adpcm.yn2 = 0; + + pb.audio_addr.looping = 0; + pb.adpcm_loop_info.pred_scale = 0; + pb.adpcm_loop_info.yn1 = 0; pb.adpcm_loop_info.yn2 = 0; + } + + /* + // the fact that no settings are reset (except running) after a SSBM type music stream or another + looping block (for example in Battle Stadium DON) has ended could cause loud garbled sound to be + played from one or more blocks. Perhaps it was in conjunction with the old sequenced music fix below, + I'm not sure. This was an attempt to prevent that anyway by resetting all. But I'm not sure if this + is needed anymore. Please try to play SSBM without it and see if it works anyway. + */ + if ( + // detect blocks that have recently been running that we should reset + pb.running == 0 && pb.audio_addr.looping == 1 + //pb.running == 0 && pb.adpcm_loop_info.pred_scale + + // this prevents us from ruining sequenced music blocks, may not be needed + /* + && !(pb.updates.num_updates[0] || pb.updates.num_updates[1] || pb.updates.num_updates[2] + || pb.updates.num_updates[3] || pb.updates.num_updates[4]) + */ + && !(updpar || upddata) + + && pb.mixer_control == 0 // only use this in SSBM + + && gSSBMremedy2 // let us turn this fix on and off + && !Wii + ) + { + // reset the detection values + pb.audio_addr.looping = 0; + pb.adpcm_loop_info.pred_scale = 0; + pb.adpcm_loop_info.yn1 = 0; pb.adpcm_loop_info.yn2 = 0; + + //pb.audio_addr.cur_addr_hi = 0; pb.audio_addr.cur_addr_lo = 0; + //pb.audio_addr.end_addr_hi = 0; pb.audio_addr.end_addr_lo = 0; + //pb.audio_addr.loop_addr_hi = 0; pb.audio_addr.loop_addr_lo = 0; + + //pb.src.cur_addr_frac = 0; PBs[i].src.ratio_hi = 0; PBs[i].src.ratio_lo = 0; + //pb.adpcm.pred_scale = 0; pb.adpcm.yn1 = 0; pb.adpcm.yn2 = 0; + } + + // ============= + + + // ======================================================================================= + // Reset all values + // ------------ + if (gReset + && (pb.running || pb.audio_addr.looping || pb.adpcm_loop_info.pred_scale) + ) + { + pb.running = 0; + + pb.audio_addr.cur_addr_hi = 0; pb.audio_addr.cur_addr_lo = 0; + pb.audio_addr.end_addr_hi = 0; pb.audio_addr.end_addr_lo = 0; + pb.audio_addr.loop_addr_hi = 0; pb.audio_addr.loop_addr_lo = 0; + + pb.src.cur_addr_frac = 0; pb.src.ratio_hi = 0; pb.src.ratio_lo = 0; + pb.adpcm.pred_scale = 0; pb.adpcm.yn1 = 0; pb.adpcm.yn2 = 0; + + pb.audio_addr.looping = 0; + pb.adpcm_loop_info.pred_scale = 0; + pb.adpcm_loop_info.yn1 = 0; pb.adpcm_loop_info.yn2 = 0; + } +} + + +#endif // _UCODE_AX_VOICE_H