diff --git a/Source/Plugins/Plugin_DSP_HLE/Plugin_DSP_HLE.vcproj b/Source/Plugins/Plugin_DSP_HLE/Plugin_DSP_HLE.vcproj
index dc1a5a7261..45eca9c5c3 100644
--- a/Source/Plugins/Plugin_DSP_HLE/Plugin_DSP_HLE.vcproj
+++ b/Source/Plugins/Plugin_DSP_HLE/Plugin_DSP_HLE.vcproj
@@ -1,7 +1,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -809,22 +813,6 @@
UsePrecompiledHeader="1"
/>
-
-
-
-
-
-
@@ -833,6 +821,14 @@
UsePrecompiledHeader="1"
/>
+
+
+
@@ -841,6 +837,14 @@
UsePrecompiledHeader="1"
/>
+
+
+
diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/SConscript b/Source/Plugins/Plugin_DSP_HLE/Src/SConscript
index 3d75c9e224..3e6f5a9683 100644
--- a/Source/Plugins/Plugin_DSP_HLE/Src/SConscript
+++ b/Source/Plugins/Plugin_DSP_HLE/Src/SConscript
@@ -23,6 +23,7 @@ files = [
'UCodes/UCode_Zelda.cpp',
'UCodes/UCode_Zelda_ADPCM.cpp',
'UCodes/UCode_Zelda_Voice.cpp',
+ 'UCodes/UCode_Zelda_Synth.cpp',
]
dspenv = env.Clone()
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 2989b4ae2c..0749c4d69c 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
@@ -25,19 +25,75 @@
void CUCode_Zelda::MixAddSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
- int mask = PB.Format ? 3 : 1;
-
- for (int i = 0; i < _Size; i++)
- {
- s16 sample = (i & mask) ? 0xc000 : 0x4000;
-
- _Buffer[i++] = (s32)sample;
- }
+ 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;
+
+ u32 pos[2] = {0, 0};
+ int i = 0;
+
+ if (PB.KeyOff != 0)
+ return;
+
+ if (PB.NeedsReset)
+ {
+ PB.RemLength = PB.Length - PB.RestartPos;
+ PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
+ PB.ReachedEnd = 0;
+ }
+
+_lRestart:
+ if (PB.ReachedEnd)
+ {
+ PB.ReachedEnd = 0;
+
+ if (PB.RepeatMode == 0)
+ {
+ PB.KeyOff = 1;
+ PB.RemLength = 0;
+ PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1) + PB.Length;
+ return;
+ }
+ else
+ {
+ PB.RestartPos = PB.LoopStartPos;
+ PB.RemLength = PB.Length - PB.RestartPos;
+ PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
+ pos[1] = 0; pos[0] = 0;
+ }
+ }
+
+ for (; i < _Size;)
+ {
+ s16 sample = ((pos[1] & mask) == mask) ? 0xc000 : 0x4000;
+
+ _Buffer[i++] = (s32)sample;
+
+ (*(u64*)&pos) += ratio;
+ if ((pos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length)
+ {
+ PB.ReachedEnd = 1;
+ goto _lRestart;
+ }
+ }
+
+ if (PB.RemLength < pos[1])
+ {
+ PB.RemLength = 0;
+ PB.ReachedEnd = 1;
+ }
+ else
+ 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;
}
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 dd874708ee..bce5f0e3f2 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
@@ -281,20 +281,22 @@ void CUCode_Zelda::MixAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBu
{
switch (PB.Format)
{
-
// Synthesized sounds
- case 0x0000:
- case 0x0001: // Used for "Denied" sound in Zelda
- //MixAddSynth_Waveform(PB, m_TempBuffer, _Size);
- break;
+ 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);
+ break;
case 0x0006:
- //MixAddSynth_Waveform(PB, m_TempBuffer, _Size);
- break;
+ WARN_LOG(DSPHLE, "Synthesizing 0x0006 (constant sound)");
+ MixAddSynth_Constant(PB, m_TempBuffer, _Size);
+ break;
- // These are more "synth" formats - square wave, saw wave etc.
+ // These are more "synth" formats - square wave, saw wave etc.
case 0x0002:
- return;
+ WARN_LOG(DSPHLE, "Synthesizing 0x0002");
+ break;
// AFC formats
diff --git a/docs/DSP/DSP_UC_Zelda.txt b/docs/DSP/DSP_UC_Zelda.txt
index 1a62b2a1c4..066b6e46d2 100644
--- a/docs/DSP/DSP_UC_Zelda.txt
+++ b/docs/DSP/DSP_UC_Zelda.txt
@@ -2915,37 +2915,51 @@ void 08b2_Unk() {
08b2 1401 lsl $ACC0, #1 // t = PB.RatioFrac * 2
// Set up sound buffers
- 08b3 009b c000 lri $AX1.H, #0xc000 // a = 0xc000
- 08b5 0099 4000 lri $AX1.L, #0x4000 // b = 0x4000
+ //08b3 009b c000 lri $AX1.H, #0xc000
+ //08b5 0099 4000 lri $AX1.L, #0x4000
- 08b7 1150 08bf bloopi #0x50, 0x08bf
- // for(int i = 0; i < 80; i++) {
- 08b9 02c0 0001 andcf $AC0.M, #0x0001
- 08bb 027c iflnz
- 08bc 1b1b srri @$AR0, $AX1.H
- 08bd 027d iflz
- 08be 1b19 srri @$AR0, $AX1.L
- 08bf 4800 addax $ACC0, $AX0.L
- // }
- 08c0 147f lsr $ACC0, #-1
+ //08b7 1150 08bf bloopi #0x50, 0x08bf
+ for(int i = 0; i < 80; i++) {
+ //08b9 02c0 0001 andcf $AC0.M, #0x0001
+ //08bb 027c iflnz
+ // 08bc 1b1b srri @$AR0, $AX1.H
+ //08bd 027d iflz
+ // 08be 1b19 srri @$AR0, $AX1.L
+ if(($AC0.M & 1) == 1)
+ *$AR0++ = 0x4000;
+ else
+ *$AR0++ = 0xc000;
+
+ 08bf 4800 addax $ACC0, $AX0.L // t += PB.RatioInt
+ }
+ 08c0 147f lsr $ACC0, #-1 // t /= 2
08c1 02df ret
}
void 08c2_Unk() {
- 08c2 1402 lsl $ACC0, #2
- 08c3 8900 clr $ACC1
- 08c4 1fb8 mrr $AC1.L, $AX0.L
- 08c5 1501 lsl $ACC1, #1
+ 08c2 1402 lsl $ACC0, #2 // t = PB.RatioFrac * 4
+ 08c3 8900 clr $ACC1 // ACC1 = 0
+ 08c4 1fb8 mrr $AC1.L, $AX0.L // AC1.L = PB.RatioInt
+ 08c5 1501 lsl $ACC1, #1 // ACC1 *= 2
08c6 009b c000 lri $AX1.H, #0xc000
08c8 0099 4000 lri $AX1.L, #0x4000
- 08ca 1150 08d2 bloopi #0x50, 0x08d2
- 08cc 02c0 0003 andcf $AC0.M, #0x0003
- 08ce 027c iflnz
- 08cf 1b1b srri @$AR0, $AX1.H
- 08d0 027d iflz
- 08d1 1b19 srri @$AR0, $AX1.L
- 08d2 4c00 add $ACC0, $AC1.L
- 08d3 147e lsr $ACC0, #-2
+ //08ca 1150 08d2 bloopi #0x50, 0x08d2
+ for(int i = 0; i < 80; i++) {
+ //08cc 02c0 0003 andcf $AC0.M, #0x0003
+ //08ce 027c iflnz
+ // 08cf 1b1b srri @$AR0, $AX1.H
+ //08d0 027d iflz
+ // 08d1 1b19 srri @$AR0, $AX1.L
+ //08d2 4c00 add $ACC0, $AC1.L
+
+ if(($AC0.M & 3) == 3)
+ *$AR0++ = 0x4000;
+ else
+ *$AR0++ = 0xc000;
+
+ t += (PB.RatioInt * 2);
+ }
+ 08d3 147e lsr $ACC0, #-2 // t /= 4
08d4 02df ret
}