DSPHLE: Some code reorg, now looks more like the ucode. DSPLLE: Rename a file.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3763 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2009-07-12 12:22:39 +00:00
parent b363b2ddc8
commit 304b34a451
10 changed files with 166 additions and 156 deletions

View File

@ -231,49 +231,44 @@ void Shutdown()
void Read16(u16& _uReturnValue, const u32 _iAddress) void Read16(u16& _uReturnValue, const u32 _iAddress)
{ {
// WTF is this check about? DSP is at 5000 TODO remove // WTF is this check about? DSP is at 5000 TODO remove
if ((_iAddress & 0x6C00) != 0x6c00) if ((_iAddress & 0x6C00) != 0x6c00)
{ {
if (_iAddress != 0xCC005004)
{
DEBUG_LOG(DSPINTERFACE, "DSPInterface(r16) 0x%08x", _iAddress);
}
switch (_iAddress & 0xFFFF) switch (_iAddress & 0xFFFF)
{ {
// AI_REGS 0x5000+ // AI_REGS 0x5000+
case DSP_MAIL_TO_DSP_HI: case DSP_MAIL_TO_DSP_HI:
_uReturnValue = dsp_plugin->DSP_ReadMailboxHigh(true); _uReturnValue = dsp_plugin->DSP_ReadMailboxHigh(true);
return; break;
case DSP_MAIL_TO_DSP_LO: case DSP_MAIL_TO_DSP_LO:
_uReturnValue = dsp_plugin->DSP_ReadMailboxLow(true); _uReturnValue = dsp_plugin->DSP_ReadMailboxLow(true);
return; break;
case DSP_MAIL_FROM_DSP_HI: case DSP_MAIL_FROM_DSP_HI:
_uReturnValue = dsp_plugin->DSP_ReadMailboxHigh(false); _uReturnValue = dsp_plugin->DSP_ReadMailboxHigh(false);
return; break;
case DSP_MAIL_FROM_DSP_LO: case DSP_MAIL_FROM_DSP_LO:
_uReturnValue = dsp_plugin->DSP_ReadMailboxLow(false); _uReturnValue = dsp_plugin->DSP_ReadMailboxLow(false);
return; break;
case DSP_CONTROL: case DSP_CONTROL:
_uReturnValue = (g_dspState.DSPControl.Hex & ~DSP_CONTROL_MASK) | _uReturnValue = (g_dspState.DSPControl.Hex & ~DSP_CONTROL_MASK) |
(dsp_plugin->DSP_ReadControlRegister() & DSP_CONTROL_MASK); (dsp_plugin->DSP_ReadControlRegister() & DSP_CONTROL_MASK);
return; break;
// AR_REGS 0x501x+ // AR_REGS 0x501x+
case 0x5012: case 0x5012:
_uReturnValue = g_AR_MODE; _uReturnValue = g_AR_MODE;
return; break;
case 0x5016: // ready flag? case 0x5016: // ready flag?
_uReturnValue = g_AR_READY_FLAG; _uReturnValue = g_AR_READY_FLAG;
return; break;
case 0x501a: case 0x501a:
_uReturnValue = 0x000; _uReturnValue = 0x000;
return; break;
case AR_DMA_MMADDR_H: _uReturnValue = g_arDMA.MMAddr >> 16; return; case AR_DMA_MMADDR_H: _uReturnValue = g_arDMA.MMAddr >> 16; return;
case AR_DMA_MMADDR_L: _uReturnValue = g_arDMA.MMAddr & 0xFFFF; return; case AR_DMA_MMADDR_L: _uReturnValue = g_arDMA.MMAddr & 0xFFFF; return;
@ -287,24 +282,29 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
// Hmm. Would be stupid to ask for bytes left. Assume it wants // Hmm. Would be stupid to ask for bytes left. Assume it wants
// blocks left. // blocks left.
_uReturnValue = g_audioDMA.BlocksLeft; _uReturnValue = g_audioDMA.BlocksLeft;
return; break;
case AUDIO_DMA_START_LO: case AUDIO_DMA_START_LO:
_uReturnValue = g_audioDMA.SourceAddress & 0xFFFF; _uReturnValue = g_audioDMA.SourceAddress & 0xFFFF;
return; break;
case AUDIO_DMA_START_HI: case AUDIO_DMA_START_HI:
_uReturnValue = g_audioDMA.SourceAddress >> 16; _uReturnValue = g_audioDMA.SourceAddress >> 16;
return; break;
case AUDIO_DMA_CONTROL_LEN: case AUDIO_DMA_CONTROL_LEN:
_uReturnValue = g_audioDMA.AudioDMAControl.Hex; _uReturnValue = g_audioDMA.AudioDMAControl.Hex;
return; break;
default: default:
_dbg_assert_(DSPINTERFACE,0); _dbg_assert_(DSPINTERFACE,0);
break; break;
} }
if (_iAddress != 0xCC005004)
{
DEBUG_LOG(DSPINTERFACE, "DSPInterface(r16) 0x%08x (%02x) (%08x)", _iAddress, _uReturnValue, PowerPC::ppcState.pc);
}
return;
} }
else else
{ {
@ -317,9 +317,8 @@ void Write16(const u16 _Value, const u32 _Address)
{ {
DEBUG_LOG(DSPINTERFACE, "DSPInterface(w16) 0x%04x 0x%08x", _Value, _Address); DEBUG_LOG(DSPINTERFACE, "DSPInterface(w16) 0x%04x 0x%08x", _Value, _Address);
switch(_Address & 0xFFFF) switch (_Address & 0xFFFF)
{ {
// DSP Regs 0x5000+ // DSP Regs 0x5000+
case DSP_MAIL_TO_DSP_HI: case DSP_MAIL_TO_DSP_HI:
dsp_plugin->DSP_WriteMailboxHigh(true, _Value); dsp_plugin->DSP_WriteMailboxHigh(true, _Value);

View File

@ -24,7 +24,7 @@ void HLEMixer::MixUCode(short *samples, int numSamples) {
// if this was called directly from the HLE, and not by timeout // if this was called directly from the HLE, and not by timeout
if (g_Config.m_EnableHLEAudio && IsHLEReady()) { if (g_Config.m_EnableHLEAudio && IsHLEReady()) {
IUCode* pUCode = CDSPHandler::GetInstance().GetUCode(); IUCode* pUCode = CDSPHandler::GetInstance().GetUCode();
if (pUCode != NULL) if (pUCode && samples)
pUCode->MixAdd(samples, numSamples); pUCode->MixAdd(samples, numSamples);
} }
} }

View File

@ -81,7 +81,8 @@ CUCode_Zelda::CUCode_Zelda(CMailHandler& _rMailHandler, u32 _CRC)
m_rMailHandler.PushMail(0xF3551111); // handshake m_rMailHandler.PushMail(0xF3551111); // handshake
} }
m_TempBuffer = new s32[256 * 1024]; m_VoiceBuffer = new s32[256 * 1024];
m_ResampleBuffer = new s32[256 * 1024];
m_LeftBuffer = new s32[256 * 1024]; m_LeftBuffer = new s32[256 * 1024];
m_RightBuffer = new s32[256 * 1024]; m_RightBuffer = new s32[256 * 1024];
@ -95,7 +96,8 @@ CUCode_Zelda::~CUCode_Zelda()
{ {
m_rMailHandler.Clear(); m_rMailHandler.Clear();
delete [] m_TempBuffer; delete [] m_VoiceBuffer;
delete [] m_ResampleBuffer;
delete [] m_LeftBuffer; delete [] m_LeftBuffer;
delete [] m_RightBuffer; delete [] m_RightBuffer;
} }
@ -474,4 +476,3 @@ void CUCode_Zelda::DoState(PointerWrap &p) {
p.Do(m_PBAddress); p.Do(m_PBAddress);
p.Do(m_PBAddress2); p.Do(m_PBAddress2);
} }

View File

@ -76,10 +76,7 @@ union ZeldaVoicePB
u16 Unk36[2]; // 0x36 | unknown // loaded at 0adc/ZWW in 0x21 decoder u16 Unk36[2]; // 0x36 | unknown // loaded at 0adc/ZWW in 0x21 decoder
u32 CurAddr; // 0x38 | current address u32 CurAddr; // 0x38 | current address
u32 RemLength; // 0x3A | remaining length u32 RemLength; // 0x3A | remaining length
u16 Unk3C; // 0x3C | something to do with the resampler - a DRAM address? u16 ResamplerOldData[4]; // 0x3C | The resampler stores the last 4 decoded samples here from the previous frame, so that the filter kernel has something to read before the start of the buffer.
u16 Unk3D; // 0x3D | unknown
u16 Unk3E; // 0x3E | unknown
u16 Unk3F; // 0x3F | unknown
u16 Unk40[0x10]; // 0x40 | Used as some sort of buffer by IIR u16 Unk40[0x10]; // 0x40 | Used as some sort of buffer by IIR
u16 Unk50[0x8]; // 0x50 | Used as some sort of buffer by 06ff/ZWW u16 Unk50[0x8]; // 0x50 | Used as some sort of buffer by 06ff/ZWW
u16 Unk58[0x8]; // 0x58 | u16 Unk58[0x8]; // 0x58 |
@ -168,7 +165,8 @@ private:
u32 m_CRC; u32 m_CRC;
// These are the only dynamically allocated things allowed in the ucode. // These are the only dynamically allocated things allowed in the ucode.
s32* m_TempBuffer; s32* m_VoiceBuffer;
s32* m_ResampleBuffer;
s32* m_LeftBuffer; s32* m_LeftBuffer;
s32* m_RightBuffer; s32* m_RightBuffer;
@ -243,6 +241,8 @@ private:
void RenderVoice_AFC(ZeldaVoicePB& PB, s32* _Buffer, int _Size); void RenderVoice_AFC(ZeldaVoicePB& PB, s32* _Buffer, int _Size);
void RenderVoice_Raw(ZeldaVoicePB& PB, s32* _Buffer, int _Size); void RenderVoice_Raw(ZeldaVoicePB& PB, s32* _Buffer, int _Size);
void Resample(ZeldaVoicePB &PB, int size, s32 *in, s32 *out);
// Renders a voice and mixes it into LeftBuffer, RightBuffer // Renders a voice and mixes it into LeftBuffer, RightBuffer
void RenderAddVoice(ZeldaVoicePB& PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size); void RenderAddVoice(ZeldaVoicePB& PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size);
}; };

View File

@ -30,9 +30,11 @@ void CUCode_Zelda::ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB)
for (int i = 0; i < (0x180 / 2); i++) for (int i = 0; i < (0x180 / 2); i++)
((u16*)&PB)[i] = Common::swap16(memory[i]); ((u16*)&PB)[i] = Common::swap16(memory[i]);
// Word swap all 32-bit variables.
PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16); PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16);
PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16); PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16);
PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16); PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16);
// Read only part
PB.LoopStartPos = (PB.LoopStartPos << 16) | (PB.LoopStartPos >> 16); PB.LoopStartPos = (PB.LoopStartPos << 16) | (PB.LoopStartPos >> 16);
PB.Length = (PB.Length << 16) | (PB.Length >> 16); PB.Length = (PB.Length << 16) | (PB.Length >> 16);
PB.StartAddr = (PB.StartAddr << 16) | (PB.StartAddr >> 16); PB.StartAddr = (PB.StartAddr << 16) | (PB.StartAddr >> 16);
@ -43,6 +45,7 @@ void CUCode_Zelda::WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB)
{ {
u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr); u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr);
// Word swap all 32-bit variables.
PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16); PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16);
PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16); PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16);
PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16); PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16);
@ -53,9 +56,11 @@ 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::RenderVoice_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 << 16); u32 _ratio = (PB.RatioInt << 16);
s64 ratio = (_ratio * ratioFactor) * 16; s64 ratio = (_ratio * ratioFactor) * 16;
@ -67,6 +72,7 @@ void CUCode_Zelda::RenderVoice_PCM16(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
if (PB.NeedsReset) if (PB.NeedsReset)
{ {
// 0a7f_UpdateSampleCounters10
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);
PB.ReachedEnd = 0; PB.ReachedEnd = 0;
@ -94,7 +100,7 @@ _lRestart:
} }
s16 *source; s16 *source;
if (m_CRC == 0xD643001F) if (m_CRC == 0xD643001F) // SMG
source = (s16*)(g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr) + PB.CurAddr); source = (s16*)(g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr) + PB.CurAddr);
else else
source = (s16*)(g_dspInitialize.pGetARAMPointer() + PB.CurAddr); source = (s16*)(g_dspInitialize.pGetARAMPointer() + PB.CurAddr);
@ -102,11 +108,8 @@ _lRestart:
for (; outpos < _Size;) for (; outpos < _Size;)
{ {
// Simple linear interpolation. // Simple linear interpolation.
float sample1 = (s16)Common::swap16(source[inpos[1]]); const s16 sample = (s16)Common::swap16(source[inpos[1]]);
float sample2 = (s16)Common::swap16(source[inpos[1]]); _Buffer[outpos++] = sample;
float frac = float(inpos[0] >> 16) / 65536.0f;
_Buffer[outpos++] = sample1 * (1-frac) + sample2 * frac;
(*(u64*)&inpos) += ratio; (*(u64*)&inpos) += ratio;
if ((inpos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length) if ((inpos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length)
@ -132,16 +135,14 @@ _lRestart:
void CUCode_Zelda::RenderVoice_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);
s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor); s64 ratio = (_ratio * ratioFactor) * 16;
// initialize "decoder" if the sample is played the first time // initialize "decoder" if the sample is played the first time
if (PB.NeedsReset != 0) if (PB.NeedsReset != 0)
{ {
// This is 0717_ReadOutPBStuff // This is 0717_ReadOutPBStuff
// increment 4fb // increment 4fb
// zelda: // zelda:
// perhaps init or "has played before" // perhaps init or "has played before"
PB.CurBlock = 0x00; PB.CurBlock = 0x00;
@ -150,23 +151,10 @@ void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
// Length in samples. // Length in samples.
PB.RemLength = PB.Length; PB.RemLength = PB.Length;
// 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;
PB.CurSampleFrac = 0; PB.CurSampleFrac = 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 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
@ -176,7 +164,7 @@ void CUCode_Zelda::RenderVoice_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
u8 *source; const u8 *source;
u32 ram_mask = 1024 * 1024 * 16 - 1; u32 ram_mask = 1024 * 1024 * 16 - 1;
if (m_CRC == 0xD643001F) { if (m_CRC == 0xD643001F) {
source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr); source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr);
@ -205,12 +193,10 @@ restart:
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;
} }
} }
short outbuf[16] = {0}; short outbuf[16] = {0};
u16 prev_yn1 = PB.YN1; u16 prev_yn1 = PB.YN1;
u16 prev_yn2 = PB.YN2; u16 prev_yn2 = PB.YN2;
u32 prev_addr = PB.CurAddr; u32 prev_addr = PB.CurAddr;
@ -277,31 +263,30 @@ restart:
} }
//u32 last_remlength = 0;
// Researching what's actually inside the mysterious 0x21 case // Researching what's actually inside the mysterious 0x21 case
// 0x21 seems to really just be reading raw 16-bit audio from RAM (not ARAM).
void CUCode_Zelda::RenderVoice_Raw(ZeldaVoicePB &PB, s32* _Buffer, int _Size) void CUCode_Zelda::RenderVoice_Raw(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;
s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor); s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor);
s64 value1; s64 samples_to_read;
// TODO: De-Ugly // TODO: De-Ugly
if(PB.Format == 0x21) // Resampled if (PB.Format == 0x21) // Resampled
value1 = (((PB.raw[0x30] + (PB.raw[2] * 0x50)) << 4) & 0xFFFF0000) >> 8; samples_to_read = (((PB.CurSampleFrac + (PB.RatioInt * 0x50)) << 4) & 0xFFFF0000) >> 8;
else if(PB.Format == 0x20) // Unsampled else if (PB.Format == 0x20) // Unsampled
value1 = 0x50; samples_to_read = 0x50;
// End of sound // End of sound
if(((PB.raw[0x3a] << 16) | PB.raw[0x3b]) <= value1) if (((PB.raw[0x3a] << 16) | PB.raw[0x3b]) <= samples_to_read)
{ {
PB.KeyOff = 1; PB.KeyOff = 1;
PB.RemLength = 0; PB.RemLength = 0;
return; return;
} }
if (PB.NeedsReset != 0) if (PB.NeedsReset != 0)
{ {
PB.CurBlock = 0x00; PB.CurBlock = 0x00;
@ -343,7 +328,6 @@ restart:
} }
u32 prev_addr = PB.CurAddr; u32 prev_addr = PB.CurAddr;
//ERROR_LOG(DSPHLE, "%08x %08x DMA", PB.StartAddr, PB.CurAddr);
const u16 *src = (u16 *)(source + (PB.CurAddr & ram_mask)); const u16 *src = (u16 *)(source + (PB.CurAddr & ram_mask));
@ -381,97 +365,116 @@ restart:
void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size) void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size)
{ {
//static u16 lastLeft = 0x1FF, lastRight = 0x1FF; //static u16 lastLeft = 0x1FF, lastRight = 0x1FF;
memset(m_TempBuffer, 0, _Size * sizeof(s32));
if (PB.IsBlank) if (PB.IsBlank)
{ {
s32 sample = (s32)(s16)PB.FixedSample; s32 sample = (s32)(s16)PB.FixedSample;
for (int i = 0; i < _Size; i++) for (int i = 0; i < _Size; i++)
m_TempBuffer[i] = sample; m_VoiceBuffer[i] = sample;
}
else
{
// XK: Use this to disable music (GREAT for testing)
//if(PB.SoundType == 0x0d00) {
// PB.NeedsReset = 0;
// return;
//}
//WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x",
// PB.Format, PB.SoundType, PB.Unk29, PB.Unk2a);
/*WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x %04x %04x %04x %04x %04x %04x",
PB.Format, PB.SoundType,
PB.volumeLeft1, PB.volumeLeft2, PB.volumeRight1, PB.volumeRight2,
PB.volumeUnknown1_1, PB.volumeUnknown1_2, PB.volumeUnknown2_1,
PB.volumeUnknown2_2);*/
goto ContinueWithBlock; // Yes, a goto. Yes, it's evil, but it makes the flow look much more like the DSP code.
}
// XK: Use this to disable MIDI music (GREAT for testing). Also kills some sound FX.
//if(PB.SoundType == 0x0d00) {
// PB.NeedsReset = 0;
// return;
//}
// The Resample calls actually don't resample yet.
// ResampleBuffer corresponds to 0x0580 in ZWW ucode.
// VoiceBuffer corresponds to 0x0520.
// First jump table at ZWW: 2a6
switch (PB.Format)
{
case 0x0005: // AFC with extra low bitrate (32:5 compression). Not yet seen.
WARN_LOG(DSPHLE, "5 byte AFC - does it work?");
case 0x0009: // AFC with normal bitrate (32:9 compression).
RenderVoice_AFC(PB, m_ResampleBuffer, _Size);
Resample(PB, _Size, m_ResampleBuffer, m_VoiceBuffer);
break;
case 0x0008: // Likely PCM8 - normal PCM 8-bit audio. Used in Mario Kart DD.
WARN_LOG(DSPHLE, "Unimplemented MixAddVoice format in zelda %04x", PB.Format);
memset(m_ResampleBuffer, 0, _Size * sizeof(s32));
Resample(PB, _Size, m_ResampleBuffer, m_VoiceBuffer);
break;
case 0x0010: // PCM16 - normal PCM 16-bit audio.
RenderVoice_PCM16(PB, m_ResampleBuffer, _Size);
Resample(PB, _Size, m_ResampleBuffer, m_VoiceBuffer);
break;
case 0x0020:
// Normally, this shouldn't resample, it should just decode directly
// to the output buffer. However, (if we ever see this sound type), we'll
// have to resample anyway since we're running at a different sample rate.
#if 0 // To hear something weird in ZWW, turn this on.
// Caution: Use at your own risk. Sounds awful :)
RenderVoice_Raw(PB, m_ResampleBuffer, _Size);
#else
// This is what 0x20 and 0x21 do on end of voice
PB.RemLength = 0;
PB.KeyOff = 1;
#endif
Resample(PB, _Size, m_ResampleBuffer, m_VoiceBuffer);
break;
case 0x0021:
// Raw sound from RAM. Important for Zelda WW. Really need to implement - missing it causes hangs.
#if 0 // To hear something weird in ZWW, turn this on.
// Caution: Use at your own risk. Sounds awful :)
RenderVoice_Raw(PB, m_ResampleBuffer, _Size);
#else
// This is what 0x20 and 0x21 do on end of voice
PB.RemLength = 0;
PB.KeyOff = 1;
#endif
Resample(PB, _Size, m_ResampleBuffer, m_VoiceBuffer);
break;
default:
// Second jump table
switch (PB.Format) switch (PB.Format)
{ {
// Synthesized sounds // Synthesized sounds
case 0x0000: // Example: Magic meter filling up in ZWW case 0x0000: // Example: Magic meter filling up in ZWW
case 0x0003: case 0x0003:
RenderSynth_RectWave(PB, m_TempBuffer, _Size); RenderSynth_RectWave(PB, m_VoiceBuffer, _Size);
break; break;
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
RenderSynth_SawWave(PB, m_TempBuffer, _Size); RenderSynth_SawWave(PB, m_VoiceBuffer, _Size);
break; break;
case 0x0006: case 0x0006:
WARN_LOG(DSPHLE, "Synthesizing 0x0006 (constant sound)"); WARN_LOG(DSPHLE, "Synthesizing 0x0006 (constant sound)");
RenderSynth_Constant(PB, m_TempBuffer, _Size); RenderSynth_Constant(PB, m_VoiceBuffer, _Size);
break; break;
// These are more "synth" formats - square wave, saw wave etc. // These are more "synth" formats - square wave, saw wave etc.
case 0x0002: case 0x0002:
case 0x000c: // Example: beam of death/yellow force-field in Temple of the Gods, ZWW case 0x000c: // Example: beam of death/yellow force-field in Temple of the Gods, ZWW
WARN_LOG(DSPHLE, "Synthesizing 0x%04x", PB.Format); WARN_LOG(DSPHLE, "Synthesizing 0x%04x", PB.Format);
break; break;
// AFC formats
case 0x0005: // AFC with extra low bitrate (32:5 compression). Not yet seen.
WARN_LOG(DSPHLE, "5 byte AFC - does it work?");
case 0x0009: // AFC with normal bitrate (32:9 compression).
RenderVoice_AFC(PB, m_TempBuffer, _Size);
break;
case 0x0010: // PCM16 - normal PCM 16-bit audio.
RenderVoice_PCM16(PB, m_TempBuffer, _Size);
//last_remlength = PB.RemLength;
break;
case 0x0008: // Likely PCM8 - normal PCM 8-bit audio. Used in Mario Kart DD.
// Example: Second time in "Hyrule", in the king's
// room, when fighting the two knights (in ZWW, of course)
WARN_LOG(DSPHLE, "Unimplemented MixAddVoice format in zelda %04x", PB.Format);
break;
case 0x0020:
case 0x0021: // Probably raw sound. Important for Zelda WW. Really need to implement - missing it causes hangs.
WARN_LOG(DSPHLE, "Unimplemented MixAddVoice format in zelda %04x", PB.Format);
#if 1 // To hear something weird in ZWW, turn this on.
RenderVoice_Raw(PB, m_TempBuffer, _Size);
#else
// This is what 0x20 and 0x21 do on end of voice
PB.RemLength = 0;
PB.KeyOff = 1;
#endif
// Caution: Use at your own risk. Sounds awful :)
break;
default: default:
// TODO: Implement general decoder here // TODO: Implement general decoder here
memset(m_VoiceBuffer, 0, _Size * sizeof(s32));
ERROR_LOG(DSPHLE, "Unknown MixAddVoice format in zelda %04x", PB.Format); ERROR_LOG(DSPHLE, "Unknown MixAddVoice format in zelda %04x", PB.Format);
break; break;
} }
// Necessary for SMG, not for Zelda. Weird.
PB.NeedsReset = 0;
} }
// ContinueWithBlock: // Necessary for SMG, not for Zelda. Weird. Where's it from?
PB.NeedsReset = 0;
ContinueWithBlock:
if (PB.FilterEnable) if (PB.FilterEnable)
{ // 0x04a8 { // 0x04a8
@ -486,6 +489,7 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ
} }
// Apply volume. There are two different modes.
if (PB.VolumeMode != 0) if (PB.VolumeMode != 0)
{ {
// Complex volume mode. Let's see what we can do. // Complex volume mode. Let's see what we can do.
@ -496,7 +500,6 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ
PB.KeyOff = 1; PB.KeyOff = 1;
} }
} }
short AX0L = PB.raw[0x28] >> 8; short AX0L = PB.raw[0x28] >> 8;
short AX0H = PB.raw[0x28] & 0x7F; short AX0H = PB.raw[0x28] & 0x7F;
short AX1L = AX0L ^ 0x7F; short AX1L = AX0L ^ 0x7F;
@ -544,7 +547,7 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ
int ramp = value << 16; int ramp = value << 16;
for (int i = 0; i < _Size; i++) for (int i = 0; i < _Size; i++)
{ {
int unmixed_audio = m_TempBuffer[i]; int unmixed_audio = m_VoiceBuffer[i];
switch (count) { switch (count) {
case 0: _LeftBuffer[i] += (u64)unmixed_audio * ramp >> 29; break; case 0: _LeftBuffer[i] += (u64)unmixed_audio * ramp >> 29; break;
case 1: _RightBuffer[i] += (u64)unmixed_audio * ramp >> 29; break; case 1: _RightBuffer[i] += (u64)unmixed_audio * ramp >> 29; break;
@ -592,11 +595,12 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ
addr--; addr--;
u32 ramp = vol1 << 16; u32 ramp = vol1 << 16;
if (mix) { if (mix)
{
// 0ca9_RampedMultiplyAddBuffer // 0ca9_RampedMultiplyAddBuffer
for (int i = 0; i < _Size; i++) for (int i = 0; i < _Size; i++)
{ {
int value = m_TempBuffer[i]; int value = m_VoiceBuffer[i];
// TODO - add to buffer specified by dest_buffer_address // TODO - add to buffer specified by dest_buffer_address
switch (count) switch (count)
@ -622,16 +626,25 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ
} }
} }
void CUCode_Zelda::Resample(ZeldaVoicePB &PB, int size, s32 *in, s32 *out)
{
// TODO
memcpy(out, in, size * sizeof(int));
}
// size is in stereo samples. // size is in stereo samples.
void CUCode_Zelda::MixAdd(short* _Buffer, int _Size) void CUCode_Zelda::MixAdd(short *_Buffer, int _Size)
{ {
// Safety check
if (_Size > 256 * 1024) if (_Size > 256 * 1024)
_Size = 256 * 1024; _Size = 256 * 1024;
// Final mix buffers
memset(m_LeftBuffer, 0, _Size * sizeof(s32)); memset(m_LeftBuffer, 0, _Size * sizeof(s32));
memset(m_RightBuffer, 0, _Size * sizeof(s32)); memset(m_RightBuffer, 0, _Size * sizeof(s32));
// For each PB...
for (u32 i = 0; i < m_NumVoices; i++) for (u32 i = 0; i < m_NumVoices; i++)
{ {
u32 flags = m_SyncFlags[(i >> 4) & 0xF]; u32 flags = m_SyncFlags[(i >> 4) & 0xF];
@ -650,22 +663,20 @@ void CUCode_Zelda::MixAdd(short* _Buffer, int _Size)
WritebackVoicePB(m_VoicePBsAddr + (i * 0x180), pb); WritebackVoicePB(m_VoicePBsAddr + (i * 0x180), pb);
} }
if (_Buffer) // Post processing, final conversion.
for (int i = 0; i < _Size; i++)
{ {
for (u32 i = 0; i < _Size; i++) s32 left = (s32)_Buffer[0] + m_LeftBuffer[i];
{ s32 right = (s32)_Buffer[1] + m_RightBuffer[i];
s32 left = (s32)_Buffer[0] + m_LeftBuffer[i];
s32 right = (s32)_Buffer[1] + m_RightBuffer[i];
if (left < -32768) left = -32768; if (left < -32768) left = -32768;
if (left > 32767) left = 32767; if (left > 32767) left = 32767;
_Buffer[0] = (short)left; _Buffer[0] = (short)left;
if (right < -32768) right = -32768; if (right < -32768) right = -32768;
if (right > 32767) right = 32767; if (right > 32767) right = 32767;
_Buffer[1] = (short)right; _Buffer[1] = (short)right;
_Buffer += 2; _Buffer += 2;
}
} }
} }

View File

@ -802,14 +802,6 @@
<Filter <Filter
Name="Debugger" Name="Debugger"
> >
<File
RelativePath=".\Src\debugger\Debugger.cpp"
>
</File>
<File
RelativePath=".\Src\debugger\Debugger.h"
>
</File>
<File <File
RelativePath=".\Src\DSPDebugInterface.cpp" RelativePath=".\Src\DSPDebugInterface.cpp"
> >
@ -818,6 +810,14 @@
RelativePath=".\Src\DSPDebugInterface.h" RelativePath=".\Src\DSPDebugInterface.h"
> >
</File> </File>
<File
RelativePath=".\Src\Debugger\DSPDebugWindow.cpp"
>
</File>
<File
RelativePath=".\Src\Debugger\DSPDebugWindow.h"
>
</File>
<File <File
RelativePath=".\Src\Debugger\DSPRegisterView.cpp" RelativePath=".\Src\Debugger\DSPRegisterView.cpp"
> >

View File

@ -20,7 +20,7 @@
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include "Debugger.h" #include "DSPDebugWindow.h"
#include "DSPRegisterView.h" #include "DSPRegisterView.h"
#include "CodeView.h" #include "CodeView.h"
#include "../DSPSymbols.h" #include "../DSPSymbols.h"

View File

@ -26,7 +26,7 @@ files = [
if env['HAVE_WX']: if env['HAVE_WX']:
files += [ files += [
"DSPConfigDlgLLE.cpp", "DSPConfigDlgLLE.cpp",
"Debugger/Debugger.cpp", "Debugger/DSPDebugWindow.cpp",
"Debugger/DSPRegisterView.cpp", "Debugger/DSPRegisterView.cpp",
] ]

View File

@ -3470,8 +3470,8 @@ void Decoder0x10() {
// 0a1f 8c00 clr15 // 0a1f 8c00 clr15
// Compute how much data we need to read, to get 0x50 samples after resampling. // Compute how much data we need to read, to get 0x50 samples after resampling.
// AC0.L is cursamplefrace, AX0.L is ratio. // AC0.L is cursamplefrac, AX0.L is ratio.
$ACC0 = PB.CurrentSampleFrac + 0x50 * PB.Ratio; $ACC0 = (PB.CurrentSampleFrac + 0x50 * PB.Ratio) << 4;
0a20 1ffe mrr $AC1.M, $AC0.M 0a20 1ffe mrr $AC1.M, $AC0.M
0a21 0083 0580 lri $AR3, #0x0580 0a21 0083 0580 lri $AR3, #0x0580
@ -4661,8 +4661,7 @@ void 0d7f_ResampleAudioData(_src($AR0), _dest($AR1), param(AX1.L) = 0, _option??
$AR0 = $AR0 - 4; $AR0 = $AR0 - 4;
$AR2 = $AR0; $AR2 = $AR0;
// 0x043c in the PBs apparently is a pointer, INTO the PB itself - where it // 0x043c to 0x043f is storage for old sample data.
// has stored the data from the last frame.
0d86 0083 043c lri $AR3, #0x043c 0d86 0083 043c lri $AR3, #0x043c
// Pipelined tiny memcpy - first four are loads, last four are stores. middle two overlap. // Pipelined tiny memcpy - first four are loads, last four are stores. middle two overlap.
@ -4795,8 +4794,8 @@ back_from_JustCopyWithoutResampling:
0dec 191e lrri $AC0.M, @$AR0 0dec 191e lrri $AC0.M, @$AR0
0ded 191f lrri $AC1.M, @$AR0 0ded 191f lrri $AC1.M, @$AR0
0dee 80a0 nx'ls : $AX0.H, $AC0.M 0dee 80a0 nx'ls : $AX0.H, $AC0.M
0def 64a1 movr'ls $ACC0, $AX0.H : $AX0.H, $AC1.M 0def 64a1 movr'ls $AC0.M, $AX0.H : $AX0.H, $AC1.M
0df0 6533 movr's $ACC1, $AX0.H : @$AR3, $AC0.M 0df0 6533 movr's $AC1.M, $AX0.H : @$AR3, $AC0.M
0df1 1b7f srri @$AR3, $AC1.M 0df1 1b7f srri @$AR3, $AC1.M
// 0df2 02df ret // 0df2 02df ret
return; return;