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 bfc434faba..2345bb4493 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp @@ -99,16 +99,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 - // 0 - // 0x10000 - // 0 - // 0x20000 - // 0 - // 0x30000 - // And then silence... Looks like some reverse countdown :) + if (m_bSyncInProgress) { if (m_bSyncCmdPending) 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 4942270424..9bd049033b 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h @@ -221,6 +221,7 @@ private: 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 RenderVoice_Raw(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); 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 80ee9fff15..70da655bc0 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 @@ -28,6 +28,8 @@ void CUCode_Zelda::RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Siz float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); u32 _ratio = (PB.RatioInt << 16); s64 ratio = (_ratio * ratioFactor) * 16; + s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16; + TrueSamplePosition += PB.CurSampleFrac; int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1; @@ -65,10 +67,12 @@ _lRestart: } } - for (; i < _Size;) + while(i < _Size) { s16 sample = ((pos[1] & mask) == mask) ? 0xc000 : 0x4000; + TrueSamplePosition += (ratio >> 16); + _Buffer[i++] = (s32)sample; (*(u64*)&pos) += ratio; @@ -87,7 +91,7 @@ _lRestart: else PB.RemLength -= pos[1]; - //PB.CurSampleFrac = TrueSamplePosition & 0xFFFF; + PB.CurSampleFrac = TrueSamplePosition & 0xFFFF; } 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 3b999c13fd..e76ec74226 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 @@ -23,6 +23,8 @@ #include "../main.h" #include "Mixer.h" +#include "../Config.h" + void CUCode_Zelda::ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB) { u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr); @@ -157,18 +159,6 @@ void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size) // 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 UnkVol11: %04x", PB.volumeUnknown1_1); - WARN_LOG(DSPHLE, "PB UnkVol12: %04x", PB.volumeUnknown1_2); - - WARN_LOG(DSPHLE, "PB UnkVol21: %04x", PB.volumeUnknown2_1); - WARN_LOG(DSPHLE, "PB UnkVol22: %04x", PB.volumeUnknown2_2); - /// WARN_LOG(DSPHLE, "PB Unk78: %04x", PB.Unk78); // WARN_LOG(DSPHLE, "PB Unk79: %04x", PB.Unk79); // WARN_LOG(DSPHLE, "PB Unk31: %04x", PB.Unk31); @@ -280,13 +270,98 @@ restart: // i think pTest[0x3a] and pTest[0x3b] got an update after you have decoded some samples... // just decrement them with the number of samples you have played - // and incrrease the ARAM Offset in pTest[0x38], pTest[0x39] + // and increase the ARAM Offset in pTest[0x38], pTest[0x39] // end of block (Zelda 03b2) } +// Researching what's actually inside the mysterious 0x21 case +void CUCode_Zelda::RenderVoice_Raw(ZeldaVoicePB &PB, s32* _Buffer, int _Size) +{ + float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate(); + u32 _ratio = (PB.RatioInt << 16);// + PB.RatioFrac; + s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor); + + if (PB.NeedsReset != 0) + { + PB.CurBlock = 0x00; + + // Length in samples. + PB.RemLength = PB.Length; + + // Copy ARAM addr from r to rw area. + PB.CurAddr = PB.StartAddr; + PB.ReachedEnd = 0; + PB.CurSampleFrac = 0; + } + + if (PB.KeyOff != 0) + return; + + u8 *source; + u32 ram_mask = 1024 * 1024 * 16 - 1; + if (m_CRC == 0xD643001F) { + source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr); + ram_mask = 1024 * 1024 * 64 - 1; + } + else + source = g_dspInitialize.pGetARAMPointer(); + +//restart: + if (PB.ReachedEnd) + { + PB.ReachedEnd = 0; + + // HACK: Looping doesn't work. + if (true || PB.RepeatMode == 0) + { + PB.KeyOff = 1; + PB.RemLength = 0; + PB.CurAddr = PB.StartAddr + PB.RestartPos + PB.Length; + return; + } + else + { + // 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.CurAddr = PB.StartAddr + (PB.RestartPos << 1); + } + } + + + + 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, PB.Format); + const char *src = (char *)(source + (PB.CurAddr & ram_mask)); + PB.CurAddr += 9; + + s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16; + TrueSamplePosition += PB.CurSampleFrac; + s64 delta = ratio >> 16; // 0x100000000ULL; + int sampleCount = 0, realSample = 0; + while (sampleCount < _Size) + { + _Buffer[sampleCount] = src[realSample] | (src[realSample + 1] << 8) | (src[realSample + 2] << 16) + | (src[realSample + 3] << 24); + + //WARN_LOG(DSPHLE, "The sample: %02x", src[sampleCount]); + + sampleCount++; + realSample += 4; + TrueSamplePosition += delta; + } + + PB.NeedsReset = 0; + PB.CurSampleFrac = TrueSamplePosition & 0xFFFF; +} + void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size) { + static u16 lastLeft = 0x1FF, lastRight = 0x1FF; memset(m_TempBuffer, 0, _Size * sizeof(s32)); if (PB.IsBlank) @@ -297,6 +372,19 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ } else { + // XK: Use this to disable music (GREAT for testing) + //if(g_Config.m_DisableStreaming && 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);*/ + switch (PB.Format) { // Synthesized sounds @@ -322,9 +410,7 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ WARN_LOG(DSPHLE, "5 byte AFC - does it work?"); case 0x0009: // AFC with normal bitrate (32:9 compression). - // XK: Use this to disable music (GREAT for testing) - //if(PB.SoundType == 0x0d00) - // break; + RenderVoice_AFC(PB, m_TempBuffer, _Size); break; @@ -335,11 +421,15 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ case 0x0008: // Likely PCM8 - normal PCM 8-bit audio. Used in Mario Kart DD. case 0x0020: - case 0x0021: // Important for Zelda WW. Really need to implement - missing it causes hangs. + 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); - PB.ReachedEnd = 1; + + // This is what 0x20 and 0x21 do on end of voice + PB.RemLength = 0; PB.KeyOff = 1; - PB.Status = 0; + + // Caution: Use at your own risk. Sounds awful :) + //RenderVoice_Raw(PB, m_TempBuffer, _Size); break; default: @@ -354,13 +444,18 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ for (int i = 0; i < _Size; i++) { + if(PB.volumeLeft2) + lastLeft = PB.volumeLeft2; + if(PB.volumeRight2) + lastRight = PB.volumeRight2; + // 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); + (lastLeft & 0x1FFF) + (lastLeft & 0x1FFF)) * 0.00005); s32 right = _RightBuffer[i] + (m_TempBuffer[i] * (float)( - (PB.volumeRight1 & 0x1FFF) + (PB.volumeRight2 & 0x1FFF)) * 0.00005); + (lastRight & 0x1FFF) + (lastRight & 0x1FFF)) * 0.00005); if (left < -32768) left = -32768; if (left > 32767) left = 32767; diff --git a/docs/DSP/DSP_UC_Zelda.txt b/docs/DSP/DSP_UC_Zelda.txt index 29771968bb..ba79345db3 100644 --- a/docs/DSP/DSP_UC_Zelda.txt +++ b/docs/DSP/DSP_UC_Zelda.txt @@ -3441,10 +3441,17 @@ void 0a91_Unk() { //////////////////////////////////////////// 0x20 DECODER { - 0a9a 8900 clr $ACC1 - 0a9b 0f50 lris $AC1.M, #0x50 - 0a9c 0083 0520 lri $AR3, #0x0520 - 0a9e 02bf 0ab3 call 0x0ab3 + // 0a9a 8900 clr $ACC1 + // 0a9b 0f50 lris $AC1.M, #0x50 + // 0a9c 0083 0520 lri $AR3, #0x0520 + // 0a9e 02bf 0ab3 call 0x0ab3 + + ACC1 = 0; + AC1.M = 0x50; + AR3 = 0x520; + + 0ab3_Decoder0x21Core(AC1.M=0x50, AR3=#0x0580); + // 0aa0 029f 02d8 jmp 0x02d8 GOTO ContinueWithBlock: // in SyncFrame } @@ -3485,64 +3492,133 @@ void 0ab3_Decoder0x21Core(AC1.M, AR3) { // 0ab8 1f1f mrr $AX0.L, $AC1.M // 0ab9 0a00 lris $AX0.H, #0x00 // 0aba 5800 subax $ACC0, $AX0.L - ACC0 = [3a,3b] - AC1.M; + ACC0 = [0x043a,0x043b] - AC1.M; + - 0abb 0292 0ad1 jg 0x0ad1 - if ((prev val of)ACC0 > AX0.L) { - 0abd 8900 clr $ACC1 - 0abe 00c0 043b lr $AR0, @0x043b - 0ac0 02bf 0af6 call 0x0af6 // 0af6_Decoder0x21_MoreStuff() + // 0abb 0292 0ad1 jg 0x0ad1 + if ([0x043a,0x043b] > *0x043a) { + // Happens when sound has finished playing? + + // 0abd 8900 clr $ACC1 + // 0abe 00c0 043b lr $AR0, @0x043b + ACC1 = 0; + AR0 = 0x043b; + + // 0ac0 02bf 0af6 call 0x0af6 // 0af6_Decoder0x21_MoreStuff() + 0af6_Decoder0x21_MoreStuff(AR0=0x043b); + + // 0ac2 8100 clr $ACC0 + // 0ac3 1fd8 mrr $AC0.M, $AX0.L + // 0ac4 223b lrs $AX0.H, @0x003b + // 0ac5 5400 subr $ACC0, $AX0.H + // 0ac6 0007 dar $AR3 + // 0ac7 1979 lrri $AX1.L, @$AR3 + + ACC0 = 0; + AX0.H = *0x043b; + AC0.M = AX0.L - *0x043b; + + AX1.L = *$AR3; + + // Looks like duplication of the first memory address AC0.M times + + // 0ac8 005e loop $AC0.M + for(int i = 0; i < AC0.M; i++) { + // 0ac9 1b79 srri @$AR3, $AX1.L + *$AR3++ = AX1.L; + } + + // 0aca 0f01 lris $AC1.M, #0x01 + // 0acb 2f01 srs @0x0001, $AC1.M + // 0acc 8900 clr $ACC1 + // 0acd 2f3b srs @0x003b, $AC1.M + + ACC1 = 0; + + // Looks like some finalization of the PB + *0x0401 = 1; // KeyOff + *0x043b = 0; // RemLength + - 0ac2 8100 clr $ACC0 - 0ac3 1fd8 mrr $AC0.M, $AX0.L - 0ac4 223b lrs $AX0.H, @0x003b - 0ac5 5400 subr $ACC0, $AX0.H - 0ac6 0007 dar $AR3 - 0ac7 1979 lrri $AX1.L, @$AR3 - 0ac8 005e loop $AC0.M - 0ac9 1b79 srri @$AR3, $AX1.L - 0aca 0f01 lris $AC1.M, #0x01 - 0acb 2f01 srs @0x0001, $AC1.M - 0acc 8900 clr $ACC1 - 0acd 2f3b srs @0x003b, $AC1.M 0ace 0092 00ff lri $CR, #0x00ff - 0ad0 02df ret + //0ad0 02df ret + return; } - 0ad1 2e3a srs @0x003a, $AC0.M - 0ad2 2c3b srs @0x003b, $AC0.L - 0ad3 8100 clr $ACC0 - 0ad4 8900 clr $ACC1 - 0ad5 268a lrs $AC0.M, @0xff8a - 0ad6 2734 lrs $AC1.M, @0x0034 - 0ad7 5c00 sub $ACC0, $AC1.L - 0ad8 2e36 srs @0x0036, $AC0.M - 0ad9 5000 subr $ACC0, $AX0.L + + // 0ad1 2e3a srs @0x003a, $AC0.M + // 0ad2 2c3b srs @0x003b, $AC0.L + + *0x043a = AC0.M; + *0x043b = AC0.L; + + // 0ad3 8100 clr $ACC0 + // 0ad4 8900 clr $ACC1 + // 0ad5 268a lrs $AC0.M, @0xff8a + // 0ad6 2734 lrs $AC1.M, @0x0034 + + ACC0 = 0; + ACC1 = 0; + AC0.M = *0x048a; + AC1.M = *0x0434; + + // 0ad7 5c00 sub $ACC0, $AC1.L + // 0ad8 2e36 srs @0x0036, $AC0.M + + ACC0 -= AC1.L; + *0x0436 = (ACC0 & 0xFFFF0000) >> 16; + + // 0ad9 5000 subr $ACC0, $AX0.L + ACC0 -= AX0.L; + 0ada 0290 0af0 jns 0x0af0 - if () { + if (ACC0 < 0) { // 0adc 00c0 0436 lr $AR0, @0x0436 // 0ade 02bf 0af6 call 0x0af6 - 0af6_Decoder0x21_MoreStuff($AR0 = *0x0436); + 0af6_Decoder0x21_MoreStuff(AR0=*0x0436); // 0ae0 8100 clr $ACC0 - 0ae1 1fd8 mrr $AC0.M, $AX0.L - 0ae2 2236 lrs $AX0.H, @0x0036 // 0x0436 - 0ae3 5400 subr $ACC0, $AX0.H - 0ae4 1c1e mrr $AR0, $AC0.M - 0ae5 8100 clr $ACC0 - 0ae6 2e34 srs @0x0034, $AC0.M - 0ae7 2688 lrs $AC0.M, @0xff88 // 0x0488 - 0ae8 2489 lrs $AC0.L, @0xff89 // 0x0489 - 0ae9 2e8c srs @0xff8c, $AC0.M - 0aea 2c8d srs @0xff8d, $AC0.L + // 0ae1 1fd8 mrr $AC0.M, $AX0.L + + ACC0 = 0; + AC0.M = AX0.L; + + // 0ae2 2236 lrs $AX0.H, @0x0036 // 0x0436 + AX0.H = *0x0436; + + // 0ae3 5400 subr $ACC0, $AX0.H + // 0ae4 1c1e mrr $AR0, $AC0.M + // 0ae5 8100 clr $ACC0 + // 0ae6 2e34 srs @0x0034, $AC0.M + + ACC0 -= AX0.H; + AR0 = (ACC0 & 0xFFFF0000) >> 16; + ACC0 = 0; + *0x0434 = 0; + + + // 0ae7 2688 lrs $AC0.M, @0xff88 // 0x0488 + // 0ae8 2489 lrs $AC0.L, @0xff89 // 0x0489 + // 0ae9 2e8c srs @0xff8c, $AC0.M + // 0aea 2c8d srs @0xff8d, $AC0.L + + *0x048c = *0x0488; + *0x048d = *0x0489; + // 0aeb 02bf 0af6 call 0x0af6 - 0af6_Decoder0x21_MoreStuff($AR0 = *0x0436); + 0af6_Decoder0x21_MoreStuff(AR0=*0x0436); 0aed 0092 00ff lri $CR, #0x00ff // 0aef 02df ret return; } - 0af0 1c18 mrr $AR0, $AX0.L - 0af1 02bf 0af6 call 0x0af6 + + // 0af0 1c18 mrr $AR0, $AX0.L + // 0af1 02bf 0af6 call 0x0af6 + + AR0 = AX0.L; + 0af6_Decoder0x21_MoreStuff(AR0=AX0.L); + + 0af3 0092 00ff lri $CR, #0x00ff // 0af5 02df ret } @@ -3552,19 +3628,24 @@ void 0ab3_Decoder0x21Core(AC1.M, AR3) { // Does strange stuff with PB[0x34] and the address PB[0x8c,d] // Does not touch AX0.L void 0af6_Decoder0x21_MoreStuff($AR0) { - 0af6 8100 clr $ACC0 - 0af7 1fc0 mrr $AC0.M, $AR0 + // 0af6 8100 clr $ACC0 + // 0af7 1fc0 mrr $AC0.M, $AR0 // 0af8 b100 tst $ACC0 // 0af9 02d5 retz if (!AR0) return; + + ACC0 = 0; + AC0.M = AR0; // 0afa 8900 clr $ACC1 // 0afb 2734 lrs $AC1.M, @0x0034 // 0afc 0340 0001 andi $AC1.M, #0x0001 // 0afe 0b00 lris $AX1.H, #0x00 // 0aff 1f3f mrr $AX1.L, $AC1.M - // AX1.L = *0x0434 & 1; + + AX1.L = *0x0434 & 1; + // 0b00 268c lrs $AC0.M, @0xff8c // 0b01 248d lrs $AC0.L, @0xff8d // 0b02 8900 clr $ACC1 @@ -3577,7 +3658,9 @@ void 0af6_Decoder0x21_MoreStuff($AR0) { ACC0 = {8c,8d} + *0x0434 * 2 - (*0x0434 & 1) * 2 - 0b08 1c20 mrr $AR1, $AR0 + // 0b08 1c20 mrr $AR1, $AR0 + + AR1 = AR0; // 0b09 1fe0 mrr $AC1.M, $AR0 // 0b0a 0502 addis $ACC1, #0x02