aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2024-10-01 07:30:57 -0300
committerGitHub <noreply@github.com>2024-10-01 11:30:57 +0100
commita2c003501371463fd1f98d2e5a7602ae19c21d7c (patch)
tree3943fb3d7396e4db9bb9758787533ede381d2f2e
parent7d158acc3b5826a08941d6e8d50d3a3897021bcd (diff)
Update audio renderer to REV13: Add support for compressor statistics and volume reset (#7372)HEAD1.1.1403master
* Update audio renderer to REV13: Add support for compressor statistics and volume reset * XML docs * Disable stats reset * Wrong comment * Fix more XML docs * PR feedback
-rw-r--r--src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs45
-rw-r--r--src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs46
-rw-r--r--src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs48
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs11
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorStatistics.cs38
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs5
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs9
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs9
-rw-r--r--src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs19
-rw-r--r--src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs13
-rw-r--r--src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs16
-rw-r--r--src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs56
-rw-r--r--src/Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs13
-rw-r--r--src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs9
-rw-r--r--src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs7
-rw-r--r--src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion1.cs6
-rw-r--r--src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs6
-rw-r--r--src/Ryujinx.Horizon/Sdk/Audio/AudioResult.cs1
-rw-r--r--src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs42
-rw-r--r--src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs41
20 files changed, 352 insertions, 88 deletions
diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs
index 09f415d2..33f61e6a 100644
--- a/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs
+++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs
@@ -1,9 +1,11 @@
using Ryujinx.Audio.Renderer.Dsp.Effect;
using Ryujinx.Audio.Renderer.Dsp.State;
+using Ryujinx.Audio.Renderer.Parameter;
using Ryujinx.Audio.Renderer.Parameter.Effect;
using Ryujinx.Audio.Renderer.Server.Effect;
using System;
using System.Diagnostics;
+using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Dsp.Command
{
@@ -21,18 +23,20 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CompressorParameter Parameter => _parameter;
public Memory<CompressorState> State { get; }
+ public Memory<EffectResultState> ResultState { get; }
public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; }
public bool IsEffectEnabled { get; }
private CompressorParameter _parameter;
- public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
+ public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, Memory<EffectResultState> resultState, bool isEnabled, int nodeId)
{
Enabled = true;
NodeId = nodeId;
_parameter = parameter;
State = state;
+ ResultState = resultState;
IsEffectEnabled = isEnabled;
@@ -71,9 +75,16 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (IsEffectEnabled && _parameter.IsChannelCountValid())
{
- Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
- Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
- Span<float> channelInput = stackalloc float[Parameter.ChannelCount];
+ if (!ResultState.IsEmpty && _parameter.StatisticsReset)
+ {
+ ref CompressorStatistics statistics = ref MemoryMarshal.Cast<byte, CompressorStatistics>(ResultState.Span[0].SpecificData)[0];
+
+ statistics.Reset(_parameter.ChannelCount);
+ }
+
+ Span<IntPtr> inputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
+ Span<IntPtr> outputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
+ Span<float> channelInput = stackalloc float[_parameter.ChannelCount];
ExponentialMovingAverage inputMovingAverage = state.InputMovingAverage;
float unknown4 = state.Unknown4;
ExponentialMovingAverage compressionGainAverage = state.CompressionGainAverage;
@@ -92,7 +103,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
channelInput[channelIndex] = *((float*)inputBuffers[channelIndex] + sampleIndex);
}
- float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain);
+ float mean = FloatingPointHelper.MeanSquare(channelInput);
+ float newMean = inputMovingAverage.Update(mean, _parameter.InputGain);
float y = FloatingPointHelper.Log10(newMean) * 10.0f;
float z = 1.0f;
@@ -111,7 +123,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (y >= state.Unknown14)
{
- tmpGain = ((1.0f / Parameter.Ratio) - 1.0f) * (y - Parameter.Threshold);
+ tmpGain = ((1.0f / _parameter.Ratio) - 1.0f) * (y - _parameter.Threshold);
}
else
{
@@ -126,7 +138,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if ((unknown4 - z) <= 0.08f)
{
- compressionEmaAlpha = Parameter.ReleaseCoefficient;
+ compressionEmaAlpha = _parameter.ReleaseCoefficient;
if ((unknown4 - z) >= -0.08f)
{
@@ -140,18 +152,31 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
else
{
- compressionEmaAlpha = Parameter.AttackCoefficient;
+ compressionEmaAlpha = _parameter.AttackCoefficient;
}
float compressionGain = compressionGainAverage.Update(z, compressionEmaAlpha);
- for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
+ for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
{
*((float*)outputBuffers[channelIndex] + sampleIndex) = channelInput[channelIndex] * compressionGain * state.OutputGain;
}
unknown4 = unknown4New;
previousCompressionEmaAlpha = compressionEmaAlpha;
+
+ if (!ResultState.IsEmpty)
+ {
+ ref CompressorStatistics statistics = ref MemoryMarshal.Cast<byte, CompressorStatistics>(ResultState.Span[0].SpecificData)[0];
+
+ statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain);
+ statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean);
+
+ for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
+ {
+ statistics.LastSamples[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
+ }
+ }
}
state.InputMovingAverage = inputMovingAverage;
@@ -161,7 +186,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
else
{
- for (int i = 0; i < Parameter.ChannelCount; i++)
+ for (int i = 0; i < _parameter.ChannelCount; i++)
{
if (InputBufferIndices[i] != OutputBufferIndices[i])
{
diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs
index 3ba0b588..06e93219 100644
--- a/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs
+++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs
@@ -38,10 +38,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
- for (int i = 0; i < Parameter.ChannelCount; i++)
+ for (int i = 0; i < _parameter.ChannelCount; i++)
{
- InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
- OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
+ InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
+ OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
}
}
@@ -51,11 +51,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (IsEffectEnabled)
{
- if (Parameter.Status == UsageState.Invalid)
+ if (_parameter.Status == UsageState.Invalid)
{
state = new LimiterState(ref _parameter, WorkBuffer);
}
- else if (Parameter.Status == UsageState.New)
+ else if (_parameter.Status == UsageState.New)
{
LimiterState.UpdateParameter(ref _parameter);
}
@@ -66,56 +66,56 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
private unsafe void ProcessLimiter(CommandList context, ref LimiterState state)
{
- Debug.Assert(Parameter.IsChannelCountValid());
+ Debug.Assert(_parameter.IsChannelCountValid());
- if (IsEffectEnabled && Parameter.IsChannelCountValid())
+ if (IsEffectEnabled && _parameter.IsChannelCountValid())
{
- Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
- Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
+ Span<IntPtr> inputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
+ Span<IntPtr> outputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
- for (int i = 0; i < Parameter.ChannelCount; i++)
+ for (int i = 0; i < _parameter.ChannelCount; i++)
{
inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]);
outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]);
}
- for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
+ for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
{
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
{
float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
- float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
+ float inputSample = (rawInputSample / short.MaxValue) * _parameter.InputGain;
float sampleInputMax = Math.Abs(inputSample);
- float inputCoefficient = Parameter.ReleaseCoefficient;
+ float inputCoefficient = _parameter.ReleaseCoefficient;
if (sampleInputMax > state.DetectorAverage[channelIndex].Read())
{
- inputCoefficient = Parameter.AttackCoefficient;
+ inputCoefficient = _parameter.AttackCoefficient;
}
float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient);
float attenuation = 1.0f;
- if (detectorValue > Parameter.Threshold)
+ if (detectorValue > _parameter.Threshold)
{
- attenuation = Parameter.Threshold / detectorValue;
+ attenuation = _parameter.Threshold / detectorValue;
}
- float outputCoefficient = Parameter.ReleaseCoefficient;
+ float outputCoefficient = _parameter.ReleaseCoefficient;
if (state.CompressionGainAverage[channelIndex].Read() > attenuation)
{
- outputCoefficient = Parameter.AttackCoefficient;
+ outputCoefficient = _parameter.AttackCoefficient;
}
float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient);
- ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
+ ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * _parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
- float outputSample = delayedSample * compressionGain * Parameter.OutputGain;
+ float outputSample = delayedSample * compressionGain * _parameter.OutputGain;
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
@@ -123,16 +123,16 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
state.DelayedSampleBufferPosition[channelIndex]++;
- while (state.DelayedSampleBufferPosition[channelIndex] >= Parameter.DelayBufferSampleCountMin)
+ while (state.DelayedSampleBufferPosition[channelIndex] >= _parameter.DelayBufferSampleCountMin)
{
- state.DelayedSampleBufferPosition[channelIndex] -= Parameter.DelayBufferSampleCountMin;
+ state.DelayedSampleBufferPosition[channelIndex] -= _parameter.DelayBufferSampleCountMin;
}
}
}
}
else
{
- for (int i = 0; i < Parameter.ChannelCount; i++)
+ for (int i = 0; i < _parameter.ChannelCount; i++)
{
if (InputBufferIndices[i] != OutputBufferIndices[i])
{
diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs
index f6e1654d..ed0538c0 100644
--- a/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs
+++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs
@@ -49,10 +49,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
- for (int i = 0; i < Parameter.ChannelCount; i++)
+ for (int i = 0; i < _parameter.ChannelCount; i++)
{
- InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
- OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
+ InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
+ OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
}
}
@@ -62,11 +62,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (IsEffectEnabled)
{
- if (Parameter.Status == UsageState.Invalid)
+ if (_parameter.Status == UsageState.Invalid)
{
state = new LimiterState(ref _parameter, WorkBuffer);
}
- else if (Parameter.Status == UsageState.New)
+ else if (_parameter.Status == UsageState.New)
{
LimiterState.UpdateParameter(ref _parameter);
}
@@ -77,63 +77,63 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
private unsafe void ProcessLimiter(CommandList context, ref LimiterState state)
{
- Debug.Assert(Parameter.IsChannelCountValid());
+ Debug.Assert(_parameter.IsChannelCountValid());
- if (IsEffectEnabled && Parameter.IsChannelCountValid())
+ if (IsEffectEnabled && _parameter.IsChannelCountValid())
{
- if (!ResultState.IsEmpty && Parameter.StatisticsReset)
+ if (!ResultState.IsEmpty && _parameter.StatisticsReset)
{
ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0];
statistics.Reset();
}
- Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
- Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
+ Span<IntPtr> inputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
+ Span<IntPtr> outputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
- for (int i = 0; i < Parameter.ChannelCount; i++)
+ for (int i = 0; i < _parameter.ChannelCount; i++)
{
inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]);
outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]);
}
- for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
+ for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
{
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
{
float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
- float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
+ float inputSample = (rawInputSample / short.MaxValue) * _parameter.InputGain;
float sampleInputMax = Math.Abs(inputSample);
- float inputCoefficient = Parameter.ReleaseCoefficient;
+ float inputCoefficient = _parameter.ReleaseCoefficient;
if (sampleInputMax > state.DetectorAverage[channelIndex].Read())
{
- inputCoefficient = Parameter.AttackCoefficient;
+ inputCoefficient = _parameter.AttackCoefficient;
}
float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient);
float attenuation = 1.0f;
- if (detectorValue > Parameter.Threshold)
+ if (detectorValue > _parameter.Threshold)
{
- attenuation = Parameter.Threshold / detectorValue;
+ attenuation = _parameter.Threshold / detectorValue;
}
- float outputCoefficient = Parameter.ReleaseCoefficient;
+ float outputCoefficient = _parameter.ReleaseCoefficient;
if (state.CompressionGainAverage[channelIndex].Read() > attenuation)
{
- outputCoefficient = Parameter.AttackCoefficient;
+ outputCoefficient = _parameter.AttackCoefficient;
}
float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient);
- ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
+ ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * _parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
- float outputSample = delayedSample * compressionGain * Parameter.OutputGain;
+ float outputSample = delayedSample * compressionGain * _parameter.OutputGain;
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
@@ -141,9 +141,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
state.DelayedSampleBufferPosition[channelIndex]++;
- while (state.DelayedSampleBufferPosition[channelIndex] >= Parameter.DelayBufferSampleCountMin)
+ while (state.DelayedSampleBufferPosition[channelIndex] >= _parameter.DelayBufferSampleCountMin)
{
- state.DelayedSampleBufferPosition[channelIndex] -= Parameter.DelayBufferSampleCountMin;
+ state.DelayedSampleBufferPosition[channelIndex] -= _parameter.DelayBufferSampleCountMin;
}
if (!ResultState.IsEmpty)
@@ -158,7 +158,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
else
{
- for (int i = 0; i < Parameter.ChannelCount; i++)
+ for (int i = 0; i < _parameter.ChannelCount; i++)
{
if (InputBufferIndices[i] != OutputBufferIndices[i])
{
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs
index b403f137..c00118e4 100644
--- a/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs
@@ -90,9 +90,16 @@ namespace Ryujinx.Audio.Renderer.Parameter.Effect
public bool MakeupGainEnabled;
/// <summary>
- /// Reserved/padding.
+ /// Indicate if the compressor effect should output statistics.
/// </summary>
- private Array2<byte> _reserved;
+ [MarshalAs(UnmanagedType.I1)]
+ public bool StatisticsEnabled;
+
+ /// <summary>
+ /// Indicate to the DSP that the user did a statistics reset.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool StatisticsReset;
/// <summary>
/// Check if the <see cref="ChannelCount"/> is valid.
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorStatistics.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorStatistics.cs
new file mode 100644
index 00000000..65335e2d
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorStatistics.cs
@@ -0,0 +1,38 @@
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Effect
+{
+ /// <summary>
+ /// Effect result state for <seealso cref="Common.EffectType.Compressor"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct CompressorStatistics
+ {
+ /// <summary>
+ /// Maximum input mean value since last reset.
+ /// </summary>
+ public float MaximumMean;
+
+ /// <summary>
+ /// Minimum output gain since last reset.
+ /// </summary>
+ public float MinimumGain;
+
+ /// <summary>
+ /// Last processed input sample, per channel.
+ /// </summary>
+ public Array6<float> LastSamples;
+
+ /// <summary>
+ /// Reset the statistics.
+ /// </summary>
+ /// <param name="channelCount">Number of channels to reset.</param>
+ public void Reset(ushort channelCount)
+ {
+ MaximumMean = 0.0f;
+ MinimumGain = 1.0f;
+ LastSamples.AsSpan()[..channelCount].Clear();
+ }
+ }
+}
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs
index 807232f2..7ee49f11 100644
--- a/src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs
+++ b/src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs
@@ -29,6 +29,11 @@ namespace Ryujinx.Audio.Renderer.Parameter
bool IsUsed { get; }
/// <summary>
+ /// Set to true to force resetting the previous mix volumes.
+ /// </summary>
+ bool ResetPrevVolume { get; }
+
+ /// <summary>
/// Mix buffer volumes.
/// </summary>
/// <remarks>Used when a splitter id is specified in the mix.</remarks>
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs
index 029c001e..f346efcb 100644
--- a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs
+++ b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs
@@ -38,9 +38,15 @@ namespace Ryujinx.Audio.Renderer.Parameter
public bool IsUsed;
/// <summary>
+ /// Set to true to force resetting the previous mix volumes.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool ResetPrevVolume;
+
+ /// <summary>
/// Reserved/padding.
/// </summary>
- private unsafe fixed byte _reserved[3];
+ private unsafe fixed byte _reserved[2];
[StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)]
private struct MixArray { }
@@ -58,6 +64,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => default;
readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed;
+ readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume;
/// <summary>
/// The expected constant of any input header.
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs
index 312be8b7..1d867919 100644
--- a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs
+++ b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs
@@ -43,9 +43,15 @@ namespace Ryujinx.Audio.Renderer.Parameter
public bool IsUsed;
/// <summary>
+ /// Set to true to force resetting the previous mix volumes.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool ResetPrevVolume;
+
+ /// <summary>
/// Reserved/padding.
/// </summary>
- private unsafe fixed byte _reserved[11];
+ private unsafe fixed byte _reserved[10];
[StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)]
private struct MixArray { }
@@ -63,6 +69,7 @@ namespace Ryujinx.Audio.Renderer.Parameter
readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => BiquadFilters;
readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed;
+ readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume;
/// <summary>
/// The expected constant of any input header.
diff --git a/src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs b/src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs
index 32c7de6c..f725eb9f 100644
--- a/src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs
+++ b/src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs
@@ -109,9 +109,17 @@ namespace Ryujinx.Audio.Renderer.Server
public const int Revision12 = 12 << 24;
/// <summary>
+ /// REV13:
+ /// The compressor effect can now output statistics.
+ /// Splitter destinations now explicitly reset the previous mix volume, instead of doing so on first use.
+ /// </summary>
+ /// <remarks>This was added in system update 18.0.0</remarks>
+ public const int Revision13 = 13 << 24;
+
+ /// <summary>
/// Last revision supported by the implementation.
/// </summary>
- public const int LastRevision = Revision12;
+ public const int LastRevision = Revision13;
/// <summary>
/// Target revision magic supported by the implementation.
@@ -385,6 +393,15 @@ namespace Ryujinx.Audio.Renderer.Server
}
/// <summary>
+ /// Check if the audio renderer should support explicit previous mix volume reset on splitter.
+ /// </summary>
+ /// <returns>True if the audio renderer support explicit previous mix volume reset on splitter</returns>
+ public bool IsSplitterPrevVolumeResetSupported()
+ {
+ return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision13);
+ }
+
+ /// <summary>
/// Get the version of the <see cref="ICommandProcessingTimeEstimator"/>.
/// </summary>
/// <returns>The version of the <see cref="ICommandProcessingTimeEstimator"/>.</returns>
diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs b/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs
index 702f0546..4c353b37 100644
--- a/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs
+++ b/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs
@@ -583,11 +583,20 @@ namespace Ryujinx.Audio.Renderer.Server
}
}
- public void GenerateCompressorEffect(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
+ /// <summary>
+ /// Generate a new <see cref="CompressorCommand"/>.
+ /// </summary>
+ /// <param name="bufferOffset">The target buffer offset.</param>
+ /// <param name="parameter">The compressor parameter.</param>
+ /// <param name="state">The compressor state.</param>
+ /// <param name="effectResultState">The DSP effect result state.</param>
+ /// <param name="isEnabled">Set to true if the effect should be active.</param>
+ /// <param name="nodeId">The node id associated to this command.</param>
+ public void GenerateCompressorEffect(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, Memory<EffectResultState> effectResultState, bool isEnabled, int nodeId)
{
if (parameter.IsChannelCountValid())
{
- CompressorCommand command = new(bufferOffset, parameter, state, isEnabled, nodeId);
+ CompressorCommand command = new(bufferOffset, parameter, state, effectResultState, isEnabled, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs b/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs
index d798230c..0b789537 100644
--- a/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs
+++ b/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs
@@ -735,14 +735,26 @@ namespace Ryujinx.Audio.Renderer.Server
}
}
- private void GenerateCompressorEffect(uint bufferOffset, CompressorEffect effect, int nodeId)
+ private void GenerateCompressorEffect(uint bufferOffset, CompressorEffect effect, int nodeId, int effectId)
{
Debug.Assert(effect.Type == EffectType.Compressor);
+ Memory<EffectResultState> dspResultState;
+
+ if (effect.Parameter.StatisticsEnabled)
+ {
+ dspResultState = _effectContext.GetDspStateMemory(effectId);
+ }
+ else
+ {
+ dspResultState = Memory<EffectResultState>.Empty;
+ }
+
_commandBuffer.GenerateCompressorEffect(
bufferOffset,
effect.Parameter,
effect.State,
+ dspResultState,
effect.IsEnabled,
nodeId);
}
@@ -795,7 +807,7 @@ namespace Ryujinx.Audio.Renderer.Server
GenerateCaptureEffect(mix.BufferOffset, (CaptureBufferEffect)effect, nodeId);
break;
case EffectType.Compressor:
- GenerateCompressorEffect(mix.BufferOffset, (CompressorEffect)effect, nodeId);
+ GenerateCompressorEffect(mix.BufferOffset, (CompressorEffect)effect, nodeId, effectId);
break;
default:
throw new NotImplementedException($"Unsupported effect type {effect.Type}");
diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs
index 06f135a8..bc9ba073 100644
--- a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs
+++ b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs
@@ -169,14 +169,28 @@ namespace Ryujinx.Audio.Renderer.Server
{
if (command.Enabled)
{
- return command.Parameter.ChannelCount switch
+ if (command.Parameter.StatisticsEnabled)
{
- 1 => 34431,
- 2 => 44253,
- 4 => 63827,
- 6 => 83361,
- _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
- };
+ return command.Parameter.ChannelCount switch
+ {
+ 1 => 22100,
+ 2 => 33211,
+ 4 => 41587,
+ 6 => 58819,
+ _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
+ };
+ }
+ else
+ {
+ return command.Parameter.ChannelCount switch
+ {
+ 1 => 19052,
+ 2 => 29852,
+ 4 => 37904,
+ 6 => 55020,
+ _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
+ };
+ }
}
return command.Parameter.ChannelCount switch
@@ -191,14 +205,28 @@ namespace Ryujinx.Audio.Renderer.Server
if (command.Enabled)
{
- return command.Parameter.ChannelCount switch
+ if (command.Parameter.StatisticsEnabled)
{
- 1 => 51095,
- 2 => 65693,
- 4 => 95383,
- 6 => 124510,
- _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
- };
+ return command.Parameter.ChannelCount switch
+ {
+ 1 => 32518,
+ 2 => 49102,
+ 4 => 61685,
+ 6 => 87250,
+ _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
+ };
+ }
+ else
+ {
+ return command.Parameter.ChannelCount switch
+ {
+ 1 => 27963,
+ 2 => 44016,
+ 4 => 56183,
+ 6 => 81862,
+ _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
+ };
+ }
}
return command.Parameter.ChannelCount switch
diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs
index eff60e7d..de0f44e4 100644
--- a/src/Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs
+++ b/src/Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs
@@ -62,6 +62,19 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
UpdateUsageStateForCommandGeneration();
Parameter.Status = UsageState.Enabled;
+ Parameter.StatisticsReset = false;
+ }
+
+ public override void InitializeResultState(ref EffectResultState state)
+ {
+ ref CompressorStatistics statistics = ref MemoryMarshal.Cast<byte, CompressorStatistics>(state.SpecificData)[0];
+
+ statistics.Reset(Parameter.ChannelCount);
+ }
+
+ public override void UpdateResultState(ref EffectResultState destState, ref EffectResultState srcState)
+ {
+ destState = srcState;
}
}
}
diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs
index a7b82a6b..6dddb431 100644
--- a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs
+++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs
@@ -52,6 +52,11 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
public bool IsBugFixed { get; private set; }
/// <summary>
+ /// If set to true, the previous mix volume is explicitly resetted using the input parameter, instead of implicitly on first use.
+ /// </summary>
+ public bool IsSplitterPrevVolumeResetSupported { get; private set; }
+
+ /// <summary>
/// Initialize <see cref="SplitterContext"/>.
/// </summary>
/// <param name="behaviourContext">The behaviour context.</param>
@@ -139,6 +144,8 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
}
}
+ IsSplitterPrevVolumeResetSupported = behaviourContext.IsSplitterPrevVolumeResetSupported();
+
SplitterState.InitializeSplitters(splitters.Span);
Setup(splitters, splitterDestinationsV1, splitterDestinationsV2, behaviourContext.IsSplitterBugFixed());
@@ -277,7 +284,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
{
SplitterDestination destination = GetDestination(parameter.Id);
- destination.Update(parameter);
+ destination.Update(parameter, IsSplitterPrevVolumeResetSupported);
}
return true;
diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs
index 36dfa5e4..1a46d41f 100644
--- a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs
+++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs
@@ -184,15 +184,16 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// Update the splitter destination data from user parameter.
/// </summary>
/// <param name="parameter">The user parameter.</param>
- public void Update<T>(in T parameter) where T : ISplitterDestinationInParameter
+ /// <param name="isPrevVolumeResetSupported">Indicates that the audio renderer revision in use supports explicitly resetting the volume.</param>
+ public void Update<T>(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter
{
if (Unsafe.IsNullRef(ref _v2))
{
- _v1.Update(parameter);
+ _v1.Update(parameter, isPrevVolumeResetSupported);
}
else
{
- _v2.Update(parameter);
+ _v2.Update(parameter, isPrevVolumeResetSupported);
}
}
diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion1.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion1.cs
index 5d2b8fb0..ce8f3368 100644
--- a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion1.cs
+++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion1.cs
@@ -93,7 +93,8 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// Update the <see cref="SplitterDestinationVersion1"/> from user parameter.
/// </summary>
/// <param name="parameter">The user parameter.</param>
- public void Update<T>(in T parameter) where T : ISplitterDestinationInParameter
+ /// <param name="isPrevVolumeResetSupported">Indicates that the audio renderer revision in use supports explicitly resetting the volume.</param>
+ public void Update<T>(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter
{
Debug.Assert(Id == parameter.Id);
@@ -103,7 +104,8 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
parameter.MixBufferVolume.CopyTo(MixBufferVolume);
- if (!IsUsed && parameter.IsUsed)
+ bool resetPrevVolume = isPrevVolumeResetSupported ? parameter.ResetPrevVolume : !IsUsed && parameter.IsUsed;
+ if (resetPrevVolume)
{
MixBufferVolume.CopyTo(PreviousMixBufferVolume);
diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs
index f9487909..5f96ef3a 100644
--- a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs
+++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs
@@ -98,7 +98,8 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// Update the <see cref="SplitterDestinationVersion2"/> from user parameter.
/// </summary>
/// <param name="parameter">The user parameter.</param>
- public void Update<T>(in T parameter) where T : ISplitterDestinationInParameter
+ /// <param name="isPrevVolumeResetSupported">Indicates that the audio renderer revision in use supports explicitly resetting the volume.</param>
+ public void Update<T>(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter
{
Debug.Assert(Id == parameter.Id);
@@ -110,7 +111,8 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
_biquadFilters = parameter.BiquadFilters;
- if (!IsUsed && parameter.IsUsed)
+ bool resetPrevVolume = isPrevVolumeResetSupported ? parameter.ResetPrevVolume : !IsUsed && parameter.IsUsed;
+ if (resetPrevVolume)
{
MixBufferVolume.CopyTo(PreviousMixBufferVolume);
diff --git a/src/Ryujinx.Horizon/Sdk/Audio/AudioResult.cs b/src/Ryujinx.Horizon/Sdk/Audio/AudioResult.cs
index c18bfee9..5914a747 100644
--- a/src/Ryujinx.Horizon/Sdk/Audio/AudioResult.cs
+++ b/src/Ryujinx.Horizon/Sdk/Audio/AudioResult.cs
@@ -8,5 +8,6 @@ namespace Ryujinx.Horizon.Sdk.Audio
public static Result DeviceNotFound => new(ModuleId, 1);
public static Result UnsupportedRevision => new(ModuleId, 2);
+ public static Result NotImplemented => new(ModuleId, 513);
}
}
diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs
index f67ea729..2d3aa7ba 100644
--- a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs
+++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs
@@ -233,6 +233,48 @@ namespace Ryujinx.Horizon.Sdk.Audio.Detail
return Result.Success;
}
+ [CmifCommand(15)] // 17.0.0+
+ public Result AcquireAudioOutputDeviceNotification([CopyHandle] out int eventHandle, ulong deviceId)
+ {
+ eventHandle = 0;
+
+ return AudioResult.NotImplemented;
+ }
+
+ [CmifCommand(16)] // 17.0.0+
+ public Result ReleaseAudioOutputDeviceNotification(ulong deviceId)
+ {
+ return AudioResult.NotImplemented;
+ }
+
+ [CmifCommand(17)] // 17.0.0+
+ public Result AcquireAudioInputDeviceNotification([CopyHandle] out int eventHandle, ulong deviceId)
+ {
+ eventHandle = 0;
+
+ return AudioResult.NotImplemented;
+ }
+
+ [CmifCommand(18)] // 17.0.0+
+ public Result ReleaseAudioInputDeviceNotification(ulong deviceId)
+ {
+ return AudioResult.NotImplemented;
+ }
+
+ [CmifCommand(19)] // 18.0.0+
+ public Result SetAudioDeviceOutputVolumeAutoTuneEnabled(bool enabled)
+ {
+ return AudioResult.NotImplemented;
+ }
+
+ [CmifCommand(20)] // 18.0.0+
+ public Result IsAudioDeviceOutputVolumeAutoTuneEnabled(out bool enabled)
+ {
+ enabled = false;
+
+ return AudioResult.NotImplemented;
+ }
+
protected virtual void Dispose(bool disposing)
{
if (disposing)
diff --git a/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs
index 3e48a5b4..0b0ed7a5 100644
--- a/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs
+++ b/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs
@@ -55,6 +55,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@@ -83,6 +84,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@@ -111,6 +113,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@@ -139,6 +142,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.75f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@@ -167,6 +171,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@@ -195,6 +200,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@@ -223,6 +229,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@@ -251,6 +258,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(3, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@@ -279,6 +287,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsFalse(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(3, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@@ -307,6 +316,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(4, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@@ -335,6 +345,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsTrue(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(5, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
@@ -363,6 +374,36 @@ namespace Ryujinx.Tests.Audio.Renderer.Server
Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing());
Assert.IsTrue(behaviourContext.IsNewEffectChannelMappingSupported());
Assert.IsTrue(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported());
+
+ Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
+ Assert.AreEqual(5, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
+ Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat());
+ }
+
+ [Test]
+ public void TestRevision13()
+ {
+ BehaviourContext behaviourContext = new();
+
+ behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision13);
+
+ Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed());
+ Assert.IsTrue(behaviourContext.IsSplitterSupported());
+ Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported());
+ Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported());
+ Assert.IsTrue(behaviourContext.IsFlushVoiceWaveBuffersSupported());
+ Assert.IsTrue(behaviourContext.IsSplitterBugFixed());
+ Assert.IsTrue(behaviourContext.IsElapsedFrameCountSupported());
+ Assert.IsTrue(behaviourContext.IsDecodingBehaviourFlagSupported());
+ Assert.IsTrue(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
+ Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
+ Assert.IsTrue(behaviourContext.IsWaveBufferVersion2Supported());
+ Assert.IsTrue(behaviourContext.IsEffectInfoVersion2Supported());
+ Assert.IsTrue(behaviourContext.UseMultiTapBiquadFilterProcessing());
+ Assert.IsTrue(behaviourContext.IsNewEffectChannelMappingSupported());
+ Assert.IsTrue(behaviourContext.IsBiquadFilterParameterForSplitterEnabled());
+ Assert.IsTrue(behaviourContext.IsSplitterPrevVolumeResetSupported());
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
Assert.AreEqual(5, behaviourContext.GetCommandProcessingTimeEstimatorVersion());