From 41b104d0fbf1e8cf280ab594f1316d815afdd1d6 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 29 Sep 2023 07:48:49 -0300 Subject: [PATCH] Fix audio renderer compressor effect (#5742) * Delete DecibelToLinearExtended and fix Log10 function * Fix CopyBuffer and ClearBuffer * Change effect states from class to struct + formatting * Formatting * Make UpdateLowPassFilter readonly * More compressor fixes --- .../Dsp/Command/AuxiliaryBufferCommand.cs | 15 +++- .../Dsp/Command/BiquadFilterCommand.cs | 9 ++- .../Renderer/Dsp/Command/CommandList.cs | 4 +- .../Renderer/Dsp/Command/CompressorCommand.cs | 12 ++-- .../Renderer/Dsp/Command/DelayCommand.cs | 18 ++--- .../Dsp/Command/LimiterCommandVersion2.cs | 9 ++- .../Renderer/Dsp/Command/ReverbCommand.cs | 68 ++++++++++--------- .../Renderer/Dsp/FloatingPointHelper.cs | 18 +---- .../Renderer/Dsp/State/CompressorState.cs | 4 +- .../Renderer/Dsp/State/DelayState.cs | 4 +- .../Renderer/Dsp/State/LimiterState.cs | 2 +- .../Renderer/Dsp/State/Reverb3dState.cs | 2 +- .../Renderer/Dsp/State/ReverbState.cs | 4 +- 13 files changed, 92 insertions(+), 77 deletions(-) diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/AuxiliaryBufferCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/AuxiliaryBufferCommand.cs index 7ed32800f8..73d66dcf45 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/AuxiliaryBufferCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/AuxiliaryBufferCommand.cs @@ -31,9 +31,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public bool IsEffectEnabled { get; } - public AuxiliaryBufferCommand(uint bufferOffset, byte inputBufferOffset, byte outputBufferOffset, - ref AuxiliaryBufferAddresses sendBufferInfo, bool isEnabled, uint countMax, - CpuAddress outputBuffer, CpuAddress inputBuffer, uint updateCount, uint writeOffset, int nodeId) + public AuxiliaryBufferCommand( + uint bufferOffset, + byte inputBufferOffset, + byte outputBufferOffset, + ref AuxiliaryBufferAddresses sendBufferInfo, + bool isEnabled, + uint countMax, + CpuAddress outputBuffer, + CpuAddress inputBuffer, + uint updateCount, + uint writeOffset, + int nodeId) { Enabled = true; NodeId = nodeId; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs index f56dd70e3c..ac1e581f61 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs @@ -21,7 +21,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command private BiquadFilterParameter _parameter; - public BiquadFilterCommand(int baseIndex, ref BiquadFilterParameter filter, Memory biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, bool needInitialization, int nodeId) + public BiquadFilterCommand( + int baseIndex, + ref BiquadFilterParameter filter, + Memory biquadFilterStateMemory, + int inputBufferOffset, + int outputBufferOffset, + bool needInitialization, + int nodeId) { _parameter = filter; BiquadFilterState = biquadFilterStateMemory; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandList.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandList.cs index 19a9576f78..3fe106ddff 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandList.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandList.cs @@ -77,7 +77,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void ClearBuffer(int index) { - Unsafe.InitBlock((void*)GetBufferPointer(index), 0, SampleCount); + Unsafe.InitBlock((void*)GetBufferPointer(index), 0, SampleCount * sizeof(float)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -89,7 +89,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void CopyBuffer(int outputBufferIndex, int inputBufferIndex) { - Unsafe.CopyBlock((void*)GetBufferPointer(outputBufferIndex), (void*)GetBufferPointer(inputBufferIndex), SampleCount); + Unsafe.CopyBlock((void*)GetBufferPointer(outputBufferIndex), (void*)GetBufferPointer(inputBufferIndex), SampleCount * sizeof(float)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs index 01291852ea..1d5917bbe5 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs @@ -94,18 +94,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain); float y = FloatingPointHelper.Log10(newMean) * 10.0f; - float z = 0.0f; + float z = 1.0f; - bool unknown10OutOfRange = false; + bool unknown10OutOfRange = y >= state.Unknown10; if (newMean < 1.0e-10f) { - z = 1.0f; + y = -100.0f; - unknown10OutOfRange = state.Unknown10 < -100.0f; + unknown10OutOfRange = state.Unknown10 <= -100.0f; } - if (y >= state.Unknown10 || unknown10OutOfRange) + if (unknown10OutOfRange) { float tmpGain; @@ -118,7 +118,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command tmpGain = (y - state.Unknown10) * ((y - state.Unknown10) * -state.CompressorGainReduction); } - z = FloatingPointHelper.DecibelToLinearExtended(tmpGain); + z = FloatingPointHelper.DecibelToLinear(tmpGain); } float unknown4New = z; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs index 003806cf78..6fa3777f4e 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs @@ -88,7 +88,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); Matrix2x2 delayFeedback = new(delayFeedbackBaseGain, delayFeedbackCrossGain, - delayFeedbackCrossGain, delayFeedbackBaseGain); + delayFeedbackCrossGain, delayFeedbackBaseGain); for (int i = 0; i < sampleCount; i++) { @@ -125,9 +125,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); Matrix4x4 delayFeedback = new(delayFeedbackBaseGain, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, - delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, - delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, - 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain); + delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, + delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, + 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain); for (int i = 0; i < sampleCount; i++) @@ -172,11 +172,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); Matrix6x6 delayFeedback = new(delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, 0.0f, delayFeedbackCrossGain, 0.0f, - 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, - delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, feedbackGain, 0.0f, 0.0f, - delayFeedbackCrossGain, 0.0f, 0.0f, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, - 0.0f, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackBaseGain); + 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, + delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, feedbackGain, 0.0f, 0.0f, + delayFeedbackCrossGain, 0.0f, 0.0f, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, + 0.0f, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackBaseGain); for (int i = 0; i < sampleCount; i++) { diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs index 6820986707..f6e1654dd3 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs @@ -28,7 +28,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command private LimiterParameter _parameter; - public LimiterCommandVersion2(uint bufferOffset, LimiterParameter parameter, Memory state, Memory resultState, bool isEnabled, ulong workBuffer, int nodeId) + public LimiterCommandVersion2( + uint bufferOffset, + LimiterParameter parameter, + Memory state, + Memory resultState, + bool isEnabled, + ulong workBuffer, + int nodeId) { Enabled = true; NodeId = nodeId; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs index f494b30288..874eb8e8bc 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs @@ -79,53 +79,57 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ProcessReverbMono(ref ReverbState state, ReadOnlySpan outputBuffers, ReadOnlySpan inputBuffers, uint sampleCount) { - ProcessReverbGeneric(ref state, - outputBuffers, - inputBuffers, - sampleCount, - _outputEarlyIndicesTableMono, - _targetEarlyDelayLineIndicesTableMono, - _targetOutputFeedbackIndicesTableMono, - _outputIndicesTableMono); + ProcessReverbGeneric( + ref state, + outputBuffers, + inputBuffers, + sampleCount, + _outputEarlyIndicesTableMono, + _targetEarlyDelayLineIndicesTableMono, + _targetOutputFeedbackIndicesTableMono, + _outputIndicesTableMono); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ProcessReverbStereo(ref ReverbState state, ReadOnlySpan outputBuffers, ReadOnlySpan inputBuffers, uint sampleCount) { - ProcessReverbGeneric(ref state, - outputBuffers, - inputBuffers, - sampleCount, - _outputEarlyIndicesTableStereo, - _targetEarlyDelayLineIndicesTableStereo, - _targetOutputFeedbackIndicesTableStereo, - _outputIndicesTableStereo); + ProcessReverbGeneric( + ref state, + outputBuffers, + inputBuffers, + sampleCount, + _outputEarlyIndicesTableStereo, + _targetEarlyDelayLineIndicesTableStereo, + _targetOutputFeedbackIndicesTableStereo, + _outputIndicesTableStereo); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ProcessReverbQuadraphonic(ref ReverbState state, ReadOnlySpan outputBuffers, ReadOnlySpan inputBuffers, uint sampleCount) { - ProcessReverbGeneric(ref state, - outputBuffers, - inputBuffers, - sampleCount, - _outputEarlyIndicesTableQuadraphonic, - _targetEarlyDelayLineIndicesTableQuadraphonic, - _targetOutputFeedbackIndicesTableQuadraphonic, - _outputIndicesTableQuadraphonic); + ProcessReverbGeneric( + ref state, + outputBuffers, + inputBuffers, + sampleCount, + _outputEarlyIndicesTableQuadraphonic, + _targetEarlyDelayLineIndicesTableQuadraphonic, + _targetOutputFeedbackIndicesTableQuadraphonic, + _outputIndicesTableQuadraphonic); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ProcessReverbSurround(ref ReverbState state, ReadOnlySpan outputBuffers, ReadOnlySpan inputBuffers, uint sampleCount) { - ProcessReverbGeneric(ref state, - outputBuffers, - inputBuffers, - sampleCount, - _outputEarlyIndicesTableSurround, - _targetEarlyDelayLineIndicesTableSurround, - _targetOutputFeedbackIndicesTableSurround, - _outputIndicesTableSurround); + ProcessReverbGeneric( + ref state, + outputBuffers, + inputBuffers, + sampleCount, + _outputEarlyIndicesTableSurround, + _targetEarlyDelayLineIndicesTableSurround, + _targetOutputFeedbackIndicesTableSurround, + _outputIndicesTableSurround); } private unsafe void ProcessReverbGeneric(ref ReverbState state, ReadOnlySpan outputBuffers, ReadOnlySpan inputBuffers, uint sampleCount, ReadOnlySpan outputEarlyIndicesTable, ReadOnlySpan targetEarlyDelayLineIndicesTable, ReadOnlySpan targetOutputFeedbackIndicesTable, ReadOnlySpan outputIndicesTable) diff --git a/src/Ryujinx.Audio/Renderer/Dsp/FloatingPointHelper.cs b/src/Ryujinx.Audio/Renderer/Dsp/FloatingPointHelper.cs index b231dbb6aa..415e1c1958 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/FloatingPointHelper.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/FloatingPointHelper.cs @@ -52,7 +52,7 @@ namespace Ryujinx.Audio.Renderer.Dsp { // NOTE: Nintendo uses an approximation of log10, we don't. // As such, we support the same ranges as Nintendo to avoid unexpected behaviours. - return MathF.Pow(10, MathF.Max(x, 1.0e-10f)); + return MathF.Log10(MathF.Max(x, 1.0e-10f)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -62,7 +62,8 @@ namespace Ryujinx.Audio.Renderer.Dsp foreach (float input in inputs) { - res += (input * input); + float normInput = input * (1f / 32768f); + res += normInput * normInput; } res /= inputs.Length; @@ -81,19 +82,6 @@ namespace Ryujinx.Audio.Renderer.Dsp return MathF.Pow(10.0f, db / 20.0f); } - /// - /// Map decibel to linear in [0, 2] range. - /// - /// The decibel value to convert - /// Converted linear value in [0, 2] range - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float DecibelToLinearExtended(float db) - { - float tmp = MathF.Log2(DecibelToLinear(db)); - - return MathF.Truncate(tmp) + MathF.Pow(2.0f, tmp - MathF.Truncate(tmp)); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DegreesToRadians(float degrees) { diff --git a/src/Ryujinx.Audio/Renderer/Dsp/State/CompressorState.cs b/src/Ryujinx.Audio/Renderer/Dsp/State/CompressorState.cs index 76aff80725..9ee5732058 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/State/CompressorState.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/State/CompressorState.cs @@ -3,7 +3,7 @@ using Ryujinx.Audio.Renderer.Parameter.Effect; namespace Ryujinx.Audio.Renderer.Dsp.State { - public class CompressorState + public struct CompressorState { public ExponentialMovingAverage InputMovingAverage; public float Unknown4; @@ -45,7 +45,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State CompressorGainReduction = (1.0f - ratio) / Constants.ChannelCountMax; Unknown10 = threshold - 1.5f; Unknown14 = threshold + 1.5f; - OutputGain = FloatingPointHelper.DecibelToLinearExtended(parameter.OutputGain + makeupGain); + OutputGain = FloatingPointHelper.DecibelToLinear(parameter.OutputGain + makeupGain); } } } diff --git a/src/Ryujinx.Audio/Renderer/Dsp/State/DelayState.cs b/src/Ryujinx.Audio/Renderer/Dsp/State/DelayState.cs index c56fa078a4..17ad2a40dd 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/State/DelayState.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/State/DelayState.cs @@ -4,7 +4,7 @@ using System.Runtime.CompilerServices; namespace Ryujinx.Audio.Renderer.Dsp.State { - public class DelayState + public struct DelayState { public DelayLine[] DelayLines { get; } public float[] LowPassZ { get; set; } @@ -53,7 +53,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State LowPassBaseGain = 1.0f - LowPassFeedbackGain; } - public void UpdateLowPassFilter(ref float tempRawRef, uint channelCount) + public readonly void UpdateLowPassFilter(ref float tempRawRef, uint channelCount) { for (int i = 0; i < channelCount; i++) { diff --git a/src/Ryujinx.Audio/Renderer/Dsp/State/LimiterState.cs b/src/Ryujinx.Audio/Renderer/Dsp/State/LimiterState.cs index 80d1cb62e9..1388bfcef4 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/State/LimiterState.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/State/LimiterState.cs @@ -4,7 +4,7 @@ using System; namespace Ryujinx.Audio.Renderer.Dsp.State { - public class LimiterState + public struct LimiterState { public ExponentialMovingAverage[] DetectorAverage; public ExponentialMovingAverage[] CompressionGainAverage; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/State/Reverb3dState.cs b/src/Ryujinx.Audio/Renderer/Dsp/State/Reverb3dState.cs index 5056b750e3..e83e0d5fc8 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/State/Reverb3dState.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/State/Reverb3dState.cs @@ -4,7 +4,7 @@ using System; namespace Ryujinx.Audio.Renderer.Dsp.State { - public class Reverb3dState + public struct Reverb3dState { private readonly float[] _fdnDelayMinTimes = new float[4] { 5.0f, 6.0f, 13.0f, 14.0f }; private readonly float[] _fdnDelayMaxTimes = new float[4] { 45.704f, 82.782f, 149.94f, 271.58f }; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/State/ReverbState.cs b/src/Ryujinx.Audio/Renderer/Dsp/State/ReverbState.cs index 2f574f4758..f1927b7188 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/State/ReverbState.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/State/ReverbState.cs @@ -5,7 +5,7 @@ using System; namespace Ryujinx.Audio.Renderer.Dsp.State { - public class ReverbState + public struct ReverbState { private static readonly float[] _fdnDelayTimes = new float[20] { @@ -54,7 +54,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State // Room 0.70f, 0.68f, 0.70f, 0.68f, 0.70f, 0.68f, 0.70f, 0.68f, 0.68f, 0.68f, // Chamber - 0.70f, 0.68f, 0.70f, 0.68f, 0.70f, 0.68f, 0.68f, 0.68f, 0.68f, 0.68f, + 0.70f, 0.68f, 0.70f, 0.68f, 0.70f, 0.68f, 0.68f, 0.68f, 0.68f, 0.68f, // Hall 0.50f, 0.70f, 0.70f, 0.68f, 0.50f, 0.68f, 0.68f, 0.70f, 0.68f, 0.00f, // Cathedral