0
0
Fork 0

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
This commit is contained in:
gdkchan 2023-09-29 07:48:49 -03:00 committed by GitHub
parent bc44b85b0b
commit 41b104d0fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 92 additions and 77 deletions

View file

@ -31,9 +31,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public bool IsEffectEnabled { get; } public bool IsEffectEnabled { get; }
public AuxiliaryBufferCommand(uint bufferOffset, byte inputBufferOffset, byte outputBufferOffset, public AuxiliaryBufferCommand(
ref AuxiliaryBufferAddresses sendBufferInfo, bool isEnabled, uint countMax, uint bufferOffset,
CpuAddress outputBuffer, CpuAddress inputBuffer, uint updateCount, uint writeOffset, int nodeId) byte inputBufferOffset,
byte outputBufferOffset,
ref AuxiliaryBufferAddresses sendBufferInfo,
bool isEnabled,
uint countMax,
CpuAddress outputBuffer,
CpuAddress inputBuffer,
uint updateCount,
uint writeOffset,
int nodeId)
{ {
Enabled = true; Enabled = true;
NodeId = nodeId; NodeId = nodeId;

View file

@ -21,7 +21,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
private BiquadFilterParameter _parameter; private BiquadFilterParameter _parameter;
public BiquadFilterCommand(int baseIndex, ref BiquadFilterParameter filter, Memory<BiquadFilterState> biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, bool needInitialization, int nodeId) public BiquadFilterCommand(
int baseIndex,
ref BiquadFilterParameter filter,
Memory<BiquadFilterState> biquadFilterStateMemory,
int inputBufferOffset,
int outputBufferOffset,
bool needInitialization,
int nodeId)
{ {
_parameter = filter; _parameter = filter;
BiquadFilterState = biquadFilterStateMemory; BiquadFilterState = biquadFilterStateMemory;

View file

@ -77,7 +77,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void ClearBuffer(int index) 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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -89,7 +89,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void CopyBuffer(int outputBufferIndex, int inputBufferIndex) 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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

View file

@ -94,18 +94,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain); float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain);
float y = FloatingPointHelper.Log10(newMean) * 10.0f; 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) 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; float tmpGain;
@ -118,7 +118,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
tmpGain = (y - state.Unknown10) * ((y - state.Unknown10) * -state.CompressorGainReduction); tmpGain = (y - state.Unknown10) * ((y - state.Unknown10) * -state.CompressorGainReduction);
} }
z = FloatingPointHelper.DecibelToLinearExtended(tmpGain); z = FloatingPointHelper.DecibelToLinear(tmpGain);
} }
float unknown4New = z; float unknown4New = z;

View file

@ -88,7 +88,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
Matrix2x2 delayFeedback = new(delayFeedbackBaseGain, delayFeedbackCrossGain, Matrix2x2 delayFeedback = new(delayFeedbackBaseGain, delayFeedbackCrossGain,
delayFeedbackCrossGain, delayFeedbackBaseGain); delayFeedbackCrossGain, delayFeedbackBaseGain);
for (int i = 0; i < sampleCount; i++) for (int i = 0; i < sampleCount; i++)
{ {
@ -125,9 +125,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
Matrix4x4 delayFeedback = new(delayFeedbackBaseGain, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, Matrix4x4 delayFeedback = new(delayFeedbackBaseGain, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f,
delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain,
delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain,
0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain); 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain);
for (int i = 0; i < sampleCount; i++) for (int i = 0; i < sampleCount; i++)
@ -172,11 +172,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
Matrix6x6 delayFeedback = new(delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, 0.0f, delayFeedbackCrossGain, 0.0f, Matrix6x6 delayFeedback = new(delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, 0.0f, delayFeedbackCrossGain, 0.0f,
0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain,
delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, feedbackGain, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, feedbackGain, 0.0f, 0.0f,
delayFeedbackCrossGain, 0.0f, 0.0f, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, 0.0f, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain,
0.0f, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackBaseGain); 0.0f, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackBaseGain);
for (int i = 0; i < sampleCount; i++) for (int i = 0; i < sampleCount; i++)
{ {

View file

@ -28,7 +28,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
private LimiterParameter _parameter; private LimiterParameter _parameter;
public LimiterCommandVersion2(uint bufferOffset, LimiterParameter parameter, Memory<LimiterState> state, Memory<EffectResultState> resultState, bool isEnabled, ulong workBuffer, int nodeId) public LimiterCommandVersion2(
uint bufferOffset,
LimiterParameter parameter,
Memory<LimiterState> state,
Memory<EffectResultState> resultState,
bool isEnabled,
ulong workBuffer,
int nodeId)
{ {
Enabled = true; Enabled = true;
NodeId = nodeId; NodeId = nodeId;

View file

@ -79,53 +79,57 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessReverbMono(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount) private void ProcessReverbMono(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
{ {
ProcessReverbGeneric(ref state, ProcessReverbGeneric(
outputBuffers, ref state,
inputBuffers, outputBuffers,
sampleCount, inputBuffers,
_outputEarlyIndicesTableMono, sampleCount,
_targetEarlyDelayLineIndicesTableMono, _outputEarlyIndicesTableMono,
_targetOutputFeedbackIndicesTableMono, _targetEarlyDelayLineIndicesTableMono,
_outputIndicesTableMono); _targetOutputFeedbackIndicesTableMono,
_outputIndicesTableMono);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessReverbStereo(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount) private void ProcessReverbStereo(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
{ {
ProcessReverbGeneric(ref state, ProcessReverbGeneric(
outputBuffers, ref state,
inputBuffers, outputBuffers,
sampleCount, inputBuffers,
_outputEarlyIndicesTableStereo, sampleCount,
_targetEarlyDelayLineIndicesTableStereo, _outputEarlyIndicesTableStereo,
_targetOutputFeedbackIndicesTableStereo, _targetEarlyDelayLineIndicesTableStereo,
_outputIndicesTableStereo); _targetOutputFeedbackIndicesTableStereo,
_outputIndicesTableStereo);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessReverbQuadraphonic(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount) private void ProcessReverbQuadraphonic(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
{ {
ProcessReverbGeneric(ref state, ProcessReverbGeneric(
outputBuffers, ref state,
inputBuffers, outputBuffers,
sampleCount, inputBuffers,
_outputEarlyIndicesTableQuadraphonic, sampleCount,
_targetEarlyDelayLineIndicesTableQuadraphonic, _outputEarlyIndicesTableQuadraphonic,
_targetOutputFeedbackIndicesTableQuadraphonic, _targetEarlyDelayLineIndicesTableQuadraphonic,
_outputIndicesTableQuadraphonic); _targetOutputFeedbackIndicesTableQuadraphonic,
_outputIndicesTableQuadraphonic);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessReverbSurround(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount) private void ProcessReverbSurround(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
{ {
ProcessReverbGeneric(ref state, ProcessReverbGeneric(
outputBuffers, ref state,
inputBuffers, outputBuffers,
sampleCount, inputBuffers,
_outputEarlyIndicesTableSurround, sampleCount,
_targetEarlyDelayLineIndicesTableSurround, _outputEarlyIndicesTableSurround,
_targetOutputFeedbackIndicesTableSurround, _targetEarlyDelayLineIndicesTableSurround,
_outputIndicesTableSurround); _targetOutputFeedbackIndicesTableSurround,
_outputIndicesTableSurround);
} }
private unsafe void ProcessReverbGeneric(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount, ReadOnlySpan<int> outputEarlyIndicesTable, ReadOnlySpan<int> targetEarlyDelayLineIndicesTable, ReadOnlySpan<int> targetOutputFeedbackIndicesTable, ReadOnlySpan<int> outputIndicesTable) private unsafe void ProcessReverbGeneric(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount, ReadOnlySpan<int> outputEarlyIndicesTable, ReadOnlySpan<int> targetEarlyDelayLineIndicesTable, ReadOnlySpan<int> targetOutputFeedbackIndicesTable, ReadOnlySpan<int> outputIndicesTable)

View file

@ -52,7 +52,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
{ {
// NOTE: Nintendo uses an approximation of log10, we don't. // NOTE: Nintendo uses an approximation of log10, we don't.
// As such, we support the same ranges as Nintendo to avoid unexpected behaviours. // 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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -62,7 +62,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
foreach (float input in inputs) foreach (float input in inputs)
{ {
res += (input * input); float normInput = input * (1f / 32768f);
res += normInput * normInput;
} }
res /= inputs.Length; res /= inputs.Length;
@ -81,19 +82,6 @@ namespace Ryujinx.Audio.Renderer.Dsp
return MathF.Pow(10.0f, db / 20.0f); return MathF.Pow(10.0f, db / 20.0f);
} }
/// <summary>
/// Map decibel to linear in [0, 2] range.
/// </summary>
/// <param name="db">The decibel value to convert</param>
/// <returns>Converted linear value in [0, 2] range</returns>
[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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float DegreesToRadians(float degrees) public static float DegreesToRadians(float degrees)
{ {

View file

@ -3,7 +3,7 @@ using Ryujinx.Audio.Renderer.Parameter.Effect;
namespace Ryujinx.Audio.Renderer.Dsp.State namespace Ryujinx.Audio.Renderer.Dsp.State
{ {
public class CompressorState public struct CompressorState
{ {
public ExponentialMovingAverage InputMovingAverage; public ExponentialMovingAverage InputMovingAverage;
public float Unknown4; public float Unknown4;
@ -45,7 +45,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
CompressorGainReduction = (1.0f - ratio) / Constants.ChannelCountMax; CompressorGainReduction = (1.0f - ratio) / Constants.ChannelCountMax;
Unknown10 = threshold - 1.5f; Unknown10 = threshold - 1.5f;
Unknown14 = threshold + 1.5f; Unknown14 = threshold + 1.5f;
OutputGain = FloatingPointHelper.DecibelToLinearExtended(parameter.OutputGain + makeupGain); OutputGain = FloatingPointHelper.DecibelToLinear(parameter.OutputGain + makeupGain);
} }
} }
} }

View file

@ -4,7 +4,7 @@ using System.Runtime.CompilerServices;
namespace Ryujinx.Audio.Renderer.Dsp.State namespace Ryujinx.Audio.Renderer.Dsp.State
{ {
public class DelayState public struct DelayState
{ {
public DelayLine[] DelayLines { get; } public DelayLine[] DelayLines { get; }
public float[] LowPassZ { get; set; } public float[] LowPassZ { get; set; }
@ -53,7 +53,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
LowPassBaseGain = 1.0f - LowPassFeedbackGain; 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++) for (int i = 0; i < channelCount; i++)
{ {

View file

@ -4,7 +4,7 @@ using System;
namespace Ryujinx.Audio.Renderer.Dsp.State namespace Ryujinx.Audio.Renderer.Dsp.State
{ {
public class LimiterState public struct LimiterState
{ {
public ExponentialMovingAverage[] DetectorAverage; public ExponentialMovingAverage[] DetectorAverage;
public ExponentialMovingAverage[] CompressionGainAverage; public ExponentialMovingAverage[] CompressionGainAverage;

View file

@ -4,7 +4,7 @@ using System;
namespace Ryujinx.Audio.Renderer.Dsp.State 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[] _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 }; private readonly float[] _fdnDelayMaxTimes = new float[4] { 45.704f, 82.782f, 149.94f, 271.58f };

View file

@ -5,7 +5,7 @@ using System;
namespace Ryujinx.Audio.Renderer.Dsp.State namespace Ryujinx.Audio.Renderer.Dsp.State
{ {
public class ReverbState public struct ReverbState
{ {
private static readonly float[] _fdnDelayTimes = new float[20] private static readonly float[] _fdnDelayTimes = new float[20]
{ {