From 5ca6d2761e68826ce63f6e224fecd35093a369e2 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Wed, 1 Jul 2009 20:55:43 +0000 Subject: [PATCH] DSPHLE: Early implementation of volume. I'm sure there's something missing but this makes the Zelda games sound a lot better, except WW which loses a lot of audio on the title screen and link's noises are too soft. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3635 8ced0084-cf51-0410-be5f-012b33b47a6e --- .../Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp | 3 +- .../Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h | 20 +++-- .../Src/UCodes/UCode_Zelda_Synth.cpp | 86 +++++++++---------- .../Src/UCodes/UCode_Zelda_Voice.cpp | 58 ++++++++----- .../Plugin_DSP_HLE/Src/UCodes/UCodes.cpp | 16 ++-- 5 files changed, 104 insertions(+), 79 deletions(-) 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 937ef1e672..28c3749b66 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp @@ -264,6 +264,7 @@ void CUCode_Zelda::Update(int cycles) void CUCode_Zelda::HandleMail(u32 _uMail) { + // WARN_LOG(DSPHLE, "Zelda uCode: Handle mail %08X", _uMail); // When we used to lose sync, the last mails we get before the audio goes bye-bye // 0 // 0x00000 @@ -640,7 +641,7 @@ void CUCode_Zelda::MixAdd(short* _Buffer, int _Size) if (pb.KeyOff != 0) continue; - MixAddVoice(pb, m_LeftBuffer, m_RightBuffer, _Size); + RenderAddVoice(pb, m_LeftBuffer, m_RightBuffer, _Size); WritebackVoicePB(m_VoicePBsAddr + (i * 0x180), pb); } 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 2f053077c2..69a8bfbe9f 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h @@ -38,9 +38,11 @@ struct ZeldaVoicePB 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 - u32 volumeRight; // 0x09 | Right Volume + 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 - u32 volumeLeft; // 0x0D | Left Volume + u16 volumeRight1; // 0x0D | Right Volume 1 + u16 volumeRight2; // 0x0E | Right Volume 2 u16 Unk0F[0x8]; // 0x0F | unknown // Buffer / something, see 036e/ZWW. there's a pattern here u16 Unk18[0x10]; // 0x18 | unknown u16 Unk28; // 0x28 | unknown @@ -145,6 +147,7 @@ private: u32 m_CRC; s32* m_TempBuffer; + s32* m_LeftBuffer; s32* m_RightBuffer; @@ -208,13 +211,14 @@ private: void ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB); void WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB); - void MixAddVoice_PCM16(ZeldaVoicePB& PB, s32* _Buffer, int _Size); - void MixAddVoice_AFC(ZeldaVoicePB& PB, s32* _Buffer, int _Size); - void MixAddVoice(ZeldaVoicePB& PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size); + // Voice formats + void RenderSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size); + void RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size); + void RenderVoice_PCM16(ZeldaVoicePB& PB, s32* _Buffer, int _Size); + void RenderVoice_AFC(ZeldaVoicePB& PB, s32* _Buffer, int _Size); - - void MixAddSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size); - void MixAddSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size); + // Renders a voice and mixes it into LeftBuffer, RightBuffer + void RenderAddVoice(ZeldaVoicePB& PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size); }; #endif diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Synth.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Synth.cpp index 0749c4d69c..721b3e9269 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Synth.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_Synth.cpp @@ -1,35 +1,35 @@ -// Copyright (C) 2003-2009 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_Zelda.h" -#include "UCode_Zelda_ADPCM.h" - -#include "../main.h" -#include "Mixer.h" - -void CUCode_Zelda::MixAddSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size) -{ +// Copyright (C) 2003-2009 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_Zelda.h" +#include "UCode_Zelda_ADPCM.h" + +#include "../main.h" +#include "Mixer.h" + +void CUCode_Zelda::RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size) +{ float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); u32 _ratio = (((PB.RatioInt * 80) + PB.RatioFrac) << 4) & 0xFFFF0000; - u64 ratio = (u64)(((_ratio / 80) << 16) * ratioFactor); - int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1; - + u64 ratio = (u64)(((_ratio / 80) << 16) * ratioFactor); + int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1; + u32 pos[2] = {0, 0}; int i = 0; @@ -87,16 +87,16 @@ _lRestart: PB.RemLength -= pos[1]; PB.CurAddr += pos[1] << 1; - // There should be a position fraction as well. -} - - -void CUCode_Zelda::MixAddSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size) -{ - // TODO: Header, footer and cases this synth actually happens - for (int i = 0; i < _Size; i++) - _Buffer[i++] = (s32)PB.RatioInt; -} - - - + // There should be a position fraction as well. +} + + +void CUCode_Zelda::RenderSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size) +{ + // TODO: Header, footer and cases this synth actually happens + for (int i = 0; i < _Size; i++) + _Buffer[i++] = (s32)PB.RatioInt; +} + + + 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 04e9621917..e957d5a29d 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 @@ -54,7 +54,7 @@ void CUCode_Zelda::WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB) memory[i] = Common::swap16(((u16*)&PB)[i]); } -void CUCode_Zelda::MixAddVoice_PCM16(ZeldaVoicePB &PB, s32* _Buffer, int _Size) +void CUCode_Zelda::RenderVoice_PCM16(ZeldaVoicePB &PB, s32* _Buffer, int _Size) { float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); u32 _ratio = (((PB.RatioInt * 80) + PB.RatioFrac) << 4) & 0xFFFF0000; @@ -126,7 +126,7 @@ _lRestart: // There should be a position fraction as well. } -void CUCode_Zelda::MixAddVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size) +void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size) { float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); u32 _ratio = (PB.RatioInt<<16) + PB.RatioFrac; @@ -151,6 +151,25 @@ void CUCode_Zelda::MixAddVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size) // Copy ARAM addr from r to rw area. PB.CurAddr = PB.StartAddr; PB.ReachedEnd = 0; + + // Looking at Zelda Four Swords + // WARN_LOG(DSPHLE, "PB -----: %04x", PB.Unk03); + // WARN_LOG(DSPHLE, "PB Unk03: %04x", PB.Unk03); 0 + // WARN_LOG(DSPHLE, "PB Unk07: %04x", PB.Unk07[0]); 0 + + //WARN_LOG(DSPHLE, "PB Unk09: %04x", PB.volumeLeft1); // often same value as 0a + //WARN_LOG(DSPHLE, "PB Unk0a: %04x", PB.volumeLeft2); + + //WARN_LOG(DSPHLE, "PB Unk0d: %04x", PB.volumeRight1); // often same value as 0e + //WARN_LOG(DSPHLE, "PB Unk0e: %04x", PB.volumeRight2); + + /// WARN_LOG(DSPHLE, "PB Unk78: %04x", PB.Unk78); + // WARN_LOG(DSPHLE, "PB Unk79: %04x", PB.Unk79); + // WARN_LOG(DSPHLE, "PB Unk31: %04x", PB.Unk31); + // WARN_LOG(DSPHLE, "PB Unk36: %04x", PB.Unk36[0]); + // WARN_LOG(DSPHLE, "PB Unk37: %04x", PB.Unk36[1]); + // WARN_LOG(DSPHLE, "PB Unk3c: %04x", PB.Unk3C[0]); + // WARN_LOG(DSPHLE, "PB Unk3d: %04x", PB.Unk3C[1]); } if (PB.KeyOff != 0) // 0747 early out... i dunno if this can happen because we filter it above @@ -160,8 +179,6 @@ void CUCode_Zelda::MixAddVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size) // u32 frac = NumberOfSamples & 0xF; // NumberOfSamples = (NumberOfSamples + 0xf) >> 4; // i think the lower 4 are the fraction - u32 sampleCount = 0; - u8 *source; u32 ram_mask = 1024 * 1024 * 16 - 1; if (m_CRC == 0xD643001F) { @@ -171,13 +188,6 @@ void CUCode_Zelda::MixAddVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size) else source = g_dspInitialize.pGetARAMPointer(); - // It must be something like this: - - // The PB contains a small sample buffer of 0x4D decoded samples. - // If it's empty or "used", decode to it. - // Then, resample from this buffer to the output as you go. When it needs - // wrapping, decode more. - restart: if (PB.ReachedEnd) { @@ -196,7 +206,7 @@ restart: // This needs adjustment. It's not right for AFC, was just copied from PCM16. // We should also probably reinitialize YN1 and YN2 with something - but with what? PB.RestartPos = PB.LoopStartPos; - PB.RemLength = PB.Length - PB.RestartPos; + PB.RemLength = PB.Length - PB.RestartPos; PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); // pos[1] = 0; pos[0] = 0; } @@ -209,11 +219,12 @@ restart: u32 prev_addr = PB.CurAddr; // Prefill the decode buffer. - AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, 9); + AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format); PB.CurAddr += 9; s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 32; s64 delta = ratio; // 0x100000000ULL; + int sampleCount = 0; while (sampleCount < _Size) { int SamplePosition = TrueSamplePosition >> 32; @@ -241,7 +252,7 @@ restart: prev_yn2 = PB.YN2; prev_addr = PB.CurAddr; - AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, 9); + AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format); PB.CurAddr += 9; } } @@ -267,7 +278,7 @@ restart: // end of block (Zelda 03b2) } -void CUCode_Zelda::MixAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size) +void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size) { memset(m_TempBuffer, 0, _Size * sizeof(s32)); @@ -285,12 +296,12 @@ void CUCode_Zelda::MixAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBu case 0x0000: // Example: Magic meter filling up in ZWW case 0x0001: // Example: "Denied" sound when trying to pull out a sword // indoors in ZWW - MixAddSynth_Waveform(PB, m_TempBuffer, _Size); + RenderSynth_Waveform(PB, m_TempBuffer, _Size); break; case 0x0006: WARN_LOG(DSPHLE, "Synthesizing 0x0006 (constant sound)"); - MixAddSynth_Constant(PB, m_TempBuffer, _Size); + RenderSynth_Constant(PB, m_TempBuffer, _Size); break; // These are more "synth" formats - square wave, saw wave etc. @@ -308,11 +319,11 @@ void CUCode_Zelda::MixAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBu //if(PB.SoundType == 0x0d00) // break; - MixAddVoice_AFC(PB, m_TempBuffer, _Size); + RenderVoice_AFC(PB, m_TempBuffer, _Size); break; case 0x0010: // PCM16 - normal PCM 16-bit audio. - MixAddVoice_PCM16(PB, m_TempBuffer, _Size); + RenderVoice_PCM16(PB, m_TempBuffer, _Size); break; @@ -334,8 +345,13 @@ void CUCode_Zelda::MixAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBu for (int i = 0; i < _Size; i++) { - s32 left = _LeftBuffer[i] + m_TempBuffer[i]; - s32 right = _RightBuffer[i] + m_TempBuffer[i]; + // 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); if (left < -32768) left = -32768; if (left > 32767) left = 32767; diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp index 1615198e44..e1e0be5765 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp @@ -32,12 +32,15 @@ IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler) switch (_CRC) { case UCODE_ROM: + INFO_LOG(DSPHLE, "Switching to ROM ucode"); return new CUCode_Rom(_rMailHandler); case UCODE_INIT_AUDIO_SYSTEM: + INFO_LOG(DSPHLE, "Switching to INIT ucode"); return new CUCode_InitAudioSystem(_rMailHandler); case 0x65d6cc6f: // CARD + INFO_LOG(DSPHLE, "Switching to CARD ucode"); return new CUCode_CARD(_rMailHandler); case 0x3ad3b7ac: // Naruto3, Paper Mario - The Thousand Year Door @@ -49,28 +52,29 @@ IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler) case 0x07f88145: // bustamove, ikaruga, fzero, robotech battle cry, star soldier, soul calibur2, // Zelda:OOT, Tony hawk, viewtiful joe case 0xe2136399: // billy hatcher, dragonballz, mario party 5, TMNT, ava1080 - INFO_LOG(CONSOLE, "AX ucode chosen, yay!\n"); + INFO_LOG(DSPHLE, "CRC %08x: AX ucode chosen", _CRC); return new CUCode_AX(_rMailHandler); case 0x088e38a5: // IPL - JAP case 0xd73338cf: // IPL case 0x42f64ac4: // Luigi + case 0x0267d05a: // http://forums.dolphin-emu.com/thread-2134.html Pikmin PAL case 0x4be6a5cb: // AC, Pikmin - INFO_LOG(CONSOLE, "JAC (early Zelda) ucode chosen\n"); + INFO_LOG(DSPHLE, "CRC %08x: JAC (early Zelda) ucode chosen", _CRC); return new CUCode_Jac(_rMailHandler); -// return new CUCode_Zelda(_rMailHandler, false); +// return new CUCode_Zelda(_rMailHandler, _CRC); case 0x6CA33A6D: // DK Jungle Beat case 0x86840740: // Zelda WW - US case 0x56d36052: // Mario Sunshine case 0x2fcdf1ec: // Mario Kart, zelda 4 swords - INFO_LOG(CONSOLE, "Zelda ucode chosen\n"); + INFO_LOG(DSPHLE, "CRC %08x: Zelda ucode chosen", _CRC); return new CUCode_Zelda(_rMailHandler, _CRC); // WII CRCs case 0x6c3f6f94: // zelda - PAL case 0xd643001f: // mario galaxy - PAL - INFO_LOG(CONSOLE, "Zelda Wii ucode chosen\n"); + INFO_LOG(DSPHLE, "CRC %08x: Zelda Wii ucode chosen\n", _CRC); return new CUCode_Zelda(_rMailHandler, _CRC); case 0x5ef56da3: // AX demo @@ -80,7 +84,7 @@ IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler) case 0xb7eb9a9c: // Wii Pikmin - JAP case 0x4cc52064: // Bleach: Versus Crusade case 0xd9c4bf34: // WiiMenu ... pray - INFO_LOG(CONSOLE, "Wii - AXWii chosen\n"); + INFO_LOG(DSPHLE, "CRC %08x: Wii - AXWii chosen", _CRC); return new CUCode_AXWii(_rMailHandler, _CRC); default: