From 7e9011673b1593aa2b318e312e0b31379e2e57e4 Mon Sep 17 00:00:00 2001
From: riperiperi <rhy3756547@hotmail.com>
Date: Thu, 17 Feb 2022 19:19:29 +0000
Subject: [PATCH] Use a basic cubic interpolation for the audren upsampler
 (#3129)

Before, it was selecting nearest neighbour, which sounded terrible. This is likely temporary til the upsampling algorithm used by the switch is reversed.

Fixes bad audio in Skyward Sword HD.
---
 Ryujinx.Audio/Renderer/Dsp/ResamplerHelper.cs | 33 ++++++++++++++++---
 1 file changed, 28 insertions(+), 5 deletions(-)

diff --git a/Ryujinx.Audio/Renderer/Dsp/ResamplerHelper.cs b/Ryujinx.Audio/Renderer/Dsp/ResamplerHelper.cs
index d40da412bf..d9e4c824dc 100644
--- a/Ryujinx.Audio/Renderer/Dsp/ResamplerHelper.cs
+++ b/Ryujinx.Audio/Renderer/Dsp/ResamplerHelper.cs
@@ -600,19 +600,42 @@ namespace Ryujinx.Audio.Renderer.Dsp
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static void ResampleForUpsampler(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, float ratio, ref float fraction, int sampleCount)
         {
-            // TODO: use a bandwidth filter to have better resampling.
+            // Currently a simple cubic interpolation, assuming duplicated values at edges.
+            // TODO: Discover and use algorithm that the switch uses.
+
             int inputBufferIndex = 0;
+            int maxIndex = inputBuffer.Length - 1;
+            int cubicEnd = inputBuffer.Length - 3;
 
             for (int i = 0; i < sampleCount; i++)
             {
-                float outputData = inputBuffer[inputBufferIndex];
+                float s0, s1, s2, s3;
 
-                if (fraction > 1.0f)
+                s1 = inputBuffer[inputBufferIndex];
+
+                if (inputBufferIndex == 0 || inputBufferIndex > cubicEnd)
                 {
-                    outputData = inputBuffer[inputBufferIndex + 1];
+                    // Clamp interplation values at the ends of the input buffer.
+                    s0 = inputBuffer[Math.Max(0, inputBufferIndex - 1)];
+                    s2 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 1)];
+                    s3 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 2)];
+                }
+                else
+                {
+                    s0 = inputBuffer[inputBufferIndex - 1];
+                    s2 = inputBuffer[inputBufferIndex + 1];
+                    s3 = inputBuffer[inputBufferIndex + 2];
                 }
 
-                outputBuffer[i] = outputData;
+                float a = s3 - s2 - s0 + s1;
+                float b = s0 - s1 - a;
+                float c = s2 - s0;
+                float d = s1;
+
+                float f2 = fraction * fraction;
+                float f3 = f2 * fraction;
+
+                outputBuffer[i] = a * f3 + b * f2 + c * fraction + d;
 
                 fraction += ratio;
                 inputBufferIndex += (int)MathF.Truncate(fraction);