From 4da334c5622e4e6c0a3aad336575451c79ee872d Mon Sep 17 00:00:00 2001 From: hrydgard Date: Mon, 29 Jun 2009 21:24:17 +0000 Subject: [PATCH] DSPHLE: Improve AFC voice decoding. Still a bit crappy but much better :) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3605 8ced0084-cf51-0410-be5f-012b33b47a6e --- .../Src/UCodes/UCode_Zelda_ADPCM.cpp | 6 +- .../Src/UCodes/UCode_Zelda_Voice.cpp | 182 ++++++++---------- 2 files changed, 82 insertions(+), 106 deletions(-) diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.cpp index a3160f3c79..2bacf5a4a5 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda_ADPCM.cpp @@ -30,7 +30,6 @@ void AFCdecodebuffer(const s16 *coef, const char *input, signed short *out, shor // First 2 nibbles are ADPCM scale etc. short delta = 1 << (((*src) >> 4) & 0xf); short idx = (*src) & 0xf; - src++; if (type == 9) @@ -91,7 +90,6 @@ void AFCdecodebuffer(const s16 *coef, const char *input, signed short *out, shor hist2 = hist; hist = (short)sample; } - - *histp=hist; - *hist2p=hist2; + *histp = hist; + *hist2p = hist2; } 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 3b91b740b4..8e87b0de19 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,64 +23,6 @@ #include "../main.h" #include "Mixer.h" - -class CResampler -{ -public: - CResampler(short* samples, int num_stereo_samples, int core_sample_rate) - : m_mode(1) - , m_queueSize(0) - { - int PV1l=0,PV2l=0,PV3l=0,PV4l=0; - int acc=0; - - while (num_stereo_samples) - { - acc += core_sample_rate; - while (num_stereo_samples && (acc >= 48000)) - { - PV4l=PV3l; - PV3l=PV2l; - PV2l=PV1l; - PV1l=*(samples++); //32bit processing - num_stereo_samples--; - acc-=48000; - } - - // defaults to nearest - s32 DataL = PV1l; - - if (m_mode == 1) { //linear - DataL = PV1l + ((PV2l - PV1l)*acc)/48000; - } - else if (m_mode == 2) {//cubic - s32 a0l = PV1l - PV2l - PV4l + PV3l; - s32 a1l = PV4l - PV3l - a0l; - s32 a2l = PV1l - PV4l; - s32 a3l = PV2l; - - s32 t0l = ((a0l )*acc)/48000; - s32 t1l = ((t0l+a1l)*acc)/48000; - s32 t2l = ((t1l+a2l)*acc)/48000; - s32 t3l = ((t2l+a3l)); - - DataL = t3l; - } - - int l = DataL; - if (l < -32767) l = -32767; - if (l > 32767) l = 32767; - sample_queue.push(l); - m_queueSize += 1; - } - } - - FixedSizeQueue sample_queue; - int m_queueSize; - int m_mode; -}; - - void CUCode_Zelda::ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB) { u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr); @@ -117,6 +59,7 @@ void CUCode_Zelda::MixAddVoice_PCM16(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); + u32 pos[2] = {0, 0}; int i = 0; @@ -180,10 +123,15 @@ _lRestart: PB.RemLength -= pos[1]; PB.CurAddr += pos[1] << 1; + // There should be a position fraction as well. } void CUCode_Zelda::MixAddVoice_AFC(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); + // initialize "decoder" if the sample is played the first time if (PB.NeedsReset != 0) { @@ -203,20 +151,16 @@ 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; } if (PB.KeyOff != 0) // 0747 early out... i dunno if this can happen because we filter it above return; - u32 Addr = PB.CurAddr; - u32 NumberOfSamples = PB.RemLength; - // round upwards how many samples we need to copy, 0759 - NumberOfSamples = (NumberOfSamples + 0xf) >> 4; // i think the lower 4 are the fraction - u32 frac = NumberOfSamples & 0xF; + // u32 frac = NumberOfSamples & 0xF; + // NumberOfSamples = (NumberOfSamples + 0xf) >> 4; // i think the lower 4 are the fraction - u8 inBuffer[9]; - short outbuf[16]; u32 sampleCount = 0; u8 *source; @@ -231,59 +175,93 @@ void CUCode_Zelda::MixAddVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size) // 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. - - while (NumberOfSamples > 0) + +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. + PB.RestartPos = PB.LoopStartPos; + PB.RemLength = PB.Length - PB.RestartPos; + PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1); +// pos[1] = 0; pos[0] = 0; + } + } + + short outbuf[16] = {0}; + + u16 prev_yn1 = PB.YN1; + u16 prev_yn2 = PB.YN2; + u32 prev_addr = PB.CurAddr; + + // Prefill the decode buffer. + AFCdecodebuffer(m_AFCCoefTable, (char*)(source + PB.CurAddr), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, 9); + PB.CurAddr += 9; + + s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 32; + s64 delta = ratio; // 0x100000000ULL; + while (sampleCount < _Size) { - for (int i = 0; i < 9; i++) - { - // inBuffer[i] = g_dspInitialize.pARAM_Read_U8(ARAMAddr); - inBuffer[i] = source[Addr]; - Addr++; - } + int SamplePosition = TrueSamplePosition >> 32; + _Buffer[sampleCount] = outbuf[SamplePosition & 15]; - AFCdecodebuffer(m_AFCCoefTable, (char*)inBuffer, outbuf, (short*)&PB.YN2, (short*)&PB.YN1, 9); - CResampler Sampler(outbuf, 16, 48000); + sampleCount++; + TrueSamplePosition += delta; - while (Sampler.m_queueSize > 0) - { - int sample = Sampler.sample_queue.front(); - Sampler.sample_queue.pop(); - Sampler.m_queueSize -= 1; + int TargetPosition = TrueSamplePosition >> 32; - // templbuffer[sampleCount] += sample; - // temprbuffer[sampleCount] += sample; - _Buffer[sampleCount] = sample; - sampleCount++; + // Decode forwards... + while (SamplePosition < TargetPosition) + { + SamplePosition++; + PB.RemLength--; + if (PB.RemLength == 0) + { + PB.ReachedEnd = 1; + goto restart; + } - if (sampleCount > _Size) - break; - } + // Need new samples! + if ((SamplePosition & 15) == 0) { + prev_yn1 = PB.YN1; + prev_yn2 = PB.YN2; + prev_addr = PB.CurAddr; - if (sampleCount > _Size) - break; - - NumberOfSamples--; + AFCdecodebuffer(m_AFCCoefTable, (char*)(source + PB.CurAddr), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, 9); + PB.CurAddr += 9; + } + } } - if (NumberOfSamples == 0) - { - PB.KeyOff = 1; // we are done ?? - } + // Here we should back off to the previous addr/yn1/yn2, since we didn't consume the full last block. + // We'll have to re-decode it the next time around. + // if (SamplePosition & 15) { + PB.YN2 = prev_yn2; + PB.YN1 = prev_yn1; + PB.CurAddr = prev_addr; + // } - // write back - NumberOfSamples = (NumberOfSamples << 4); // missing fraction - - PB.CurAddr = Addr; - PB.RemLength = NumberOfSamples; + PB.NeedsReset = 0; + // write back + // NumberOfSamples = (NumberOfSamples << 4) | frac; // missing fraction // 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] - // end of block (Zelda 03b2) - PB.NeedsReset = 0; } void CUCode_Zelda::MixAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size)