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
This commit is contained in:
hrydgard 2009-07-01 20:55:43 +00:00
parent de83d1cda4
commit 5ca6d2761e
5 changed files with 104 additions and 79 deletions

View File

@ -264,6 +264,7 @@ void CUCode_Zelda::Update(int cycles)
void CUCode_Zelda::HandleMail(u32 _uMail) 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 // When we used to lose sync, the last mails we get before the audio goes bye-bye
// 0 // 0
// 0x00000 // 0x00000
@ -640,7 +641,7 @@ void CUCode_Zelda::MixAdd(short* _Buffer, int _Size)
if (pb.KeyOff != 0) if (pb.KeyOff != 0)
continue; continue;
MixAddVoice(pb, m_LeftBuffer, m_RightBuffer, _Size); RenderAddVoice(pb, m_LeftBuffer, m_RightBuffer, _Size);
WritebackVoicePB(m_VoicePBsAddr + (i * 0x180), pb); WritebackVoicePB(m_VoicePBsAddr + (i * 0x180), pb);
} }

View File

@ -38,9 +38,11 @@ struct ZeldaVoicePB
u16 IsBlank; // 0x06 | 0 = normal sound, 1 = samples are always the same u16 IsBlank; // 0x06 | 0 = normal sound, 1 = samples are always the same
u16 Unk07; // 0x07 | unknown, in zelda always 0x0010 u16 Unk07; // 0x07 | unknown, in zelda always 0x0010
u16 SoundType; // 0x08 | Sound type: so far in zww: 0x0d00 for music, 0x4861 for sfx 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 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 Unk0F[0x8]; // 0x0F | unknown // Buffer / something, see 036e/ZWW. there's a pattern here
u16 Unk18[0x10]; // 0x18 | unknown u16 Unk18[0x10]; // 0x18 | unknown
u16 Unk28; // 0x28 | unknown u16 Unk28; // 0x28 | unknown
@ -145,6 +147,7 @@ private:
u32 m_CRC; u32 m_CRC;
s32* m_TempBuffer; s32* m_TempBuffer;
s32* m_LeftBuffer; s32* m_LeftBuffer;
s32* m_RightBuffer; s32* m_RightBuffer;
@ -208,13 +211,14 @@ private:
void ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB); void ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB);
void WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB); void WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB);
void MixAddVoice_PCM16(ZeldaVoicePB& PB, s32* _Buffer, int _Size); // Voice formats
void MixAddVoice_AFC(ZeldaVoicePB& PB, s32* _Buffer, int _Size); void RenderSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size);
void MixAddVoice(ZeldaVoicePB& PB, s32* _LeftBuffer, s32* _RightBuffer, 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);
// Renders a voice and mixes it into LeftBuffer, RightBuffer
void MixAddSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size); void RenderAddVoice(ZeldaVoicePB& PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size);
void MixAddSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size);
}; };
#endif #endif

View File

@ -1,35 +1,35 @@
// Copyright (C) 2003-2009 Dolphin Project. // Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0. // the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details. // GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program. // A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/ // If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at // Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
#include "../Globals.h" #include "../Globals.h"
#include "UCodes.h" #include "UCodes.h"
#include "UCode_Zelda.h" #include "UCode_Zelda.h"
#include "UCode_Zelda_ADPCM.h" #include "UCode_Zelda_ADPCM.h"
#include "../main.h" #include "../main.h"
#include "Mixer.h" #include "Mixer.h"
void CUCode_Zelda::MixAddSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size) void CUCode_Zelda::RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{ {
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (((PB.RatioInt * 80) + PB.RatioFrac) << 4) & 0xFFFF0000; u32 _ratio = (((PB.RatioInt * 80) + PB.RatioFrac) << 4) & 0xFFFF0000;
u64 ratio = (u64)(((_ratio / 80) << 16) * ratioFactor); u64 ratio = (u64)(((_ratio / 80) << 16) * ratioFactor);
int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1; int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1;
u32 pos[2] = {0, 0}; u32 pos[2] = {0, 0};
int i = 0; int i = 0;
@ -87,16 +87,16 @@ _lRestart:
PB.RemLength -= pos[1]; PB.RemLength -= pos[1];
PB.CurAddr += pos[1] << 1; PB.CurAddr += pos[1] << 1;
// There should be a position fraction as well. // There should be a position fraction as well.
} }
void CUCode_Zelda::MixAddSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size) void CUCode_Zelda::RenderSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{ {
// TODO: Header, footer and cases this synth actually happens // TODO: Header, footer and cases this synth actually happens
for (int i = 0; i < _Size; i++) for (int i = 0; i < _Size; i++)
_Buffer[i++] = (s32)PB.RatioInt; _Buffer[i++] = (s32)PB.RatioInt;
} }

View File

@ -54,7 +54,7 @@ void CUCode_Zelda::WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB)
memory[i] = Common::swap16(((u16*)&PB)[i]); 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(); float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (((PB.RatioInt * 80) + PB.RatioFrac) << 4) & 0xFFFF0000; u32 _ratio = (((PB.RatioInt * 80) + PB.RatioFrac) << 4) & 0xFFFF0000;
@ -126,7 +126,7 @@ _lRestart:
// There should be a position fraction as well. // 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(); float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (PB.RatioInt<<16) + PB.RatioFrac; 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. // Copy ARAM addr from r to rw area.
PB.CurAddr = PB.StartAddr; PB.CurAddr = PB.StartAddr;
PB.ReachedEnd = 0; 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 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; // u32 frac = NumberOfSamples & 0xF;
// NumberOfSamples = (NumberOfSamples + 0xf) >> 4; // i think the lower 4 are the fraction // NumberOfSamples = (NumberOfSamples + 0xf) >> 4; // i think the lower 4 are the fraction
u32 sampleCount = 0;
u8 *source; u8 *source;
u32 ram_mask = 1024 * 1024 * 16 - 1; u32 ram_mask = 1024 * 1024 * 16 - 1;
if (m_CRC == 0xD643001F) { if (m_CRC == 0xD643001F) {
@ -171,13 +188,6 @@ void CUCode_Zelda::MixAddVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
else else
source = g_dspInitialize.pGetARAMPointer(); 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: restart:
if (PB.ReachedEnd) if (PB.ReachedEnd)
{ {
@ -196,7 +206,7 @@ restart:
// This needs adjustment. It's not right for AFC, was just copied from PCM16. // 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? // We should also probably reinitialize YN1 and YN2 with something - but with what?
PB.RestartPos = PB.LoopStartPos; PB.RestartPos = PB.LoopStartPos;
PB.RemLength = PB.Length - PB.RestartPos; PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
// pos[1] = 0; pos[0] = 0; // pos[1] = 0; pos[0] = 0;
} }
@ -209,11 +219,12 @@ restart:
u32 prev_addr = PB.CurAddr; u32 prev_addr = PB.CurAddr;
// Prefill the decode buffer. // 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; PB.CurAddr += 9;
s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 32; s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 32;
s64 delta = ratio; // 0x100000000ULL; s64 delta = ratio; // 0x100000000ULL;
int sampleCount = 0;
while (sampleCount < _Size) while (sampleCount < _Size)
{ {
int SamplePosition = TrueSamplePosition >> 32; int SamplePosition = TrueSamplePosition >> 32;
@ -241,7 +252,7 @@ restart:
prev_yn2 = PB.YN2; prev_yn2 = PB.YN2;
prev_addr = PB.CurAddr; 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; PB.CurAddr += 9;
} }
} }
@ -267,7 +278,7 @@ restart:
// end of block (Zelda 03b2) // 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)); 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 0x0000: // Example: Magic meter filling up in ZWW
case 0x0001: // Example: "Denied" sound when trying to pull out a sword case 0x0001: // Example: "Denied" sound when trying to pull out a sword
// indoors in ZWW // indoors in ZWW
MixAddSynth_Waveform(PB, m_TempBuffer, _Size); RenderSynth_Waveform(PB, m_TempBuffer, _Size);
break; break;
case 0x0006: case 0x0006:
WARN_LOG(DSPHLE, "Synthesizing 0x0006 (constant sound)"); WARN_LOG(DSPHLE, "Synthesizing 0x0006 (constant sound)");
MixAddSynth_Constant(PB, m_TempBuffer, _Size); RenderSynth_Constant(PB, m_TempBuffer, _Size);
break; break;
// These are more "synth" formats - square wave, saw wave etc. // 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) //if(PB.SoundType == 0x0d00)
// break; // break;
MixAddVoice_AFC(PB, m_TempBuffer, _Size); RenderVoice_AFC(PB, m_TempBuffer, _Size);
break; break;
case 0x0010: // PCM16 - normal PCM 16-bit audio. case 0x0010: // PCM16 - normal PCM 16-bit audio.
MixAddVoice_PCM16(PB, m_TempBuffer, _Size); RenderVoice_PCM16(PB, m_TempBuffer, _Size);
break; break;
@ -334,8 +345,13 @@ void CUCode_Zelda::MixAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBu
for (int i = 0; i < _Size; i++) for (int i = 0; i < _Size; i++)
{ {
s32 left = _LeftBuffer[i] + m_TempBuffer[i]; // TODO: Some noises in Zelda WW (birds, etc) have a volume of 0
s32 right = _RightBuffer[i] + m_TempBuffer[i]; // 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 < -32768) left = -32768;
if (left > 32767) left = 32767; if (left > 32767) left = 32767;

View File

@ -32,12 +32,15 @@ IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler)
switch (_CRC) switch (_CRC)
{ {
case UCODE_ROM: case UCODE_ROM:
INFO_LOG(DSPHLE, "Switching to ROM ucode");
return new CUCode_Rom(_rMailHandler); return new CUCode_Rom(_rMailHandler);
case UCODE_INIT_AUDIO_SYSTEM: case UCODE_INIT_AUDIO_SYSTEM:
INFO_LOG(DSPHLE, "Switching to INIT ucode");
return new CUCode_InitAudioSystem(_rMailHandler); return new CUCode_InitAudioSystem(_rMailHandler);
case 0x65d6cc6f: // CARD case 0x65d6cc6f: // CARD
INFO_LOG(DSPHLE, "Switching to CARD ucode");
return new CUCode_CARD(_rMailHandler); return new CUCode_CARD(_rMailHandler);
case 0x3ad3b7ac: // Naruto3, Paper Mario - The Thousand Year Door 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, case 0x07f88145: // bustamove, ikaruga, fzero, robotech battle cry, star soldier, soul calibur2,
// Zelda:OOT, Tony hawk, viewtiful joe // Zelda:OOT, Tony hawk, viewtiful joe
case 0xe2136399: // billy hatcher, dragonballz, mario party 5, TMNT, ava1080 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); return new CUCode_AX(_rMailHandler);
case 0x088e38a5: // IPL - JAP case 0x088e38a5: // IPL - JAP
case 0xd73338cf: // IPL case 0xd73338cf: // IPL
case 0x42f64ac4: // Luigi case 0x42f64ac4: // Luigi
case 0x0267d05a: // http://forums.dolphin-emu.com/thread-2134.html Pikmin PAL
case 0x4be6a5cb: // AC, Pikmin 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_Jac(_rMailHandler);
// return new CUCode_Zelda(_rMailHandler, false); // return new CUCode_Zelda(_rMailHandler, _CRC);
case 0x6CA33A6D: // DK Jungle Beat case 0x6CA33A6D: // DK Jungle Beat
case 0x86840740: // Zelda WW - US case 0x86840740: // Zelda WW - US
case 0x56d36052: // Mario Sunshine case 0x56d36052: // Mario Sunshine
case 0x2fcdf1ec: // Mario Kart, zelda 4 swords 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); return new CUCode_Zelda(_rMailHandler, _CRC);
// WII CRCs // WII CRCs
case 0x6c3f6f94: // zelda - PAL case 0x6c3f6f94: // zelda - PAL
case 0xd643001f: // mario galaxy - 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); return new CUCode_Zelda(_rMailHandler, _CRC);
case 0x5ef56da3: // AX demo case 0x5ef56da3: // AX demo
@ -80,7 +84,7 @@ IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler)
case 0xb7eb9a9c: // Wii Pikmin - JAP case 0xb7eb9a9c: // Wii Pikmin - JAP
case 0x4cc52064: // Bleach: Versus Crusade case 0x4cc52064: // Bleach: Versus Crusade
case 0xd9c4bf34: // WiiMenu ... pray 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); return new CUCode_AXWii(_rMailHandler, _CRC);
default: default: