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 outputBuffer, ReadOnlySpan 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);