From e2143d43bcb6762340d8a01f20e7b5fdf104f02f Mon Sep 17 00:00:00 2001 From: LotP <22-lotp@users.noreply.git.ryujinx.app> Date: Sat, 11 Oct 2025 02:11:39 -0500 Subject: [PATCH] SDK20 and REV15 support (ryubing/ryujinx!50) See merge request ryubing/ryujinx!50 --- .../Renderer/Common/BehaviourParameter.cs | 8 +- .../{VoiceUpdateState.cs => VoiceState.cs} | 5 +- .../Renderer/Dsp/BiquadFilterHelper.cs | 238 +++++++--- .../Command/AdpcmDataSourceCommandVersion1.cs | 18 +- .../Dsp/Command/BiquadFilterAndMixCommand.cs | 8 +- .../Dsp/Command/BiquadFilterCommand.cs | 4 +- .../Renderer/Dsp/Command/CommandList.cs | 2 +- .../Renderer/Dsp/Command/CommandType.cs | 9 + .../Dsp/Command/DataSourceVersion2Command.cs | 24 +- .../Dsp/Command/DepopPrepareCommand.cs | 6 +- .../Renderer/Dsp/Command/DeviceSinkCommand.cs | 4 +- .../Renderer/Dsp/Command/FillBufferCommand.cs | 69 +++ .../Renderer/Dsp/Command/MixRampCommand.cs | 4 +- .../Dsp/Command/MixRampGroupedCommand.cs | 6 +- .../MultiTapBiquadFilterAndMixCommand.cs | 12 +- .../Command/MultiTapBiquadFilterCommand.cs | 4 +- .../PcmFloatDataSourceCommandVersion1.cs | 16 +- .../PcmInt16DataSourceCommandVersion1.cs | 16 +- .../Renderer/Dsp/Command/UpsampleCommand.cs | 4 +- .../Renderer/Dsp/DataSourceHelper.cs | 4 +- .../Renderer/Dsp/ResamplerHelper.cs | 2 +- .../Parameter/AudioRendererConfiguration.cs | 3 +- ...Parameter.cs => BiquadFilterParameter1.cs} | 2 +- .../Parameter/BiquadFilterParameter2.cs | 36 ++ ...ter.cs => BiquadFilterEffectParameter1.cs} | 2 +- .../Effect/BiquadFilterEffectParameter2.cs | 49 +++ .../Parameter/EffectInParameterVersion3.cs | 97 ++++ .../ISplitterDestinationInParameter.cs | 4 +- .../Renderer/Parameter/SinkInParameter.cs | 2 +- .../SplitterDestinationInParameterVersion1.cs | 4 +- ...SplitterDestinationInParameterVersion2a.cs | 100 +++++ ...plitterDestinationInParameterVersion2b.cs} | 6 +- ...iceInParameter.cs => VoiceInParameter1.cs} | 10 +- .../Renderer/Parameter/VoiceInParameter2.cs | 176 ++++++++ .../Renderer/Parameter/VoiceOutStatus.cs | 6 +- .../Renderer/Server/AudioRenderSystem.cs | 131 +++--- .../{BehaviourContext.cs => BehaviourInfo.cs} | 98 +++-- .../Renderer/Server/CommandBuffer.cs | 90 ++-- .../Renderer/Server/CommandGenerator.cs | 183 ++++---- .../CommandProcessingTimeEstimatorVersion1.cs | 5 + .../CommandProcessingTimeEstimatorVersion2.cs | 5 + .../CommandProcessingTimeEstimatorVersion3.cs | 7 +- .../CommandProcessingTimeEstimatorVersion5.cs | 5 + .../Renderer/Server/Effect/BaseEffect.cs | 13 + .../Server/Effect/BiquadFilterEffect.cs | 22 +- .../Server/ICommandProcessingTimeEstimator.cs | 1 + .../Renderer/Server/MemoryPool/AddressInfo.cs | 34 +- .../{MemoryPoolState.cs => MemoryPoolInfo.cs} | 38 +- .../Renderer/Server/MemoryPool/PoolMapper.cs | 76 ++-- .../Renderer/Server/Mix/MixContext.cs | 54 +-- .../Server/Mix/{MixState.cs => MixInfo.cs} | 21 +- .../Server/Performance/PerformanceManager.cs | 12 +- .../Renderer/Server/RendererSystemContext.cs | 9 +- .../Renderer/Server/Sink/DeviceSink.cs | 6 +- .../Server/Splitter/SplitterContext.cs | 72 ++- .../Server/Splitter/SplitterDestination.cs | 92 ++-- .../Splitter/SplitterDestinationVersion2.cs | 11 +- .../Renderer/Server/StateUpdater.cs | 224 ++++++++-- .../Renderer/Server/Types/PlayState.cs | 6 +- .../{UpsamplerState.cs => UpsamplerInfo.cs} | 12 +- .../Server/Upsampler/UpsamplerManager.cs | 16 +- .../Renderer/Server/Voice/VoiceContext.cs | 58 +-- .../Voice/{VoiceState.cs => VoiceInfo.cs} | 312 ++++++++++--- .../SharedMemory/Common/ISampledDataStruct.cs | 2 +- .../Audio/AudioUserIpcServer.cs | 2 + .../Sdk/Audio/Detail/AudioDevice.cs | 6 +- .../Sdk/Audio/Detail/AudioRendererManager.cs | 4 +- .../Sdk/Audio/Detail/AudioSnoopManager.cs | 42 +- .../Sdk/Audio/Detail/IAudioSnoopManager.cs | 6 + .../Renderer/BiquadFilterParameterTests.cs | 3 +- ...UpdateStateTests.cs => VoiceStateTests.cs} | 4 +- .../Audio/Renderer/Dsp/ResamplerTests.cs | 22 +- .../BiquadFilterEffectParameterTests.cs | 3 +- .../Audio/Renderer/Server/AddressInfoTests.cs | 4 +- .../Renderer/Server/BehaviourContextTests.cs | 413 ------------------ .../Renderer/Server/BehaviourInfoTests.cs | 413 ++++++++++++++++++ ...olStateTests.cs => MemoryPoolInfoTests.cs} | 10 +- .../{MixStateTests.cs => MixInfoTests.cs} | 4 +- .../Audio/Renderer/Server/PoolMapperTests.cs | 16 +- .../Server/SplitterDestinationTests.cs | 2 +- .../{VoiceStateTests.cs => VoiceInfoTests.cs} | 4 +- .../Audio/Renderer/VoiceInParameterTests.cs | 3 +- src/Ryujinx.Tests/Memory/PartialUnmaps.cs | 2 +- 83 files changed, 2343 insertions(+), 1195 deletions(-) rename src/Ryujinx.Audio/Renderer/Common/{VoiceUpdateState.cs => VoiceState.cs} (95%) create mode 100644 src/Ryujinx.Audio/Renderer/Dsp/Command/FillBufferCommand.cs rename src/Ryujinx.Audio/Renderer/Parameter/{BiquadFilterParameter.cs => BiquadFilterParameter1.cs} (95%) create mode 100644 src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter2.cs rename src/Ryujinx.Audio/Renderer/Parameter/Effect/{BiquadFilterEffectParameter.cs => BiquadFilterEffectParameter1.cs} (96%) create mode 100644 src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter2.cs create mode 100644 src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion3.cs create mode 100644 src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2a.cs rename src/Ryujinx.Audio/Renderer/Parameter/{SplitterDestinationInParameterVersion2.cs => SplitterDestinationInParameterVersion2b.cs} (90%) rename src/Ryujinx.Audio/Renderer/Parameter/{VoiceInParameter.cs => VoiceInParameter1.cs} (98%) create mode 100644 src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter2.cs rename src/Ryujinx.Audio/Renderer/Server/{BehaviourContext.cs => BehaviourInfo.cs} (89%) rename src/Ryujinx.Audio/Renderer/Server/MemoryPool/{MemoryPoolState.cs => MemoryPoolInfo.cs} (73%) rename src/Ryujinx.Audio/Renderer/Server/Mix/{MixState.cs => MixInfo.cs} (93%) rename src/Ryujinx.Audio/Renderer/Server/Upsampler/{UpsamplerState.cs => UpsamplerInfo.cs} (82%) rename src/Ryujinx.Audio/Renderer/Server/Voice/{VoiceState.cs => VoiceInfo.cs} (66%) rename src/Ryujinx.Tests/Audio/Renderer/Common/{VoiceUpdateStateTests.cs => VoiceStateTests.cs} (68%) delete mode 100644 src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs create mode 100644 src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourInfoTests.cs rename src/Ryujinx.Tests/Audio/Renderer/Server/{MemoryPoolStateTests.cs => MemoryPoolInfoTests.cs} (80%) rename src/Ryujinx.Tests/Audio/Renderer/Server/{MixStateTests.cs => MixInfoTests.cs} (73%) rename src/Ryujinx.Tests/Audio/Renderer/Server/{VoiceStateTests.cs => VoiceInfoTests.cs} (71%) diff --git a/src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs b/src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs index 3b8d15dc5..5b4f39e23 100644 --- a/src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs +++ b/src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs @@ -1,9 +1,11 @@ +using Ryujinx.Audio.Renderer.Server; +using Ryujinx.Audio.Renderer.Server.MemoryPool; using System.Runtime.InteropServices; namespace Ryujinx.Audio.Renderer.Common { /// - /// Represents the input parameter for . + /// Represents the input parameter for . /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct BehaviourParameter @@ -21,7 +23,7 @@ namespace Ryujinx.Audio.Renderer.Common /// /// The flags given controlling behaviour of the audio renderer /// - /// See and . + /// See and . public ulong Flags; /// @@ -43,7 +45,7 @@ namespace Ryujinx.Audio.Renderer.Common /// /// Extra information given with the /// - /// This is usually used to report a faulting cpu address when a mapping fail. + /// This is usually used to report a faulting cpu address when a mapping fail. public ulong ExtraErrorInfo; } } diff --git a/src/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs b/src/Ryujinx.Audio/Renderer/Common/VoiceState.cs similarity index 95% rename from src/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs rename to src/Ryujinx.Audio/Renderer/Common/VoiceState.cs index 7f881373f..508daa6e2 100644 --- a/src/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs +++ b/src/Ryujinx.Audio/Renderer/Common/VoiceState.cs @@ -1,4 +1,5 @@ using Ryujinx.Audio.Renderer.Dsp.State; +using Ryujinx.Audio.Renderer.Parameter; using Ryujinx.Common.Memory; using Ryujinx.Common.Utilities; using System; @@ -11,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Common /// /// This is shared between the server and audio processor. [StructLayout(LayoutKind.Sequential, Pack = Align)] - public struct VoiceUpdateState + public struct VoiceState { public const int Align = 0x10; public const int BiquadStateOffset = 0x0; @@ -25,7 +26,7 @@ namespace Ryujinx.Audio.Renderer.Common /// The total amount of samples that was played. /// /// This is reset to 0 when a finishes playing and is set. - /// This is reset to 0 when looping while is set. + /// This is reset to 0 when looping while is set. public ulong PlayedSampleCount; /// diff --git a/src/Ryujinx.Audio/Renderer/Dsp/BiquadFilterHelper.cs b/src/Ryujinx.Audio/Renderer/Dsp/BiquadFilterHelper.cs index 2122f2b44..4f98a8fb5 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/BiquadFilterHelper.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/BiquadFilterHelper.cs @@ -1,5 +1,7 @@ using Ryujinx.Audio.Renderer.Dsp.State; using Ryujinx.Audio.Renderer.Parameter; +using Ryujinx.Audio.Renderer.Parameter.Effect; +using Ryujinx.Common.Memory; using System; using System.Runtime.CompilerServices; @@ -9,6 +11,112 @@ namespace Ryujinx.Audio.Renderer.Dsp { private const int FixedPointPrecisionForParameter = 14; + public static BiquadFilterParameter1 ToBiquadFilterParameter1(BiquadFilterParameter2 parameter) + { + BiquadFilterParameter1 result = new() + { + Enable = parameter.Enable, Numerator = new Array3(), Denominator = new Array2() + }; + + Span resultNumeratorSpan = result.Numerator.AsSpan(); + Span resultDenominatorSpan = result.Denominator.AsSpan(); + + Span parameterNumeratorSpan = parameter.Numerator.AsSpan(); + Span parameterDenominatorSpan = parameter.Denominator.AsSpan(); + + + resultNumeratorSpan[0] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[0], FixedPointPrecisionForParameter); + resultNumeratorSpan[1] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[1], FixedPointPrecisionForParameter); + resultNumeratorSpan[2] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[2], FixedPointPrecisionForParameter); + + resultDenominatorSpan[0] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[0], FixedPointPrecisionForParameter); + resultDenominatorSpan[1] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[1], FixedPointPrecisionForParameter); + + return result; + } + + public static BiquadFilterParameter2 ToBiquadFilterParameter2(BiquadFilterParameter1 parameter) + { + BiquadFilterParameter2 result = new() + { + Enable = parameter.Enable, Numerator = new Array3(), Denominator = new Array2() + }; + + Span resultNumeratorSpan = result.Numerator.AsSpan(); + Span resultDenominatorSpan = result.Denominator.AsSpan(); + + Span parameterNumeratorSpan = parameter.Numerator.AsSpan(); + Span parameterDenominatorSpan = parameter.Denominator.AsSpan(); + + + resultNumeratorSpan[0] = FixedPointHelper.ToFloat(parameterNumeratorSpan[0], FixedPointPrecisionForParameter); + resultNumeratorSpan[1] = FixedPointHelper.ToFloat(parameterNumeratorSpan[1], FixedPointPrecisionForParameter); + resultNumeratorSpan[2] = FixedPointHelper.ToFloat(parameterNumeratorSpan[2], FixedPointPrecisionForParameter); + + resultDenominatorSpan[0] = FixedPointHelper.ToFloat(parameterDenominatorSpan[0], FixedPointPrecisionForParameter); + resultDenominatorSpan[1] = FixedPointHelper.ToFloat(parameterDenominatorSpan[1], FixedPointPrecisionForParameter); + + return result; + } + + public static BiquadFilterEffectParameter1 ToBiquadFilterEffectParameter1(BiquadFilterEffectParameter2 parameter) + { + BiquadFilterEffectParameter1 result = new() + { + Input = parameter.Input, + Output = parameter.Output, + Numerator = new Array3(), + Denominator = new Array2(), + ChannelCount = parameter.ChannelCount, + Status = parameter.Status, + }; + + Span resultNumeratorSpan = result.Numerator.AsSpan(); + Span resultDenominatorSpan = result.Denominator.AsSpan(); + + Span parameterNumeratorSpan = parameter.Numerator.AsSpan(); + Span parameterDenominatorSpan = parameter.Denominator.AsSpan(); + + + resultNumeratorSpan[0] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[0], FixedPointPrecisionForParameter); + resultNumeratorSpan[1] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[1], FixedPointPrecisionForParameter); + resultNumeratorSpan[2] = (short)FixedPointHelper.ToFixed(parameterNumeratorSpan[2], FixedPointPrecisionForParameter); + + resultDenominatorSpan[0] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[0], FixedPointPrecisionForParameter); + resultDenominatorSpan[1] = (short)FixedPointHelper.ToFixed(parameterDenominatorSpan[1], FixedPointPrecisionForParameter); + + return result; + } + + public static BiquadFilterEffectParameter2 ToBiquadFilterEffectParameter2(BiquadFilterEffectParameter1 parameter) + { + BiquadFilterEffectParameter2 result = new() + { + Input = parameter.Input, + Output = parameter.Output, + Numerator = new Array3(), + Denominator = new Array2(), + ChannelCount = parameter.ChannelCount, + Status = parameter.Status, + }; + + Span resultNumeratorSpan = result.Numerator.AsSpan(); + Span resultDenominatorSpan = result.Denominator.AsSpan(); + + Span parameterNumeratorSpan = parameter.Numerator.AsSpan(); + Span parameterDenominatorSpan = parameter.Denominator.AsSpan(); + + + resultNumeratorSpan[0] = FixedPointHelper.ToFloat(parameterNumeratorSpan[0], FixedPointPrecisionForParameter); + resultNumeratorSpan[1] = FixedPointHelper.ToFloat(parameterNumeratorSpan[1], FixedPointPrecisionForParameter); + resultNumeratorSpan[2] = FixedPointHelper.ToFloat(parameterNumeratorSpan[2], FixedPointPrecisionForParameter); + + resultDenominatorSpan[0] = FixedPointHelper.ToFloat(parameterDenominatorSpan[0], FixedPointPrecisionForParameter); + resultDenominatorSpan[1] = FixedPointHelper.ToFloat(parameterDenominatorSpan[1], FixedPointPrecisionForParameter); + + return result; + } + /// /// Apply a single biquad filter. /// @@ -20,21 +128,21 @@ namespace Ryujinx.Audio.Renderer.Dsp /// The count of samples to process [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ProcessBiquadFilter( - ref BiquadFilterParameter parameter, + ref BiquadFilterParameter2 parameter, ref BiquadFilterState state, Span outputBuffer, ReadOnlySpan inputBuffer, uint sampleCount) { - Span numeratorSpan = parameter.Numerator.AsSpan(); - Span denominatorSpan = parameter.Denominator.AsSpan(); + Span numeratorSpan = parameter.Numerator.AsSpan(); + Span denominatorSpan = parameter.Denominator.AsSpan(); - float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter); - float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter); - float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter); + float a0 = numeratorSpan[0]; + float a1 = numeratorSpan[1]; + float a2 = numeratorSpan[2]; - float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter); - float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter); + float b1 = denominatorSpan[0]; + float b2 = denominatorSpan[1]; for (int i = 0; i < sampleCount; i++) { @@ -60,22 +168,22 @@ namespace Ryujinx.Audio.Renderer.Dsp /// Mix volume [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ProcessBiquadFilterAndMix( - ref BiquadFilterParameter parameter, + ref BiquadFilterParameter2 parameter, ref BiquadFilterState state, Span outputBuffer, ReadOnlySpan inputBuffer, uint sampleCount, float volume) { - Span numeratorSpan = parameter.Numerator.AsSpan(); - Span denominatorSpan = parameter.Denominator.AsSpan(); + Span numeratorSpan = parameter.Numerator.AsSpan(); + Span denominatorSpan = parameter.Denominator.AsSpan(); - float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter); - float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter); - float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter); + float a0 = numeratorSpan[0]; + float a1 = numeratorSpan[1]; + float a2 = numeratorSpan[2]; - float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter); - float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter); + float b1 = denominatorSpan[0]; + float b2 = denominatorSpan[1]; for (int i = 0; i < sampleCount; i++) { @@ -105,7 +213,7 @@ namespace Ryujinx.Audio.Renderer.Dsp /// Last filtered sample value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ProcessBiquadFilterAndMixRamp( - ref BiquadFilterParameter parameter, + ref BiquadFilterParameter2 parameter, ref BiquadFilterState state, Span outputBuffer, ReadOnlySpan inputBuffer, @@ -113,15 +221,15 @@ namespace Ryujinx.Audio.Renderer.Dsp float volume, float ramp) { - Span numeratorSpan = parameter.Numerator.AsSpan(); - Span denominatorSpan = parameter.Denominator.AsSpan(); + Span numeratorSpan = parameter.Numerator.AsSpan(); + Span denominatorSpan = parameter.Denominator.AsSpan(); - float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter); - float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter); - float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter); + float a0 = numeratorSpan[0]; + float a1 = numeratorSpan[1]; + float a2 = numeratorSpan[2]; - float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter); - float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter); + float b1 = denominatorSpan[0]; + float b2 = denominatorSpan[1]; float mixState = 0f; @@ -155,7 +263,7 @@ namespace Ryujinx.Audio.Renderer.Dsp /// The count of samples to process [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ProcessBiquadFilter( - ReadOnlySpan parameters, + ReadOnlySpan parameters, Span states, Span outputBuffer, ReadOnlySpan inputBuffer, @@ -163,19 +271,19 @@ namespace Ryujinx.Audio.Renderer.Dsp { for (int stageIndex = 0; stageIndex < parameters.Length; stageIndex++) { - BiquadFilterParameter parameter = parameters[stageIndex]; + BiquadFilterParameter2 parameter = parameters[stageIndex]; ref BiquadFilterState state = ref states[stageIndex]; - Span numeratorSpan = parameter.Numerator.AsSpan(); - Span denominatorSpan = parameter.Denominator.AsSpan(); + Span numeratorSpan = parameter.Numerator.AsSpan(); + Span denominatorSpan = parameter.Denominator.AsSpan(); - float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter); - float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter); - float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter); + float a0 = numeratorSpan[0]; + float a1 = numeratorSpan[1]; + float a2 = numeratorSpan[2]; - float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter); - float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter); + float b1 = denominatorSpan[0]; + float b2 = denominatorSpan[1]; for (int i = 0; i < sampleCount; i++) { @@ -204,8 +312,8 @@ namespace Ryujinx.Audio.Renderer.Dsp /// Mix volume [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ProcessDoubleBiquadFilterAndMix( - ref BiquadFilterParameter parameter0, - ref BiquadFilterParameter parameter1, + ref BiquadFilterParameter2 parameter0, + ref BiquadFilterParameter2 parameter1, ref BiquadFilterState state0, ref BiquadFilterState state1, Span outputBuffer, @@ -213,25 +321,25 @@ namespace Ryujinx.Audio.Renderer.Dsp uint sampleCount, float volume) { - Span numerator0Span = parameter0.Numerator.AsSpan(); - Span numerator1Span = parameter1.Numerator.AsSpan(); - Span denominator0Span = parameter0.Denominator.AsSpan(); - Span denominator1Span = parameter1.Denominator.AsSpan(); + Span numerator0Span = parameter0.Numerator.AsSpan(); + Span numerator1Span = parameter1.Numerator.AsSpan(); + Span denominator0Span = parameter0.Denominator.AsSpan(); + Span denominator1Span = parameter1.Denominator.AsSpan(); - float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter); - float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter); - float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter); + float a00 = numerator0Span[0]; + float a10 = numerator0Span[1]; + float a20 = numerator0Span[2]; - float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter); - float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter); + float b10 = denominator0Span[0]; + float b20 = denominator0Span[1]; - float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter); - float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter); - float a21 = FixedPointHelper.ToFloat(numerator1Span[2], FixedPointPrecisionForParameter); + float a01 = numerator1Span[0]; + float a11 = numerator1Span[1]; + float a21 = numerator1Span[2]; - float b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter); - float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter); + float b11 = denominator1Span[0]; + float b21 = denominator1Span[1]; for (int i = 0; i < sampleCount; i++) { @@ -269,8 +377,8 @@ namespace Ryujinx.Audio.Renderer.Dsp /// Last filtered sample value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ProcessDoubleBiquadFilterAndMixRamp( - ref BiquadFilterParameter parameter0, - ref BiquadFilterParameter parameter1, + ref BiquadFilterParameter2 parameter0, + ref BiquadFilterParameter2 parameter1, ref BiquadFilterState state0, ref BiquadFilterState state1, Span outputBuffer, @@ -279,24 +387,24 @@ namespace Ryujinx.Audio.Renderer.Dsp float volume, float ramp) { - Span numerator0Span = parameter0.Numerator.AsSpan(); - Span numerator1Span = parameter1.Numerator.AsSpan(); - Span denominator0Span = parameter0.Denominator.AsSpan(); - Span denominator1Span = parameter1.Denominator.AsSpan(); + Span numerator0Span = parameter0.Numerator.AsSpan(); + Span numerator1Span = parameter1.Numerator.AsSpan(); + Span denominator0Span = parameter0.Denominator.AsSpan(); + Span denominator1Span = parameter1.Denominator.AsSpan(); - float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter); - float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter); - float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter); + float a00 = numerator0Span[0]; + float a10 = numerator0Span[1]; + float a20 = numerator0Span[2]; - float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter); - float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter); + float b10 = denominator0Span[0]; + float b20 = denominator0Span[1]; - float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter); - float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter); - float a21 = FixedPointHelper.ToFloat(numerator1Span[2], FixedPointPrecisionForParameter); + float a01 = numerator1Span[0]; + float a11 = numerator1Span[1]; + float a21 = numerator1Span[2]; - float b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter); - float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter); + float b11 = denominator1Span[0]; + float b21 = denominator1Span[1]; float mixState = 0f; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/AdpcmDataSourceCommandVersion1.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/AdpcmDataSourceCommandVersion1.cs index 59786c059..60161ee7a 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/AdpcmDataSourceCommandVersion1.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/AdpcmDataSourceCommandVersion1.cs @@ -2,7 +2,7 @@ using Ryujinx.Audio.Common; using Ryujinx.Audio.Renderer.Common; using Ryujinx.Audio.Renderer.Server.Voice; using System; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; +using Ryujinx.Audio.Renderer.Parameter; using WaveBuffer = Ryujinx.Audio.Renderer.Common.WaveBuffer; namespace Ryujinx.Audio.Renderer.Dsp.Command @@ -24,23 +24,23 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public WaveBuffer[] WaveBuffers { get; } - public Memory State { get; } + public Memory State { get; } public ulong AdpcmParameter { get; } public ulong AdpcmParameterSize { get; } public DecodingBehaviour DecodingBehaviour { get; } - public AdpcmDataSourceCommandVersion1(ref VoiceState serverState, Memory state, ushort outputBufferIndex, int nodeId) + public AdpcmDataSourceCommandVersion1(ref VoiceInfo serverInfo, Memory state, ushort outputBufferIndex, int nodeId) { Enabled = true; NodeId = nodeId; OutputBufferIndex = outputBufferIndex; - SampleRate = serverState.SampleRate; - Pitch = serverState.Pitch; + SampleRate = serverInfo.SampleRate; + Pitch = serverInfo.Pitch; - Span waveBufferSpan = serverState.WaveBuffers.AsSpan(); + Span waveBufferSpan = serverInfo.WaveBuffers.AsSpan(); WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount]; @@ -51,10 +51,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command WaveBuffers[i] = voiceWaveBuffer.ToCommon(1); } - AdpcmParameter = serverState.DataSourceStateAddressInfo.GetReference(true); - AdpcmParameterSize = serverState.DataSourceStateAddressInfo.Size; + AdpcmParameter = serverInfo.DataSourceStateAddressInfo.GetReference(true); + AdpcmParameterSize = serverInfo.DataSourceStateAddressInfo.Size; State = state; - DecodingBehaviour = serverState.DecodingBehaviour; + DecodingBehaviour = serverInfo.DecodingBehaviour; } public void Process(CommandList context) diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterAndMixCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterAndMixCommand.cs index 106fc0357..624c0d55b 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterAndMixCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterAndMixCommand.cs @@ -18,12 +18,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public ushort InputBufferIndex { get; } public ushort OutputBufferIndex { get; } - private BiquadFilterParameter _parameter; + private BiquadFilterParameter2 _parameter; public Memory BiquadFilterState { get; } public Memory PreviousBiquadFilterState { get; } - public Memory State { get; } + public Memory State { get; } public int LastSampleIndex { get; } @@ -40,8 +40,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, - Memory state, - ref BiquadFilterParameter filter, + Memory state, + ref BiquadFilterParameter2 filter, Memory biquadFilterState, Memory previousBiquadFilterState, bool needInitialization, diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs index ac1e581f6..a8c996428 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs @@ -19,11 +19,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public int OutputBufferIndex { get; } public bool NeedInitialization { get; } - private BiquadFilterParameter _parameter; + private BiquadFilterParameter2 _parameter; public BiquadFilterCommand( int baseIndex, - ref BiquadFilterParameter filter, + ref BiquadFilterParameter2 filter, Memory biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandList.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandList.cs index 185d169f0..9abd6a18a 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandList.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandList.cs @@ -129,7 +129,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command { startTime = PerformanceCounter.ElapsedNanoseconds; } - + command.Process(this); if (shouldMeter) diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandType.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandType.cs index de5c0ea2c..377eb6e57 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandType.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/CommandType.cs @@ -12,6 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command Volume, VolumeRamp, BiquadFilter, + BiquadFilterFloatCoeff, // new Mix, MixRamp, MixRampGrouped, @@ -31,9 +32,17 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command LimiterVersion1, LimiterVersion2, MultiTapBiquadFilter, + MultiTapBiquadFilterFloatCoeff, // new CaptureBuffer, Compressor, BiquadFilterAndMix, + BiquadFilterAndMixFloatCoeff, // new MultiTapBiquadFilterAndMix, + MultiTapBiquadFilterAndMixFloatCoef, // new + AuxiliaryBufferGrouped, // new + FillMixBuffer, // new + BiquadFilterCrossFade, // new + MultiTapBiquadFilterCrossFade, // new + FillBuffer, // new } } diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/DataSourceVersion2Command.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/DataSourceVersion2Command.cs index d3d3d2418..1fbd95c32 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/DataSourceVersion2Command.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/DataSourceVersion2Command.cs @@ -2,7 +2,7 @@ using Ryujinx.Audio.Common; using Ryujinx.Audio.Renderer.Common; using Ryujinx.Audio.Renderer.Server.Voice; using System; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; +using Ryujinx.Audio.Renderer.Parameter; using WaveBuffer = Ryujinx.Audio.Renderer.Common.WaveBuffer; namespace Ryujinx.Audio.Renderer.Dsp.Command @@ -24,7 +24,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public WaveBuffer[] WaveBuffers { get; } - public Memory State { get; } + public Memory State { get; } public ulong ExtraParameter { get; } public ulong ExtraParameterSize { get; } @@ -39,21 +39,21 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public SampleRateConversionQuality SrcQuality { get; } - public DataSourceVersion2Command(ref VoiceState serverState, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) + public DataSourceVersion2Command(ref VoiceInfo serverInfo, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) { Enabled = true; NodeId = nodeId; ChannelIndex = channelIndex; - ChannelCount = serverState.ChannelsCount; - SampleFormat = serverState.SampleFormat; - SrcQuality = serverState.SrcQuality; + ChannelCount = serverInfo.ChannelsCount; + SampleFormat = serverInfo.SampleFormat; + SrcQuality = serverInfo.SrcQuality; CommandType = GetCommandTypeBySampleFormat(SampleFormat); OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex); - SampleRate = serverState.SampleRate; - Pitch = serverState.Pitch; + SampleRate = serverInfo.SampleRate; + Pitch = serverInfo.Pitch; - Span waveBufferSpan = serverState.WaveBuffers.AsSpan(); + Span waveBufferSpan = serverInfo.WaveBuffers.AsSpan(); WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount]; @@ -66,12 +66,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command if (SampleFormat == SampleFormat.Adpcm) { - ExtraParameter = serverState.DataSourceStateAddressInfo.GetReference(true); - ExtraParameterSize = serverState.DataSourceStateAddressInfo.Size; + ExtraParameter = serverInfo.DataSourceStateAddressInfo.GetReference(true); + ExtraParameterSize = serverInfo.DataSourceStateAddressInfo.Size; } State = state; - DecodingBehaviour = serverState.DecodingBehaviour; + DecodingBehaviour = serverInfo.DecodingBehaviour; } private static CommandType GetCommandTypeBySampleFormat(SampleFormat sampleFormat) diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/DepopPrepareCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/DepopPrepareCommand.cs index a76f690e4..18ae11eb4 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/DepopPrepareCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/DepopPrepareCommand.cs @@ -17,10 +17,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public ushort[] OutputBufferIndices { get; } - public Memory State { get; } + public Memory State { get; } public Memory DepopBuffer { get; } - public DepopPrepareCommand(Memory state, Memory depopBuffer, uint mixBufferCount, uint bufferOffset, int nodeId, bool enabled) + public DepopPrepareCommand(Memory state, Memory depopBuffer, uint mixBufferCount, uint bufferOffset, int nodeId, bool enabled) { Enabled = enabled; NodeId = nodeId; @@ -39,7 +39,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public void Process(CommandList context) { - ref VoiceUpdateState state = ref State.Span[0]; + ref VoiceState state = ref State.Span[0]; Span depopBuffer = DepopBuffer.Span; Span lastSamplesSpan = state.LastSamples.AsSpan(); diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/DeviceSinkCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/DeviceSinkCommand.cs index 322c5d386..b0e4b3c99 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/DeviceSinkCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/DeviceSinkCommand.cs @@ -42,9 +42,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]); } - if (sink.UpsamplerState != null) + if (sink.UpsamplerInfo != null) { - Buffers = sink.UpsamplerState.OutputBuffer; + Buffers = sink.UpsamplerInfo.OutputBuffer; } else { diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/FillBufferCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/FillBufferCommand.cs new file mode 100644 index 000000000..ca5428c56 --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/FillBufferCommand.cs @@ -0,0 +1,69 @@ +using Ryujinx.Audio.Renderer.Server.Splitter; +using System; +using System.Runtime.CompilerServices; + +namespace Ryujinx.Audio.Renderer.Dsp.Command +{ + public class FillBufferCommand : ICommand + { + public bool Enabled { get; set; } + + public int NodeId { get; } + + public CommandType CommandType => CommandType.FillBuffer; + + public uint EstimatedProcessingTime { get; set; } + + public SplitterDestinationVersion1 Destination1 { get; } + public SplitterDestinationVersion2 Destination2 { get; } + public bool IsV2 { get; } + public int Length { get; } + public float Value { get; } + + public FillBufferCommand(SplitterDestinationVersion1 destination, int length, float value, int nodeId) + { + Enabled = true; + NodeId = nodeId; + + Destination1 = destination; + IsV2 = false; + Length = length; + Value = value; + } + + public FillBufferCommand(SplitterDestinationVersion2 destination, int length, float value, int nodeId) + { + Enabled = true; + NodeId = nodeId; + + Destination2 = destination; + IsV2 = true; + Length = length; + Value = value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ProcessFillBuffer() + { + if (IsV2) + { + for (int i = 0; i < Length; i++) + { + Destination2.PreviousMixBufferVolume[i] = Value; + } + } + else + { + for (int i = 0; i < Length; i++) + { + Destination1.PreviousMixBufferVolume[i] = Value; + } + } + } + + public void Process(CommandList context) + { + ProcessFillBuffer(); + } + } +} diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampCommand.cs index f77a233e1..6c5f7628c 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampCommand.cs @@ -20,11 +20,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public float Volume0 { get; } public float Volume1 { get; } - public Memory State { get; } + public Memory State { get; } public int LastSampleIndex { get; } - public MixRampCommand(float volume0, float volume1, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory state, int nodeId) + public MixRampCommand(float volume0, float volume1, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory state, int nodeId) { Enabled = true; NodeId = nodeId; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs index bc1f277ac..0d732c3fa 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public float[] Volume0 { get; } public float[] Volume1 { get; } - public Memory State { get; } + public Memory State { get; } public MixRampGroupedCommand( uint mixBufferCount, @@ -30,7 +30,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command uint outputBufferIndex, ReadOnlySpan volume0, ReadOnlySpan volume1, - Memory state, + Memory state, int nodeId) { Enabled = true; @@ -79,7 +79,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public void Process(CommandList context) { - ref VoiceUpdateState state = ref State.Span[0]; + ref VoiceState state = ref State.Span[0]; Span lastSamplesSpan = state.LastSamples.AsSpan(); diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterAndMixCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterAndMixCommand.cs index e359371b4..ee28ce2fb 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterAndMixCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterAndMixCommand.cs @@ -18,15 +18,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public ushort InputBufferIndex { get; } public ushort OutputBufferIndex { get; } - private BiquadFilterParameter _parameter0; - private BiquadFilterParameter _parameter1; + private BiquadFilterParameter2 _parameter0; + private BiquadFilterParameter2 _parameter1; public Memory BiquadFilterState0 { get; } public Memory BiquadFilterState1 { get; } public Memory PreviousBiquadFilterState0 { get; } public Memory PreviousBiquadFilterState1 { get; } - public Memory State { get; } + public Memory State { get; } public int LastSampleIndex { get; } @@ -44,9 +44,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, - Memory state, - ref BiquadFilterParameter filter0, - ref BiquadFilterParameter filter1, + Memory state, + ref BiquadFilterParameter2 filter0, + ref BiquadFilterParameter2 filter1, Memory biquadFilterState0, Memory biquadFilterState1, Memory previousBiquadFilterState0, diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterCommand.cs index e159f8ef7..84998056f 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/MultiTapBiquadFilterCommand.cs @@ -14,13 +14,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public uint EstimatedProcessingTime { get; set; } - private readonly BiquadFilterParameter[] _parameters; + private readonly BiquadFilterParameter2[] _parameters; private readonly Memory _biquadFilterStates; private readonly int _inputBufferIndex; private readonly int _outputBufferIndex; private readonly bool[] _isInitialized; - public MultiTapBiquadFilterCommand(int baseIndex, ReadOnlySpan filters, Memory biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan isInitialized, int nodeId) + public MultiTapBiquadFilterCommand(int baseIndex, ReadOnlySpan filters, Memory biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan isInitialized, int nodeId) { _parameters = filters.ToArray(); _biquadFilterStates = biquadFilterStateMemory; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/PcmFloatDataSourceCommandVersion1.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/PcmFloatDataSourceCommandVersion1.cs index 2b5f0de72..d54158541 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/PcmFloatDataSourceCommandVersion1.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/PcmFloatDataSourceCommandVersion1.cs @@ -2,7 +2,7 @@ using Ryujinx.Audio.Common; using Ryujinx.Audio.Renderer.Common; using Ryujinx.Audio.Renderer.Server.Voice; using System; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; +using Ryujinx.Audio.Renderer.Parameter; using WaveBuffer = Ryujinx.Audio.Renderer.Common.WaveBuffer; namespace Ryujinx.Audio.Renderer.Dsp.Command @@ -27,23 +27,23 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public WaveBuffer[] WaveBuffers { get; } - public Memory State { get; } + public Memory State { get; } public DecodingBehaviour DecodingBehaviour { get; } - public PcmFloatDataSourceCommandVersion1(ref VoiceState serverState, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) + public PcmFloatDataSourceCommandVersion1(ref VoiceInfo serverInfo, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) { Enabled = true; NodeId = nodeId; OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex); - SampleRate = serverState.SampleRate; + SampleRate = serverInfo.SampleRate; ChannelIndex = channelIndex; - ChannelCount = serverState.ChannelsCount; - Pitch = serverState.Pitch; + ChannelCount = serverInfo.ChannelsCount; + Pitch = serverInfo.Pitch; WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount]; - Span waveBufferSpan = serverState.WaveBuffers.AsSpan(); + Span waveBufferSpan = serverInfo.WaveBuffers.AsSpan(); for (int i = 0; i < WaveBuffers.Length; i++) { @@ -53,7 +53,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command } State = state; - DecodingBehaviour = serverState.DecodingBehaviour; + DecodingBehaviour = serverInfo.DecodingBehaviour; } public void Process(CommandList context) diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/PcmInt16DataSourceCommandVersion1.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/PcmInt16DataSourceCommandVersion1.cs index 9c30de41d..91619d80f 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/PcmInt16DataSourceCommandVersion1.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/PcmInt16DataSourceCommandVersion1.cs @@ -2,7 +2,7 @@ using Ryujinx.Audio.Common; using Ryujinx.Audio.Renderer.Common; using Ryujinx.Audio.Renderer.Server.Voice; using System; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; +using Ryujinx.Audio.Renderer.Parameter; using WaveBuffer = Ryujinx.Audio.Renderer.Common.WaveBuffer; namespace Ryujinx.Audio.Renderer.Dsp.Command @@ -27,23 +27,23 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public WaveBuffer[] WaveBuffers { get; } - public Memory State { get; } + public Memory State { get; } public DecodingBehaviour DecodingBehaviour { get; } - public PcmInt16DataSourceCommandVersion1(ref VoiceState serverState, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) + public PcmInt16DataSourceCommandVersion1(ref VoiceInfo serverInfo, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) { Enabled = true; NodeId = nodeId; OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex); - SampleRate = serverState.SampleRate; + SampleRate = serverInfo.SampleRate; ChannelIndex = channelIndex; - ChannelCount = serverState.ChannelsCount; - Pitch = serverState.Pitch; + ChannelCount = serverInfo.ChannelsCount; + Pitch = serverInfo.Pitch; WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount]; - Span waveBufferSpan = serverState.WaveBuffers.AsSpan(); + Span waveBufferSpan = serverInfo.WaveBuffers.AsSpan(); for (int i = 0; i < WaveBuffers.Length; i++) { @@ -53,7 +53,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command } State = state; - DecodingBehaviour = serverState.DecodingBehaviour; + DecodingBehaviour = serverInfo.DecodingBehaviour; } public void Process(CommandList context) diff --git a/src/Ryujinx.Audio/Renderer/Dsp/Command/UpsampleCommand.cs b/src/Ryujinx.Audio/Renderer/Dsp/Command/UpsampleCommand.cs index 8882500cd..5d23addae 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/Command/UpsampleCommand.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/Command/UpsampleCommand.cs @@ -18,11 +18,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public uint InputSampleCount { get; } public uint InputSampleRate { get; } - public UpsamplerState UpsamplerInfo { get; } + public UpsamplerInfo UpsamplerInfo { get; } public Memory OutBuffer { get; } - public UpsampleCommand(uint bufferOffset, UpsamplerState info, uint inputCount, Span inputBufferOffset, uint bufferCount, uint sampleCount, uint sampleRate, int nodeId) + public UpsampleCommand(uint bufferOffset, UpsamplerInfo info, uint inputCount, Span inputBufferOffset, uint bufferCount, uint sampleCount, uint sampleRate, int nodeId) { Enabled = true; NodeId = nodeId; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/DataSourceHelper.cs b/src/Ryujinx.Audio/Renderer/Dsp/DataSourceHelper.cs index 130836c6b..9e4e04890 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/DataSourceHelper.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/DataSourceHelper.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; +using Ryujinx.Audio.Renderer.Parameter; namespace Ryujinx.Audio.Renderer.Dsp { @@ -42,7 +42,7 @@ namespace Ryujinx.Audio.Renderer.Dsp }; } - public static void ProcessWaveBuffers(IVirtualMemoryManager memoryManager, Span outputBuffer, ref WaveBufferInformation info, Span wavebuffers, ref VoiceUpdateState voiceState, uint targetSampleRate, int sampleCount) + public static void ProcessWaveBuffers(IVirtualMemoryManager memoryManager, Span outputBuffer, ref WaveBufferInformation info, Span wavebuffers, ref VoiceState voiceState, uint targetSampleRate, int sampleCount) { const int TempBufferSize = 0x3F00; diff --git a/src/Ryujinx.Audio/Renderer/Dsp/ResamplerHelper.cs b/src/Ryujinx.Audio/Renderer/Dsp/ResamplerHelper.cs index 16048d7ff..0de34101e 100644 --- a/src/Ryujinx.Audio/Renderer/Dsp/ResamplerHelper.cs +++ b/src/Ryujinx.Audio/Renderer/Dsp/ResamplerHelper.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; +using Ryujinx.Audio.Renderer.Parameter; namespace Ryujinx.Audio.Renderer.Dsp { diff --git a/src/Ryujinx.Audio/Renderer/Parameter/AudioRendererConfiguration.cs b/src/Ryujinx.Audio/Renderer/Parameter/AudioRendererConfiguration.cs index 491a05c86..c70e16544 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/AudioRendererConfiguration.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/AudioRendererConfiguration.cs @@ -1,3 +1,4 @@ +using Ryujinx.Audio.Renderer.Server; using Ryujinx.Audio.Renderer.Server.Types; using System.Runtime.InteropServices; @@ -93,7 +94,7 @@ namespace Ryujinx.Audio.Renderer.Parameter /// /// The user audio revision /// - /// + /// public int Revision; } } diff --git a/src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter1.cs similarity index 95% rename from src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter.cs rename to src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter1.cs index f1492b0b1..5a3091f62 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter1.cs @@ -7,7 +7,7 @@ namespace Ryujinx.Audio.Renderer.Parameter /// Biquad filter parameters. /// [StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 1)] - public struct BiquadFilterParameter + public struct BiquadFilterParameter1 { /// /// Set to true if the biquad filter is active. diff --git a/src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter2.cs b/src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter2.cs new file mode 100644 index 000000000..8e47b22e0 --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter2.cs @@ -0,0 +1,36 @@ +using Ryujinx.Common.Memory; +using System.Runtime.InteropServices; + +namespace Ryujinx.Audio.Renderer.Parameter +{ + /// + /// Biquad filter parameters. + /// + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 1)] + public struct BiquadFilterParameter2 + { + /// + /// Set to true if the biquad filter is active. + /// + [MarshalAs(UnmanagedType.I1)] + public bool Enable; + + /// + /// Reserved/padding. + /// + private readonly byte _reserved1; + private readonly byte _reserved2; + private readonly byte _reserved3; + + /// + /// Biquad filter numerator (b0, b1, b2). + /// + public Array3 Numerator; + + /// + /// Biquad filter denominator (a1, a2). + /// + /// a0 = 1 + public Array2 Denominator; + } +} diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter1.cs similarity index 96% rename from src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter.cs rename to src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter1.cs index b12a941a5..443b257be 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter1.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Parameter.Effect /// for . /// [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct BiquadFilterEffectParameter + public struct BiquadFilterEffectParameter1 { /// /// The input channel indices that will be used by the . diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter2.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter2.cs new file mode 100644 index 000000000..0c74f1e7b --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter2.cs @@ -0,0 +1,49 @@ +using Ryujinx.Audio.Renderer.Server.Effect; +using Ryujinx.Common.Memory; +using System.Runtime.InteropServices; + +namespace Ryujinx.Audio.Renderer.Parameter.Effect +{ + /// + /// for . + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct BiquadFilterEffectParameter2 + { + /// + /// The input channel indices that will be used by the . + /// + public Array6 Input; + + /// + /// The output channel indices that will be used by the . + /// + public Array6 Output; + + /// + /// Biquad filter numerator (b0, b1, b2). + /// + public Array3 Numerator; + + /// + /// Biquad filter denominator (a1, a2). + /// + /// a0 = 1 + public Array2 Denominator; + + /// + /// The total channel count used. + /// + public byte ChannelCount; + + /// + /// The current usage status of the effect on the client side. + /// + public UsageState Status; + + /// + /// Reserved/unused. + /// + private readonly ushort _reserved; + } +} diff --git a/src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion3.cs b/src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion3.cs new file mode 100644 index 000000000..2cf4911a6 --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion3.cs @@ -0,0 +1,97 @@ +using Ryujinx.Audio.Renderer.Common; +using Ryujinx.Common.Utilities; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Audio.Renderer.Parameter +{ + /// + /// Input information for an effect version 2. (added with REV9) + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct EffectInParameterVersion3 : IEffectInParameter + { + /// + /// Type of the effect. + /// + public EffectType Type; + + /// + /// Set to true if the effect is new. + /// + [MarshalAs(UnmanagedType.I1)] + public bool IsNew; + + /// + /// Set to true if the effect must be active. + /// + [MarshalAs(UnmanagedType.I1)] + public bool IsEnabled; + + /// + /// Reserved/padding. + /// + private readonly byte _reserved1; + + /// + /// The target mix id of the effect. + /// + public int MixId; + + /// + /// Address of the processing workbuffer. + /// + /// This is additional data that could be required by the effect processing. + public ulong BufferBase; + + /// + /// Size of the processing workbuffer. + /// + /// This is additional data that could be required by the effect processing. + public ulong BufferSize; + + /// + /// Position of the effect while processing effects. + /// + public uint ProcessingOrder; + + /// + /// Reserved/padding. + /// + private readonly uint _reserved2; + + /// + /// Specific data storage. + /// + private SpecificDataStruct _specificDataStart; + + [StructLayout(LayoutKind.Sequential, Size = 0xA0, Pack = 1)] + private struct SpecificDataStruct { } + + public Span SpecificData => SpanHelpers.AsSpan(ref _specificDataStart); + + readonly EffectType IEffectInParameter.Type => Type; + + readonly bool IEffectInParameter.IsNew => IsNew; + + readonly bool IEffectInParameter.IsEnabled => IsEnabled; + + readonly int IEffectInParameter.MixId => MixId; + + readonly ulong IEffectInParameter.BufferBase => BufferBase; + + readonly ulong IEffectInParameter.BufferSize => BufferSize; + + readonly uint IEffectInParameter.ProcessingOrder => ProcessingOrder; + + /// + /// Check if the given channel count is valid. + /// + /// The channel count to check + /// Returns true if the channel count is valid. + public static bool IsChannelCountValid(int channelCount) + { + return channelCount is 1 or 2 or 4 or 6; + } + } +} diff --git a/src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs index 7ee49f11a..c3224c57d 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/ISplitterDestinationInParameter.cs @@ -17,11 +17,11 @@ namespace Ryujinx.Audio.Renderer.Parameter /// The mix to output the result of the splitter. /// int DestinationId { get; } - + /// /// Biquad filter parameters. /// - Array2 BiquadFilters { get; } + Array2 BiquadFilters2 { get; } /// /// Set to true if in use. diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SinkInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/SinkInParameter.cs index 3c1ac09c0..86ceea30a 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/SinkInParameter.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/SinkInParameter.cs @@ -25,7 +25,7 @@ namespace Ryujinx.Audio.Renderer.Parameter /// /// Reserved/padding. /// - private readonly ushort _reserved1; + private readonly ushort _magic; // 0xCAFE /// /// The node id of the sink. diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs index f346efcb0..fbc036806 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion1.cs @@ -60,8 +60,8 @@ namespace Ryujinx.Audio.Renderer.Parameter readonly int ISplitterDestinationInParameter.Id => Id; readonly int ISplitterDestinationInParameter.DestinationId => DestinationId; - - readonly Array2 ISplitterDestinationInParameter.BiquadFilters => default; + + readonly Array2 ISplitterDestinationInParameter.BiquadFilters2 => default; readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed; readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume; diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2a.cs b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2a.cs new file mode 100644 index 000000000..4270b5e20 --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2a.cs @@ -0,0 +1,100 @@ +using Ryujinx.Audio.Renderer.Dsp; +using Ryujinx.Common.Memory; +using Ryujinx.Common.Utilities; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Audio.Renderer.Parameter +{ + /// + /// Input header for a splitter destination version 2 update. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct SplitterDestinationInParameterVersion2a : ISplitterDestinationInParameter + { + /// + /// Magic of the input header. + /// + public uint Magic; + + /// + /// Target splitter destination data id. + /// + public int Id; + + /// + /// Mix buffer volumes storage. + /// + private MixArray _mixBufferVolume; + + /// + /// The mix to output the result of the splitter. + /// + public int DestinationId; + + /// + /// Biquad filter parameters. + /// + public Array2 BiquadFilters; + + /// + /// Set to true if in use. + /// + [MarshalAs(UnmanagedType.I1)] + public bool IsUsed; + + /// + /// Set to true to force resetting the previous mix volumes. + /// + [MarshalAs(UnmanagedType.I1)] + public bool ResetPrevVolume; + + /// + /// Reserved/padding. + /// + private unsafe fixed byte _reserved[10]; + + [StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)] + private struct MixArray { } + + /// + /// Mix buffer volumes. + /// + /// Used when a splitter id is specified in the mix. + public Span MixBufferVolume => SpanHelpers.AsSpan(ref _mixBufferVolume); + + readonly int ISplitterDestinationInParameter.Id => Id; + + readonly int ISplitterDestinationInParameter.DestinationId => DestinationId; + + readonly Array2 ISplitterDestinationInParameter.BiquadFilters2 + { + get + { + Array2 newFilters = new(); + Span newFiltersSpan = newFilters.AsSpan(); + newFiltersSpan[0] = BiquadFilterHelper.ToBiquadFilterParameter2(BiquadFilters[0]); + newFiltersSpan[1] = BiquadFilterHelper.ToBiquadFilterParameter2(BiquadFilters[1]); + + return newFilters; + } + } + + readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed; + readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume; + + /// + /// The expected constant of any input header. + /// + private const uint ValidMagic = 0x44444E53; + + /// + /// Check if the magic is valid. + /// + /// Returns true if the magic is valid. + public readonly bool IsMagicValid() + { + return Magic == ValidMagic; + } + } +} diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2b.cs similarity index 90% rename from src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs rename to src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2b.cs index 1d867919d..81e9d823b 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameterVersion2b.cs @@ -9,7 +9,7 @@ namespace Ryujinx.Audio.Renderer.Parameter /// Input header for a splitter destination version 2 update. /// [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct SplitterDestinationInParameterVersion2 : ISplitterDestinationInParameter + public struct SplitterDestinationInParameterVersion2b : ISplitterDestinationInParameter { /// /// Magic of the input header. @@ -34,7 +34,7 @@ namespace Ryujinx.Audio.Renderer.Parameter /// /// Biquad filter parameters. /// - public Array2 BiquadFilters; + public Array2 BiquadFilters; /// /// Set to true if in use. @@ -66,7 +66,7 @@ namespace Ryujinx.Audio.Renderer.Parameter readonly int ISplitterDestinationInParameter.DestinationId => DestinationId; - readonly Array2 ISplitterDestinationInParameter.BiquadFilters => BiquadFilters; + readonly Array2 ISplitterDestinationInParameter.BiquadFilters2 => BiquadFilters; readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed; readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume; diff --git a/src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter1.cs similarity index 98% rename from src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter.cs rename to src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter1.cs index f33d82aa0..a3633edbd 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter1.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Parameter /// Input information for a voice. /// [StructLayout(LayoutKind.Sequential, Size = 0x170, Pack = 1)] - public struct VoiceInParameter + public struct VoiceInParameter1 { /// /// Id of the voice. @@ -79,7 +79,7 @@ namespace Ryujinx.Audio.Renderer.Parameter /// /// Biquad filters to apply to the output of the voice. /// - public Array2 BiquadFilters; + public Array2 BiquadFilters; /// /// Total count of of the voice. @@ -171,8 +171,9 @@ namespace Ryujinx.Audio.Renderer.Parameter /// Reserved/unused. /// private unsafe fixed uint _reserved3[2]; - - /// + } + + /// /// Input information for a voice wavebuffer. /// [StructLayout(LayoutKind.Sequential, Size = 0x38, Pack = 1)] @@ -328,5 +329,4 @@ namespace Ryujinx.Audio.Renderer.Parameter /// Low, } - } } diff --git a/src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter2.cs b/src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter2.cs new file mode 100644 index 000000000..78e47b69a --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter2.cs @@ -0,0 +1,176 @@ +using Ryujinx.Audio.Common; +using Ryujinx.Audio.Renderer.Common; +using Ryujinx.Audio.Renderer.Dsp; +using Ryujinx.Common.Memory; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Audio.Renderer.Parameter +{ + /// + /// Input information for a voice. + /// + [StructLayout(LayoutKind.Sequential, Size = 0x188, Pack = 1)] + public struct VoiceInParameter2 + { + /// + /// Id of the voice. + /// + public int Id; + + /// + /// Node id of the voice. + /// + public int NodeId; + + /// + /// Set to true if the voice is new. + /// + [MarshalAs(UnmanagedType.I1)] + public bool IsNew; + + /// + /// Set to true if the voice is used. + /// + [MarshalAs(UnmanagedType.I1)] + public bool InUse; + + /// + /// The voice wanted by the user. + /// + public PlayState PlayState; + + /// + /// The of the voice. + /// + public SampleFormat SampleFormat; + + /// + /// The sample rate of the voice. + /// + public uint SampleRate; + + /// + /// The priority of the voice. + /// + public uint Priority; + + /// + /// Target sorting position of the voice. (Used to sort voices with the same ) + /// + public uint SortingOrder; + + /// + /// The total channel count used. + /// + public uint ChannelCount; + + /// + /// The pitch used on the voice. + /// + public float Pitch; + + /// + /// The output volume of the voice. + /// + public float Volume; + + /// + /// Biquad filters to apply to the output of the voice. + /// + public Array2 BiquadFilters; + + /// + /// Total count of of the voice. + /// + public uint WaveBuffersCount; + + /// + /// Current playing of the voice. + /// + public uint WaveBuffersIndex; + + /// + /// Reserved/unused. + /// + private readonly uint + _reserved1; + + /// + /// User state address required by the data source. + /// + /// Only used for as the address of the GC-ADPCM coefficients. + public ulong DataSourceStateAddress; + + /// + /// User state size required by the data source. + /// + /// Only used for as the size of the GC-ADPCM coefficients. + public ulong DataSourceStateSize; + + /// + /// The target mix id of the voice. + /// + public int MixId; + + /// + /// The target splitter id of the voice. + /// + public uint SplitterId; + + /// + /// The wavebuffer parameters of this voice. + /// + public Array4 WaveBuffers; + + /// + /// The channel resource ids associated to the voice. + /// + public Array6 ChannelResourceIds; + + /// + /// Reset the voice drop flag during voice server update. + /// + [MarshalAs(UnmanagedType.I1)] + public bool ResetVoiceDropFlag; + + /// + /// Flush the amount of wavebuffer specified. This will result in the wavebuffer being skipped and marked played. + /// + /// This was added on REV5. + public byte FlushWaveBufferCount; + + /// + /// Reserved/unused. + /// + private readonly ushort _reserved2; + + /// + /// Change the behaviour of the voice. + /// + /// This was added on REV5. + public DecodingBehaviour DecodingBehaviourFlags; + + /// + /// Change the Sample Rate Conversion (SRC) quality of the voice. + /// + /// This was added on REV8. + public SampleRateConversionQuality SrcQuality; + + /// + /// This was previously used for opus codec support on the Audio Renderer and was removed on REV3. + /// + public uint ExternalContext; + + /// + /// This was previously used for opus codec support on the Audio Renderer and was removed on REV3. + /// + public uint ExternalContextSize; + + /// + /// Reserved/unused. + /// + private unsafe fixed uint _reserved3[2]; + } +} diff --git a/src/Ryujinx.Audio/Renderer/Parameter/VoiceOutStatus.cs b/src/Ryujinx.Audio/Renderer/Parameter/VoiceOutStatus.cs index a7c749835..0ec864cdc 100644 --- a/src/Ryujinx.Audio/Renderer/Parameter/VoiceOutStatus.cs +++ b/src/Ryujinx.Audio/Renderer/Parameter/VoiceOutStatus.cs @@ -1,3 +1,5 @@ +using Ryujinx.Audio.Renderer.Common; +using Ryujinx.Audio.Renderer.Server; using System.Runtime.InteropServices; namespace Ryujinx.Audio.Renderer.Parameter @@ -5,7 +7,7 @@ namespace Ryujinx.Audio.Renderer.Parameter /// /// Output information about a voice. /// - /// See + /// See [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct VoiceOutStatus { @@ -13,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Parameter /// The total amount of samples that was played. /// /// This is reset to 0 when a finishes playing and is set. - /// This is reset to 0 when looping while is set. + /// This is reset to 0 when looping while is set. public ulong PlayedSampleCount; /// diff --git a/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs b/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs index ee2f23479..188af8640 100644 --- a/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs +++ b/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs @@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Renderer.Server private AudioRendererRenderingDevice _renderingDevice; private AudioRendererExecutionMode _executionMode; private readonly IWritableEvent _systemEvent; - private MemoryPoolState _dspMemoryPoolState; + private MemoryPoolInfo _dspMemoryPoolInfo; private readonly VoiceContext _voiceContext; private readonly MixContext _mixContext; private readonly SinkContext _sinkContext; @@ -40,13 +40,13 @@ namespace Ryujinx.Audio.Renderer.Server private PerformanceManager _performanceManager; private UpsamplerManager _upsamplerManager; private bool _isActive; - private BehaviourContext _behaviourContext; + private BehaviourInfo _behaviourInfo; #pragma warning disable IDE0052 // Remove unread private member private ulong _totalElapsedTicksUpdating; private ulong _totalElapsedTicks; #pragma warning restore IDE0052 private int _sessionId; - private Memory _memoryPools; + private Memory _memoryPools; private uint _sampleRate; private uint _sampleCount; @@ -84,7 +84,7 @@ namespace Ryujinx.Audio.Renderer.Server public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent) { _manager = manager; - _dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp); + _dspMemoryPoolInfo = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Dsp); _voiceContext = new VoiceContext(); _mixContext = new MixContext(); _sinkContext = new SinkContext(); @@ -93,7 +93,7 @@ namespace Ryujinx.Audio.Renderer.Server _commandProcessingTimeEstimator = null; _systemEvent = systemEvent; - _behaviourContext = new BehaviourContext(); + _behaviourInfo = new BehaviourInfo(); _totalElapsedTicksUpdating = 0; _sessionId = 0; @@ -110,7 +110,7 @@ namespace Ryujinx.Audio.Renderer.Server ulong appletResourceId, IVirtualMemoryManager memoryManager) { - if (!BehaviourContext.CheckValidRevision(parameter.Revision)) + if (!BehaviourInfo.CheckValidRevision(parameter.Revision)) { return ResultCode.OperationFailed; } @@ -122,9 +122,9 @@ namespace Ryujinx.Audio.Renderer.Server Debug.Assert(parameter.RenderingDevice == AudioRendererRenderingDevice.Dsp && parameter.ExecutionMode == AudioRendererExecutionMode.Auto); - Logger.Info?.Print(LogClass.AudioRenderer, $"Initializing with REV{BehaviourContext.GetRevisionNumber(parameter.Revision)}"); + Logger.Info?.Print(LogClass.AudioRenderer, $"Initializing with REV{BehaviourInfo.GetRevisionNumber(parameter.Revision)}"); - _behaviourContext.SetUserRevision(parameter.Revision); + _behaviourInfo.SetUserRevision(parameter.Revision); _sampleRate = parameter.SampleRate; _sampleCount = parameter.SampleCount; @@ -151,7 +151,7 @@ namespace Ryujinx.Audio.Renderer.Server workBufferAllocator = new WorkBufferAllocator(workBufferMemory); PoolMapper poolMapper = new(processHandle, false); - poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize); + poolMapper.InitializeSystemPool(ref _dspMemoryPoolInfo, workBuffer, workBufferSize); _mixBuffer = workBufferAllocator.Allocate(_sampleCount * (_voiceChannelCountMax + _mixBufferCount), 0x10); @@ -176,7 +176,7 @@ namespace Ryujinx.Audio.Renderer.Server Memory splitterBqfStates = Memory.Empty; - if (_behaviourContext.IsBiquadFilterParameterForSplitterEnabled() && + if (_behaviourInfo.IsBiquadFilterParameterForSplitterEnabled() && parameter.SplitterCount > 0 && parameter.SplitterDestinationCount > 0) { @@ -191,23 +191,23 @@ namespace Ryujinx.Audio.Renderer.Server } // Invalidate DSP cache on what was currently allocated with workBuffer. - AudioProcessorMemoryManager.InvalidateDspCache(_dspMemoryPoolState.Translate(workBuffer, workBufferAllocator.Offset), workBufferAllocator.Offset); + AudioProcessorMemoryManager.InvalidateDspCache(_dspMemoryPoolInfo.Translate(workBuffer, workBufferAllocator.Offset), workBufferAllocator.Offset); Debug.Assert((workBufferAllocator.Offset % Constants.BufferAlignment) == 0); - Memory voices = workBufferAllocator.Allocate(parameter.VoiceCount, VoiceState.Alignment); + Memory voices = workBufferAllocator.Allocate(parameter.VoiceCount, VoiceInfo.Alignment); if (voices.IsEmpty) { return ResultCode.WorkBufferTooSmall; } - foreach (ref VoiceState voice in voices.Span) + foreach (ref VoiceInfo voice in voices.Span) { voice.Initialize(); } - // A pain to handle as we can't have VoiceState*, use indices to be a bit more safe + // A pain to handle as we can't have VoiceInfo*, use indices to be a bit more safe Memory sortedVoices = workBufferAllocator.Allocate(parameter.VoiceCount, 0x10); if (sortedVoices.IsEmpty) @@ -233,16 +233,16 @@ namespace Ryujinx.Audio.Renderer.Server voiceChannelResource.IsUsed = false; } - Memory voiceUpdateStates = workBufferAllocator.Allocate(parameter.VoiceCount, VoiceUpdateState.Align); + Memory voiceStates = workBufferAllocator.Allocate(parameter.VoiceCount, VoiceState.Align); - if (voiceUpdateStates.IsEmpty) + if (voiceStates.IsEmpty) { return ResultCode.WorkBufferTooSmall; } uint mixesCount = parameter.SubMixBufferCount + 1; - Memory mixes = workBufferAllocator.Allocate(mixesCount, MixState.Alignment); + Memory mixes = workBufferAllocator.Allocate(mixesCount, MixInfo.Alignment); if (mixes.IsEmpty) { @@ -251,18 +251,18 @@ namespace Ryujinx.Audio.Renderer.Server if (parameter.EffectCount == 0) { - foreach (ref MixState mix in mixes.Span) + foreach (ref MixInfo mix in mixes.Span) { - mix = new MixState(Memory.Empty, ref _behaviourContext); + mix = new MixInfo(Memory.Empty, ref _behaviourInfo); } } else { Memory effectProcessingOrderArray = workBufferAllocator.Allocate(parameter.EffectCount * mixesCount, 0x10); - foreach (ref MixState mix in mixes.Span) + foreach (ref MixInfo mix in mixes.Span) { - mix = new MixState(effectProcessingOrderArray[..(int)parameter.EffectCount], ref _behaviourContext); + mix = new MixInfo(effectProcessingOrderArray[..(int)parameter.EffectCount], ref _behaviourInfo); effectProcessingOrderArray = effectProcessingOrderArray[(int)parameter.EffectCount..]; } @@ -271,20 +271,20 @@ namespace Ryujinx.Audio.Renderer.Server // Initialize the final mix id mixes.Span[0].MixId = Constants.FinalMixId; - Memory sortedMixesState = workBufferAllocator.Allocate(mixesCount, 0x10); + Memory sortedMixesInfo = workBufferAllocator.Allocate(mixesCount, 0x10); - if (sortedMixesState.IsEmpty) + if (sortedMixesInfo.IsEmpty) { return ResultCode.WorkBufferTooSmall; } // Clear memory (use -1 as it's an invalid index) - sortedMixesState.Span.Fill(-1); + sortedMixesInfo.Span.Fill(-1); Memory nodeStatesWorkBuffer = Memory.Empty; Memory edgeMatrixWorkBuffer = Memory.Empty; - if (_behaviourContext.IsSplitterSupported()) + if (_behaviourInfo.IsSplitterSupported()) { nodeStatesWorkBuffer = workBufferAllocator.Allocate((uint)NodeStates.GetWorkBufferSize((int)mixesCount), 1); edgeMatrixWorkBuffer = workBufferAllocator.Allocate((uint)EdgeMatrix.GetWorkBufferSize((int)mixesCount), 1); @@ -295,21 +295,21 @@ namespace Ryujinx.Audio.Renderer.Server } } - _mixContext.Initialize(sortedMixesState, mixes, nodeStatesWorkBuffer, edgeMatrixWorkBuffer); + _mixContext.Initialize(sortedMixesInfo, mixes, nodeStatesWorkBuffer, edgeMatrixWorkBuffer); - _memoryPools = workBufferAllocator.Allocate(_memoryPoolCount, MemoryPoolState.Alignment); + _memoryPools = workBufferAllocator.Allocate(_memoryPoolCount, MemoryPoolInfo.Alignment); if (_memoryPools.IsEmpty) { return ResultCode.WorkBufferTooSmall; } - foreach (ref MemoryPoolState state in _memoryPools.Span) + foreach (ref MemoryPoolInfo info in _memoryPools.Span) { - state = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); + info = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Cpu); } - if (!_splitterContext.Initialize(ref _behaviourContext, ref parameter, workBufferAllocator, splitterBqfStates)) + if (!_splitterContext.Initialize(ref _behaviourInfo, ref parameter, workBufferAllocator, splitterBqfStates)) { return ResultCode.WorkBufferTooSmall; } @@ -318,21 +318,21 @@ namespace Ryujinx.Audio.Renderer.Server _upsamplerManager = new UpsamplerManager(upSamplerWorkBuffer, _upsamplerCount); - _effectContext.Initialize(parameter.EffectCount, _behaviourContext.IsEffectInfoVersion2Supported() ? parameter.EffectCount : 0); + _effectContext.Initialize(parameter.EffectCount, _behaviourInfo.IsEffectInfoVersion2Supported() ? parameter.EffectCount : 0); _sinkContext.Initialize(parameter.SinkCount); - Memory voiceUpdateStatesDsp = workBufferAllocator.Allocate(parameter.VoiceCount, VoiceUpdateState.Align); + Memory voiceStatesDsp = workBufferAllocator.Allocate(parameter.VoiceCount, VoiceState.Align); - if (voiceUpdateStatesDsp.IsEmpty) + if (voiceStatesDsp.IsEmpty) { return ResultCode.WorkBufferTooSmall; } - _voiceContext.Initialize(sortedVoices, voices, voiceChannelResources, voiceUpdateStates, voiceUpdateStatesDsp, parameter.VoiceCount); + _voiceContext.Initialize(sortedVoices, voices, voiceChannelResources, voiceStates, voiceStatesDsp, parameter.VoiceCount); if (parameter.PerformanceMetricFramesCount > 0) { - ulong performanceBufferSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref _behaviourContext) * (parameter.PerformanceMetricFramesCount + 1) + 0xC; + ulong performanceBufferSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref _behaviourInfo) * (parameter.PerformanceMetricFramesCount + 1) + 0xC; _performanceBuffer = workBufferAllocator.Allocate(performanceBufferSize, Constants.BufferAlignment); @@ -341,7 +341,7 @@ namespace Ryujinx.Audio.Renderer.Server return ResultCode.WorkBufferTooSmall; } - _performanceManager = PerformanceManager.Create(_performanceBuffer, ref parameter, _behaviourContext); + _performanceManager = PerformanceManager.Create(_performanceBuffer, ref parameter, _behaviourInfo); } else { @@ -359,14 +359,14 @@ namespace Ryujinx.Audio.Renderer.Server _elapsedFrameCount = 0; _voiceDropParameter = 1.0f; - _commandProcessingTimeEstimator = _behaviourContext.GetCommandProcessingTimeEstimatorVersion() switch + _commandProcessingTimeEstimator = _behaviourInfo.GetCommandProcessingTimeEstimatorVersion() switch { 1 => new CommandProcessingTimeEstimatorVersion1(_sampleCount, _mixBufferCount), 2 => new CommandProcessingTimeEstimatorVersion2(_sampleCount, _mixBufferCount), 3 => new CommandProcessingTimeEstimatorVersion3(_sampleCount, _mixBufferCount), 4 => new CommandProcessingTimeEstimatorVersion4(_sampleCount, _mixBufferCount), 5 => new CommandProcessingTimeEstimatorVersion5(_sampleCount, _mixBufferCount), - _ => throw new NotImplementedException($"Unsupported processing time estimator version {_behaviourContext.GetCommandProcessingTimeEstimatorVersion()}."), + _ => throw new NotImplementedException($"Unsupported processing time estimator version {_behaviourInfo.GetCommandProcessingTimeEstimatorVersion()}."), }; return ResultCode.Success; @@ -411,11 +411,11 @@ namespace Ryujinx.Audio.Renderer.Server output.Span.Clear(); - StateUpdater stateUpdater = new(input, output, _processHandle, _behaviourContext); + StateUpdater stateUpdater = new(input, output, _processHandle, _behaviourInfo); ResultCode result; - result = stateUpdater.UpdateBehaviourContext(); + result = stateUpdater.UpdateBehaviourInfo(); if (result != ResultCode.Success) { @@ -436,9 +436,16 @@ namespace Ryujinx.Audio.Renderer.Server return result; } - PoolMapper poolMapper = new(_processHandle, _memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); + PoolMapper poolMapper = new(_processHandle, _memoryPools, _behaviourInfo.IsMemoryPoolForceMappingEnabled()); - result = stateUpdater.UpdateVoices(_voiceContext, poolMapper); + if (_behaviourInfo.IsBiquadFilterParameterFloatSupported()) + { + result = stateUpdater.UpdateVoices2(_voiceContext, poolMapper); + } + else + { + result = stateUpdater.UpdateVoices1(_voiceContext, poolMapper); + } if (result != ResultCode.Success) { @@ -452,7 +459,7 @@ namespace Ryujinx.Audio.Renderer.Server return result; } - if (_behaviourContext.IsSplitterSupported()) + if (_behaviourInfo.IsSplitterSupported()) { result = stateUpdater.UpdateSplitter(_splitterContext); @@ -490,7 +497,7 @@ namespace Ryujinx.Audio.Renderer.Server return result; } - if (_behaviourContext.IsElapsedFrameCountSupported()) + if (_behaviourInfo.IsElapsedFrameCountSupported()) { result = stateUpdater.UpdateRendererInfo(_elapsedFrameCount); @@ -557,7 +564,7 @@ namespace Ryujinx.Audio.Renderer.Server break; } - ref VoiceState voice = ref _voiceContext.GetState(NodeIdHelper.GetBase(targetNodeId)); + ref VoiceInfo voice = ref _voiceContext.GetState(NodeIdHelper.GetBase(targetNodeId)); if (voice.Priority == Constants.VoiceHighestPriority) { @@ -646,7 +653,7 @@ namespace Ryujinx.Audio.Renderer.Server _voiceContext.UpdateForCommandGeneration(); - if (_behaviourContext.IsEffectInfoVersion2Supported()) + if (_behaviourInfo.IsEffectInfoVersion2Supported()) { _effectContext.UpdateResultStateForCommandGeneration(); } @@ -661,7 +668,7 @@ namespace Ryujinx.Audio.Renderer.Server private int GetMaxAllocatedTimeForDsp() { - return (int)(Constants.AudioProcessorMaxUpdateTimePerSessions * _behaviourContext.GetAudioRendererProcessingTimeLimit() * (GetRenderingTimeLimit() / 100.0f)); + return (int)(Constants.AudioProcessorMaxUpdateTimePerSessions * _behaviourInfo.GetAudioRendererProcessingTimeLimit() * (GetRenderingTimeLimit() / 100.0f)); } public void SendCommands() @@ -736,7 +743,7 @@ namespace Ryujinx.Audio.Renderer.Server return new RendererSystemContext { ChannelCount = _manager.Processor.OutputDevices[_sessionId].GetChannelCount(), - BehaviourContext = _behaviourContext, + BehaviourInfo = _behaviourInfo, DepopBuffer = _depopBuffer, MixBufferCount = GetMixBufferCount(), SessionId = _sessionId, @@ -751,9 +758,9 @@ namespace Ryujinx.Audio.Renderer.Server public static ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter) { - BehaviourContext behaviourContext = new(); + BehaviourInfo behaviourInfo = new(); - behaviourContext.SetUserRevision(parameter.Revision); + behaviourInfo.SetUserRevision(parameter.Revision); uint mixesCount = parameter.SubMixBufferCount + 1; @@ -771,28 +778,28 @@ namespace Ryujinx.Audio.Renderer.Server size = WorkBufferAllocator.GetTargetSize(size, BitUtils.AlignUp(parameter.MixBufferCount, Constants.BufferAlignment), Constants.BufferAlignment); // Voice - size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, VoiceState.Alignment); + size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, VoiceInfo.Alignment); size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, 0x10); size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, VoiceChannelResource.Alignment); - size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, VoiceUpdateState.Align); + size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, VoiceState.Align); // Mix - size = WorkBufferAllocator.GetTargetSize(size, mixesCount, MixState.Alignment); + size = WorkBufferAllocator.GetTargetSize(size, mixesCount, MixInfo.Alignment); size = WorkBufferAllocator.GetTargetSize(size, parameter.EffectCount * mixesCount, 0x10); size = WorkBufferAllocator.GetTargetSize(size, mixesCount, 0x10); - if (behaviourContext.IsSplitterSupported()) + if (behaviourInfo.IsSplitterSupported()) { size += (ulong)BitUtils.AlignUp(NodeStates.GetWorkBufferSize((int)mixesCount) + EdgeMatrix.GetWorkBufferSize((int)mixesCount), 0x10); } // Memory Pool - size = WorkBufferAllocator.GetTargetSize(size, memoryPoolCount, MemoryPoolState.Alignment); + size = WorkBufferAllocator.GetTargetSize(size, memoryPoolCount, MemoryPoolInfo.Alignment); // Splitter - size = SplitterContext.GetWorkBufferSize(size, ref behaviourContext, ref parameter); + size = SplitterContext.GetWorkBufferSize(size, ref behaviourInfo, ref parameter); - if (behaviourContext.IsBiquadFilterParameterForSplitterEnabled() && + if (behaviourInfo.IsBiquadFilterParameterForSplitterEnabled() && parameter.SplitterCount > 0 && parameter.SplitterDestinationCount > 0) { @@ -800,12 +807,12 @@ namespace Ryujinx.Audio.Renderer.Server } // DSP Voice - size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, VoiceUpdateState.Align); + size = WorkBufferAllocator.GetTargetSize(size, parameter.VoiceCount, VoiceState.Align); // Performance if (parameter.PerformanceMetricFramesCount > 0) { - ulong performanceMetricsPerFramesSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref behaviourContext) * (parameter.PerformanceMetricFramesCount + 1) + 0xC; + ulong performanceMetricsPerFramesSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref behaviourInfo) * (parameter.PerformanceMetricFramesCount + 1) + 0xC; size += BitUtils.AlignUp(performanceMetricsPerFramesSize, Constants.PerformanceMetricsPerFramesSizeAlignment); } @@ -847,13 +854,13 @@ namespace Ryujinx.Audio.Renderer.Server } PoolMapper mapper = new(_processHandle, false); - mapper.Unmap(ref _dspMemoryPoolState); + mapper.Unmap(ref _dspMemoryPoolInfo); PoolMapper.ClearUsageState(_memoryPools); for (int i = 0; i < _memoryPoolCount; i++) { - ref MemoryPoolState memoryPool = ref _memoryPools.Span[i]; + ref MemoryPoolInfo memoryPool = ref _memoryPools.Span[i]; if (memoryPool.IsMapped()) { @@ -875,7 +882,7 @@ namespace Ryujinx.Audio.Renderer.Server public void SetVoiceDropParameter(float voiceDropParameter) { - _voiceDropParameter = Math.Clamp(voiceDropParameter, 0.0f, 2.0f); + _voiceDropParameter = Math.Clamp(voiceDropParameter, 0.0f, 4.0f); } public float GetVoiceDropParameter() diff --git a/src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs b/src/Ryujinx.Audio/Renderer/Server/BehaviourInfo.cs similarity index 89% rename from src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs rename to src/Ryujinx.Audio/Renderer/Server/BehaviourInfo.cs index f725eb9f3..04463e876 100644 --- a/src/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs +++ b/src/Ryujinx.Audio/Renderer/Server/BehaviourInfo.cs @@ -1,3 +1,5 @@ +using Ryujinx.Audio.Renderer.Parameter; +using Ryujinx.Common.Memory; using System; using System.Buffers; using System.Diagnostics; @@ -9,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Server /// Behaviour context. /// /// This handles features based on the audio renderer revision provided by the user. - public class BehaviourContext + public class BehaviourInfo { /// /// The base magic of the Audio Renderer revision. @@ -40,7 +42,7 @@ namespace Ryujinx.Audio.Renderer.Server public const int Revision4 = 4 << 24; /// - /// REV5: , were added to voice. + /// REV5: , were added to voice. /// A new performance frame format (version 2) was added with support for more information about DSP timing. /// was added to supply the count of update done sent to the DSP. /// A new version of the command estimator was added to address timing changes caused by the voice changes. @@ -64,7 +66,7 @@ namespace Ryujinx.Audio.Renderer.Server /// /// REV8: /// Wavebuffer was changed to support more control over loop (you can now specify where to start and end a loop, and how many times to loop). - /// was added (see for more info). + /// was added (see for more info). /// Final leftovers of the codec system were removed. /// support was added. /// A new version of the command estimator was added to address timing changes caused by the voice and command changes. @@ -115,16 +117,27 @@ namespace Ryujinx.Audio.Renderer.Server /// /// This was added in system update 18.0.0 public const int Revision13 = 13 << 24; + + /// + /// REV14: + /// Fixes the Depop Bug. + /// + /// + /// This was added in system update 19.0.0 + public const int Revision14 = 14 << 24; + + /// + /// REV15: + /// Support for float coefficients in biquad filters + /// + /// + /// This was added in system update 19.0.0 + public const int Revision15 = 15 << 24; /// /// Last revision supported by the implementation. /// - public const int LastRevision = Revision13; - - /// - /// Target revision magic supported by the implementation. - /// - public const int ProcessRevision = BaseRevisionMagic + LastRevision; + public const int LastRevision = Revision15; /// /// Get the revision number from the revision magic. @@ -133,15 +146,25 @@ namespace Ryujinx.Audio.Renderer.Server /// The revision number. public static int GetRevisionNumber(int revision) => (revision - BaseRevisionMagic) >> 24; + /// + /// Target revision magic supported by the implementation. + /// + public const int ProcessRevision = BaseRevisionMagic + LastRevision; + /// /// Current active revision. /// public int UserRevision { get; private set; } + + /// + /// Current flags of the . + /// + private ulong _flags; /// /// Error storage. /// - private readonly ErrorInfo[] _errorInfos; + private readonly Array10 _errorInfos; /// /// Current position in the array. @@ -149,17 +172,12 @@ namespace Ryujinx.Audio.Renderer.Server private uint _errorIndex; /// - /// Current flags of the . + /// Create a new instance of . /// - private ulong _flags; - - /// - /// Create a new instance of . - /// - public BehaviourContext() + public BehaviourInfo() { UserRevision = 0; - _errorInfos = new ErrorInfo[Constants.MaxErrorInfos]; + _errorInfos = new Array10(); _errorIndex = 0; } @@ -173,7 +191,7 @@ namespace Ryujinx.Audio.Renderer.Server } /// - /// Update flags of the . + /// Update flags of the . /// /// The new flags. public void UpdateFlags(ulong flags) @@ -321,9 +339,9 @@ namespace Ryujinx.Audio.Renderer.Server } /// - /// Check if the audio renderer should support . + /// Check if the audio renderer should support . /// - /// True if the audio renderer should support . + /// True if the audio renderer should support . public bool IsDecodingBehaviourFlagSupported() { return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5); @@ -400,6 +418,24 @@ namespace Ryujinx.Audio.Renderer.Server { return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision13); } + + /// + /// Check if the audio renderer should support the depop bug fix. + /// + /// True if the audio renderer supports the depop bug fix + public bool IsSplitterDepopBugFixEnabled() + { + return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision14); + } + + /// + /// Check if the audio renderer should support biquad filter with float coefficients. + /// + /// True if the audio renderer support biquad filter with float coefficients + public bool IsBiquadFilterParameterFloatSupported() + { + return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision15); + } /// /// Get the version of the . @@ -440,7 +476,7 @@ namespace Ryujinx.Audio.Renderer.Server if (_errorIndex <= Constants.MaxErrorInfos - 1) { - _errorInfos[_errorIndex++] = errorInfo; + _errorInfos[(int)_errorIndex++] = errorInfo; } } @@ -457,22 +493,8 @@ namespace Ryujinx.Audio.Renderer.Server } errorCount = Math.Min(_errorIndex, Constants.MaxErrorInfos); - - for (int i = 0; i < Constants.MaxErrorInfos; i++) - { - if (i < errorCount) - { - errorInfos[i] = _errorInfos[i]; - } - else - { - errorInfos[i] = new ErrorInfo - { - ErrorCode = 0, - ExtraErrorInfo = 0, - }; - } - } + + _errorInfos.AsSpan().CopyTo(errorInfos); } /// diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs b/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs index d65897e45..62380f926 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs @@ -5,9 +5,11 @@ using Ryujinx.Audio.Renderer.Parameter; using Ryujinx.Audio.Renderer.Parameter.Effect; using Ryujinx.Audio.Renderer.Server.Performance; using Ryujinx.Audio.Renderer.Server.Sink; +using Ryujinx.Audio.Renderer.Server.Splitter; using Ryujinx.Audio.Renderer.Server.Upsampler; using Ryujinx.Audio.Renderer.Server.Voice; using System; +using System.Runtime.CompilerServices; using CpuAddress = System.UInt64; namespace Ryujinx.Audio.Renderer.Server @@ -77,7 +79,7 @@ namespace Ryujinx.Audio.Renderer.Server /// The target buffer offset. /// The node id associated to this command. /// Set to true if the voice was playing previously. - public void GenerateDepopPrepare(Memory state, Memory depopBuffer, uint bufferCount, uint bufferOffset, int nodeId, bool wasPlaying) + public void GenerateDepopPrepare(Memory state, Memory depopBuffer, uint bufferCount, uint bufferOffset, int nodeId, bool wasPlaying) { DepopPrepareCommand command = new(state, depopBuffer, bufferCount, bufferOffset, nodeId, wasPlaying); @@ -120,14 +122,14 @@ namespace Ryujinx.Audio.Renderer.Server /// /// Create a new . /// - /// The to generate the command from. - /// The to generate the command from. + /// The to generate the command from. + /// The to generate the command from. /// The output buffer index to use. /// The target channel index. /// The node id associated to this command. - public void GenerateDataSourceVersion2(ref VoiceState voiceState, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) + public void GenerateDataSourceVersion2(ref VoiceInfo voiceInfo, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) { - DataSourceVersion2Command command = new(ref voiceState, state, outputBufferIndex, channelIndex, nodeId); + DataSourceVersion2Command command = new(ref voiceInfo, state, outputBufferIndex, channelIndex, nodeId); command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); @@ -137,14 +139,14 @@ namespace Ryujinx.Audio.Renderer.Server /// /// Create a new . /// - /// The to generate the command from. - /// The to generate the command from. + /// The to generate the command from. + /// The to generate the command from. /// The output buffer index to use. /// The target channel index. /// The node id associated to this command. - public void GeneratePcmInt16DataSourceVersion1(ref VoiceState voiceState, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) + public void GeneratePcmInt16DataSourceVersion1(ref VoiceInfo voiceInfo, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) { - PcmInt16DataSourceCommandVersion1 command = new(ref voiceState, state, outputBufferIndex, channelIndex, nodeId); + PcmInt16DataSourceCommandVersion1 command = new(ref voiceInfo, state, outputBufferIndex, channelIndex, nodeId); command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); @@ -154,14 +156,14 @@ namespace Ryujinx.Audio.Renderer.Server /// /// Create a new . /// - /// The to generate the command from. - /// The to generate the command from. + /// The to generate the command from. + /// The to generate the command from. /// The output buffer index to use. /// The target channel index. /// The node id associated to this command. - public void GeneratePcmFloatDataSourceVersion1(ref VoiceState voiceState, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) + public void GeneratePcmFloatDataSourceVersion1(ref VoiceInfo voiceInfo, Memory state, ushort outputBufferIndex, ushort channelIndex, int nodeId) { - PcmFloatDataSourceCommandVersion1 command = new(ref voiceState, state, outputBufferIndex, channelIndex, nodeId); + PcmFloatDataSourceCommandVersion1 command = new(ref voiceInfo, state, outputBufferIndex, channelIndex, nodeId); command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); @@ -171,13 +173,13 @@ namespace Ryujinx.Audio.Renderer.Server /// /// Create a new . /// - /// The to generate the command from. - /// The to generate the command from. + /// The to generate the command from. + /// The to generate the command from. /// The output buffer index to use. /// The node id associated to this command. - public void GenerateAdpcmDataSourceVersion1(ref VoiceState voiceState, Memory state, ushort outputBufferIndex, int nodeId) + public void GenerateAdpcmDataSourceVersion1(ref VoiceInfo voiceInfo, Memory state, ushort outputBufferIndex, int nodeId) { - AdpcmDataSourceCommandVersion1 command = new(ref voiceState, state, outputBufferIndex, nodeId); + AdpcmDataSourceCommandVersion1 command = new(ref voiceInfo, state, outputBufferIndex, nodeId); command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); @@ -194,7 +196,7 @@ namespace Ryujinx.Audio.Renderer.Server /// The output buffer offset. /// Set to true if the biquad filter state needs to be initialized. /// The node id associated to this command. - public void GenerateBiquadFilter(int baseIndex, ref BiquadFilterParameter filter, Memory biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, bool needInitialization, int nodeId) + public void GenerateBiquadFilter(int baseIndex, ref BiquadFilterParameter2 filter, Memory biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, bool needInitialization, int nodeId) { BiquadFilterCommand command = new(baseIndex, ref filter, biquadFilterStateMemory, inputBufferOffset, outputBufferOffset, needInitialization, nodeId); @@ -213,7 +215,7 @@ namespace Ryujinx.Audio.Renderer.Server /// The output buffer offset. /// Set to true if the biquad filter state is initialized. /// The node id associated to this command. - public void GenerateMultiTapBiquadFilter(int baseIndex, ReadOnlySpan filters, Memory biquadFilterStatesMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan isInitialized, int nodeId) + public void GenerateMultiTapBiquadFilter(int baseIndex, ReadOnlySpan filters, Memory biquadFilterStatesMemory, int inputBufferOffset, int outputBufferOffset, ReadOnlySpan isInitialized, int nodeId) { MultiTapBiquadFilterCommand command = new(baseIndex, filters, biquadFilterStatesMemory, inputBufferOffset, outputBufferOffset, isInitialized, nodeId); @@ -230,9 +232,9 @@ namespace Ryujinx.Audio.Renderer.Server /// The base output index. /// The previous volume. /// The new volume. - /// The to generate the command from. + /// The to generate the command from. /// The node id associated to this command. - public void GenerateMixRampGrouped(uint mixBufferCount, uint inputBufferIndex, uint outputBufferIndex, ReadOnlySpan previousVolume, ReadOnlySpan volume, Memory state, int nodeId) + public void GenerateMixRampGrouped(uint mixBufferCount, uint inputBufferIndex, uint outputBufferIndex, ReadOnlySpan previousVolume, ReadOnlySpan volume, Memory state, int nodeId) { MixRampGroupedCommand command = new(mixBufferCount, inputBufferIndex, outputBufferIndex, previousVolume, volume, state, nodeId); @@ -248,10 +250,10 @@ namespace Ryujinx.Audio.Renderer.Server /// The new volume. /// The input buffer index. /// The output buffer index. - /// The index in the array to store the ramped sample. - /// The to generate the command from. + /// The index in the array to store the ramped sample. + /// The to generate the command from. /// The node id associated to this command. - public void GenerateMixRamp(float previousVolume, float volume, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory state, int nodeId) + public void GenerateMixRamp(float previousVolume, float volume, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory state, int nodeId) { MixRampCommand command = new(previousVolume, volume, inputBufferIndex, outputBufferIndex, lastSampleIndex, state, nodeId); @@ -267,8 +269,8 @@ namespace Ryujinx.Audio.Renderer.Server /// The new volume. /// The input buffer index. /// The output buffer index. - /// The index in the array to store the ramped sample. - /// The to generate the command from. + /// The index in the array to store the ramped sample. + /// The to generate the command from. /// The biquad filter parameter. /// The biquad state. /// The previous biquad state. @@ -282,8 +284,8 @@ namespace Ryujinx.Audio.Renderer.Server uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, - Memory state, - ref BiquadFilterParameter filter, + Memory state, + ref BiquadFilterParameter2 filter, Memory biquadFilterState, Memory previousBiquadFilterState, bool needInitialization, @@ -318,8 +320,8 @@ namespace Ryujinx.Audio.Renderer.Server /// The new volume. /// The input buffer index. /// The output buffer index. - /// The index in the array to store the ramped sample. - /// The to generate the command from. + /// The index in the array to store the ramped sample. + /// The to generate the command from. /// First biquad filter parameter. /// Second biquad filter parameter. /// First biquad state. @@ -337,9 +339,9 @@ namespace Ryujinx.Audio.Renderer.Server uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, - Memory state, - ref BiquadFilterParameter filter0, - ref BiquadFilterParameter filter1, + Memory state, + ref BiquadFilterParameter2 filter0, + ref BiquadFilterParameter2 filter1, Memory biquadFilterState0, Memory biquadFilterState1, Memory previousBiquadFilterState0, @@ -654,14 +656,14 @@ namespace Ryujinx.Audio.Renderer.Server /// Create a new . /// /// The offset of the mix buffer. - /// The associated. + /// The associated. /// The total input count. /// The input buffer mix offset. /// The buffer count per sample. /// The source sample count. /// The source sample rate. /// The node id associated to this command. - public void GenerateUpsample(uint bufferOffset, UpsamplerState upsampler, uint inputCount, Span inputBufferOffset, uint bufferCountPerSample, uint sampleCount, uint sampleRate, int nodeId) + public void GenerateUpsample(uint bufferOffset, UpsamplerInfo upsampler, uint inputCount, Span inputBufferOffset, uint bufferCountPerSample, uint sampleCount, uint sampleRate, int nodeId) { UpsampleCommand command = new(bufferOffset, upsampler, inputCount, inputBufferOffset, bufferCountPerSample, sampleCount, sampleRate, nodeId); @@ -686,5 +688,23 @@ namespace Ryujinx.Audio.Renderer.Server AddCommand(command); } + + public void GenerateFillBuffer(SplitterDestination destination, float value, int length, int nodeId) + { + FillBufferCommand command; + + if (Unsafe.IsNullRef(ref destination.GetV2RefOrNull())) + { + command = new(destination.GetV1RefOrNull(), length, value, nodeId); + } + else + { + command = new(destination.GetV2RefOrNull(), length, value, nodeId); + } + + command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); + + AddCommand(command); + } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs b/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs index 519de9b65..c88aa51f2 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs @@ -1,5 +1,6 @@ using Ryujinx.Audio.Common; using Ryujinx.Audio.Renderer.Common; +using Ryujinx.Audio.Renderer.Dsp; using Ryujinx.Audio.Renderer.Dsp.Command; using Ryujinx.Audio.Renderer.Dsp.State; using Ryujinx.Audio.Renderer.Parameter; @@ -41,27 +42,27 @@ namespace Ryujinx.Audio.Renderer.Server _commandBuffer.GenerateClearMixBuffer(Constants.InvalidNodeId); } - private void GenerateDataSource(ref VoiceState voiceState, Memory dspState, int channelIndex) + private void GenerateDataSource(ref VoiceInfo voiceInfo, Memory dspState, int channelIndex) { - if (voiceState.MixId != Constants.UnusedMixId) + if (voiceInfo.MixId != Constants.UnusedMixId) { - ref MixState mix = ref _mixContext.GetState(voiceState.MixId); + ref MixInfo mix = ref _mixContext.GetState(voiceInfo.MixId); _commandBuffer.GenerateDepopPrepare( dspState, _rendererContext.DepopBuffer, mix.BufferCount, mix.BufferOffset, - voiceState.NodeId, - voiceState.WasPlaying); + voiceInfo.NodeId, + voiceInfo.WasPlaying); } - else if (voiceState.SplitterId != Constants.UnusedSplitterId) + else if (voiceInfo.SplitterId != Constants.UnusedSplitterId) { int destinationId = 0; while (true) { - SplitterDestination destination = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId++); + SplitterDestination destination = _splitterContext.GetDestination((int)voiceInfo.SplitterId, destinationId++); if (destination.IsNull) { @@ -74,15 +75,17 @@ namespace Ryujinx.Audio.Renderer.Server if (mixId < _mixContext.GetCount() && mixId != Constants.UnusedSplitterIdInt) { - ref MixState mix = ref _mixContext.GetState(mixId); + ref MixInfo mix = ref _mixContext.GetState(mixId); + + // _commandBuffer.GenerateFillBuffer(); _commandBuffer.GenerateDepopPrepare( dspState, _rendererContext.DepopBuffer, mix.BufferCount, mix.BufferOffset, - voiceState.NodeId, - voiceState.WasPlaying); + voiceInfo.NodeId, + voiceInfo.WasPlaying); destination.MarkAsNeedToUpdateInternalState(); } @@ -90,71 +93,71 @@ namespace Ryujinx.Audio.Renderer.Server } } - if (!voiceState.WasPlaying) + if (!voiceInfo.WasPlaying) { - Debug.Assert(voiceState.SampleFormat != SampleFormat.Adpcm || channelIndex == 0); + Debug.Assert(voiceInfo.SampleFormat != SampleFormat.Adpcm || channelIndex == 0); - if (_rendererContext.BehaviourContext.IsWaveBufferVersion2Supported()) + if (_rendererContext.BehaviourInfo.IsWaveBufferVersion2Supported()) { _commandBuffer.GenerateDataSourceVersion2( - ref voiceState, + ref voiceInfo, dspState, (ushort)_rendererContext.MixBufferCount, (ushort)channelIndex, - voiceState.NodeId); + voiceInfo.NodeId); } else { - switch (voiceState.SampleFormat) + switch (voiceInfo.SampleFormat) { case SampleFormat.PcmInt16: _commandBuffer.GeneratePcmInt16DataSourceVersion1( - ref voiceState, + ref voiceInfo, dspState, (ushort)_rendererContext.MixBufferCount, (ushort)channelIndex, - voiceState.NodeId); + voiceInfo.NodeId); break; case SampleFormat.PcmFloat: _commandBuffer.GeneratePcmFloatDataSourceVersion1( - ref voiceState, + ref voiceInfo, dspState, (ushort)_rendererContext.MixBufferCount, (ushort)channelIndex, - voiceState.NodeId); + voiceInfo.NodeId); break; case SampleFormat.Adpcm: _commandBuffer.GenerateAdpcmDataSourceVersion1( - ref voiceState, + ref voiceInfo, dspState, (ushort)_rendererContext.MixBufferCount, - voiceState.NodeId); + voiceInfo.NodeId); break; default: - throw new NotImplementedException($"Unsupported data source {voiceState.SampleFormat}"); + throw new NotImplementedException($"Unsupported data source {voiceInfo.SampleFormat}"); } } } } - private void GenerateBiquadFilterForVoice(ref VoiceState voiceState, Memory state, int baseIndex, int bufferOffset, int nodeId) + private void GenerateBiquadFilterForVoice(ref VoiceInfo voiceInfo, Memory state, int baseIndex, int bufferOffset, int nodeId) { - bool supportsOptimizedPath = _rendererContext.BehaviourContext.UseMultiTapBiquadFilterProcessing(); + bool supportsOptimizedPath = _rendererContext.BehaviourInfo.UseMultiTapBiquadFilterProcessing(); - Span biquadFiltersSpan = voiceState.BiquadFilters.AsSpan(); + Span biquadFiltersSpan = voiceInfo.BiquadFilters.AsSpan(); if (supportsOptimizedPath && biquadFiltersSpan[0].Enable && biquadFiltersSpan[1].Enable) { Memory biquadStateRawMemory = SpanMemoryManager.Cast(state)[..(Unsafe.SizeOf() * Constants.VoiceBiquadFilterCount)]; Memory stateMemory = SpanMemoryManager.Cast(biquadStateRawMemory); - _commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, biquadFiltersSpan, stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId); + _commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, biquadFiltersSpan, stateMemory, bufferOffset, bufferOffset, voiceInfo.BiquadFilterNeedInitialization, nodeId); } else { for (int i = 0; i < biquadFiltersSpan.Length; i++) { - ref BiquadFilterParameter filter = ref biquadFiltersSpan[i]; + ref BiquadFilterParameter2 filter = ref biquadFiltersSpan[i]; if (filter.Enable) { @@ -167,7 +170,7 @@ namespace Ryujinx.Audio.Renderer.Server stateMemory.Slice(i, 1), bufferOffset, bufferOffset, - !voiceState.BiquadFilterNeedInitialization[i], + !voiceInfo.BiquadFilterNeedInitialization[i], nodeId); } } @@ -176,7 +179,7 @@ namespace Ryujinx.Audio.Renderer.Server private void GenerateVoiceMixWithSplitter( SplitterDestination destination, - Memory state, + Memory state, uint bufferOffset, uint bufferCount, uint bufferIndex, @@ -185,8 +188,8 @@ namespace Ryujinx.Audio.Renderer.Server ReadOnlySpan mixVolumes = destination.MixBufferVolume; ReadOnlySpan previousMixVolumes = destination.PreviousMixBufferVolume; - ref BiquadFilterParameter bqf0 = ref destination.GetBiquadFilterParameter(0); - ref BiquadFilterParameter bqf1 = ref destination.GetBiquadFilterParameter(1); + ref BiquadFilterParameter2 bqf0 = ref destination.GetBiquadFilterParameter(0); + ref BiquadFilterParameter2 bqf1 = ref destination.GetBiquadFilterParameter(1); Memory bqfState = _splitterContext.GetBiquadFilterState(destination); @@ -270,7 +273,7 @@ namespace Ryujinx.Audio.Renderer.Server private void GenerateVoiceMix( ReadOnlySpan mixVolumes, ReadOnlySpan previousMixVolumes, - Memory state, + Memory state, uint bufferOffset, uint bufferCount, uint bufferIndex, @@ -309,27 +312,27 @@ namespace Ryujinx.Audio.Renderer.Server } } - private void GenerateVoice(ref VoiceState voiceState) + private void GenerateVoice(ref VoiceInfo voiceInfo) { - int nodeId = voiceState.NodeId; - uint channelsCount = voiceState.ChannelsCount; + int nodeId = voiceInfo.NodeId; + uint channelsCount = voiceInfo.ChannelsCount; - Span channelResourceIdsSpan = voiceState.ChannelResourceIds.AsSpan(); - Span biquadFiltersSpan = voiceState.BiquadFilters.AsSpan(); + Span channelResourceIdsSpan = voiceInfo.ChannelResourceIds.AsSpan(); + Span biquadFiltersSpan = voiceInfo.BiquadFilters.AsSpan(); for (int channelIndex = 0; channelIndex < channelsCount; channelIndex++) { - Memory dspStateMemory = _voiceContext.GetUpdateStateForDsp(channelResourceIdsSpan[channelIndex]); + Memory dspStateMemory = _voiceContext.GetUpdateStateForDsp(channelResourceIdsSpan[channelIndex]); ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(channelResourceIdsSpan[channelIndex]); PerformanceDetailType dataSourceDetailType = PerformanceDetailType.Adpcm; - if (voiceState.SampleFormat == SampleFormat.PcmInt16) + if (voiceInfo.SampleFormat == SampleFormat.PcmInt16) { dataSourceDetailType = PerformanceDetailType.PcmInt16; } - else if (voiceState.SampleFormat == SampleFormat.PcmFloat) + else if (voiceInfo.SampleFormat == SampleFormat.PcmFloat) { dataSourceDetailType = PerformanceDetailType.PcmFloat; } @@ -345,18 +348,18 @@ namespace Ryujinx.Audio.Renderer.Server GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); } - GenerateDataSource(ref voiceState, dspStateMemory, channelIndex); + GenerateDataSource(ref voiceInfo, dspStateMemory, channelIndex); if (performanceInitialized) { GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); } - if (voiceState.WasPlaying) + if (voiceInfo.WasPlaying) { - voiceState.PreviousVolume = 0.0f; + voiceInfo.PreviousVolume = 0.0f; } - else if (voiceState.HasAnyDestination()) + else if (voiceInfo.HasAnyDestination()) { performanceInitialized = false; @@ -367,7 +370,7 @@ namespace Ryujinx.Audio.Renderer.Server GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); } - GenerateBiquadFilterForVoice(ref voiceState, dspStateMemory, (int)_rendererContext.MixBufferCount, channelIndex, nodeId); + GenerateBiquadFilterForVoice(ref voiceInfo, dspStateMemory, (int)_rendererContext.MixBufferCount, channelIndex, nodeId); if (performanceInitialized) { @@ -384,8 +387,8 @@ namespace Ryujinx.Audio.Renderer.Server } _commandBuffer.GenerateVolumeRamp( - voiceState.PreviousVolume, - voiceState.Volume, + voiceInfo.PreviousVolume, + voiceInfo.Volume, _rendererContext.MixBufferCount + (uint)channelIndex, nodeId); @@ -394,17 +397,17 @@ namespace Ryujinx.Audio.Renderer.Server GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); } - voiceState.PreviousVolume = voiceState.Volume; + voiceInfo.PreviousVolume = voiceInfo.Volume; - if (voiceState.MixId == Constants.UnusedMixId) + if (voiceInfo.MixId == Constants.UnusedMixId) { - if (voiceState.SplitterId != Constants.UnusedSplitterId) + if (voiceInfo.SplitterId != Constants.UnusedSplitterId) { int destinationId = channelIndex; while (true) { - SplitterDestination destination = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId); + SplitterDestination destination = _splitterContext.GetDestination((int)voiceInfo.SplitterId, destinationId); if (destination.IsNull) { @@ -419,7 +422,7 @@ namespace Ryujinx.Audio.Renderer.Server if (mixId < _mixContext.GetCount() && mixId != Constants.UnusedSplitterIdInt) { - ref MixState mix = ref _mixContext.GetState(mixId); + ref MixInfo mix = ref _mixContext.GetState(mixId); if (destination.IsBiquadFilterEnabled()) { @@ -451,7 +454,7 @@ namespace Ryujinx.Audio.Renderer.Server } else { - ref MixState mix = ref _mixContext.GetState(voiceState.MixId); + ref MixInfo mix = ref _mixContext.GetState(voiceInfo.MixId); performanceInitialized = false; @@ -479,9 +482,9 @@ namespace Ryujinx.Audio.Renderer.Server channelResource.UpdateState(); } - for (int i = 0; i < voiceState.BiquadFilterNeedInitialization.Length; i++) + for (int i = 0; i < voiceInfo.BiquadFilterNeedInitialization.Length; i++) { - voiceState.BiquadFilterNeedInitialization[i] = biquadFiltersSpan[i].Enable; + voiceInfo.BiquadFilterNeedInitialization[i] = biquadFiltersSpan[i].Enable; } } } @@ -491,11 +494,11 @@ namespace Ryujinx.Audio.Renderer.Server { for (int i = 0; i < _voiceContext.GetCount(); i++) { - ref VoiceState sortedState = ref _voiceContext.GetSortedState(i); + ref VoiceInfo sortedInfo = ref _voiceContext.GetSortedState(i); - if (!sortedState.ShouldSkip() && sortedState.UpdateForCommandGeneration(_voiceContext)) + if (!sortedInfo.ShouldSkip() && sortedInfo.UpdateForCommandGeneration(_voiceContext)) { - int nodeId = sortedState.NodeId; + int nodeId = sortedInfo.NodeId; PerformanceEntryAddresses performanceEntry = new(); @@ -508,7 +511,7 @@ namespace Ryujinx.Audio.Renderer.Server GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); } - GenerateVoice(ref sortedState); + GenerateVoice(ref sortedInfo); if (performanceInitialized) { @@ -639,9 +642,9 @@ namespace Ryujinx.Audio.Renderer.Server if (effect.IsEnabled) { bool needInitialization = effect.Parameter.Status == UsageState.Invalid || - (effect.Parameter.Status == UsageState.New && !_rendererContext.BehaviourContext.IsBiquadFilterEffectStateClearBugFixed()); + (effect.Parameter.Status == UsageState.New && !_rendererContext.BehaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); - BiquadFilterParameter parameter = new() + BiquadFilterParameter2 parameter = new() { Enable = true, }; @@ -683,7 +686,7 @@ namespace Ryujinx.Audio.Renderer.Server ulong workBuffer = effect.GetWorkBuffer(-1); - if (_rendererContext.BehaviourContext.IsEffectInfoVersion2Supported()) + if (_rendererContext.BehaviourInfo.IsEffectInfoVersion2Supported()) { Memory dspResultState; @@ -777,7 +780,7 @@ namespace Ryujinx.Audio.Renderer.Server nodeId); } - private void GenerateEffect(ref MixState mix, int effectId, BaseEffect effect) + private void GenerateEffect(ref MixInfo mix, int effectId, BaseEffect effect) { int nodeId = mix.NodeId; @@ -807,13 +810,13 @@ namespace Ryujinx.Audio.Renderer.Server GenerateAuxEffect(mix.BufferOffset, (AuxiliaryBufferEffect)effect, nodeId); break; case EffectType.Delay: - GenerateDelayEffect(mix.BufferOffset, (DelayEffect)effect, nodeId, _rendererContext.BehaviourContext.IsNewEffectChannelMappingSupported()); + GenerateDelayEffect(mix.BufferOffset, (DelayEffect)effect, nodeId, _rendererContext.BehaviourInfo.IsNewEffectChannelMappingSupported()); break; case EffectType.Reverb: - GenerateReverbEffect(mix.BufferOffset, (ReverbEffect)effect, nodeId, mix.IsLongSizePreDelaySupported, _rendererContext.BehaviourContext.IsNewEffectChannelMappingSupported()); + GenerateReverbEffect(mix.BufferOffset, (ReverbEffect)effect, nodeId, mix.IsLongSizePreDelaySupported, _rendererContext.BehaviourInfo.IsNewEffectChannelMappingSupported()); break; case EffectType.Reverb3d: - GenerateReverb3dEffect(mix.BufferOffset, (Reverb3dEffect)effect, nodeId, _rendererContext.BehaviourContext.IsNewEffectChannelMappingSupported()); + GenerateReverb3dEffect(mix.BufferOffset, (Reverb3dEffect)effect, nodeId, _rendererContext.BehaviourInfo.IsNewEffectChannelMappingSupported()); break; case EffectType.BiquadFilter: GenerateBiquadFilterEffect(mix.BufferOffset, (BiquadFilterEffect)effect, nodeId); @@ -839,7 +842,7 @@ namespace Ryujinx.Audio.Renderer.Server effect.UpdateForCommandGeneration(); } - private void GenerateEffects(ref MixState mix) + private void GenerateEffects(ref MixInfo mix) { ReadOnlySpan effectProcessingOrderArray = mix.EffectProcessingOrderArray; @@ -875,8 +878,8 @@ namespace Ryujinx.Audio.Renderer.Server ref bool isFirstMixBuffer, int nodeId) { - ref BiquadFilterParameter bqf0 = ref destination.GetBiquadFilterParameter(0); - ref BiquadFilterParameter bqf1 = ref destination.GetBiquadFilterParameter(1); + ref BiquadFilterParameter2 bqf0 = ref destination.GetBiquadFilterParameter(0); + ref BiquadFilterParameter2 bqf1 = ref destination.GetBiquadFilterParameter(1); Memory bqfState = _splitterContext.GetBiquadFilterState(destination); @@ -888,7 +891,7 @@ namespace Ryujinx.Audio.Renderer.Server inputBufferIndex, outputBufferIndex, 0, - Memory.Empty, + Memory.Empty, ref bqf0, ref bqf1, bqfState[..1], @@ -912,7 +915,7 @@ namespace Ryujinx.Audio.Renderer.Server inputBufferIndex, outputBufferIndex, 0, - Memory.Empty, + Memory.Empty, ref bqf0, bqfState[..1], bqfState.Slice(1, 1), @@ -931,7 +934,7 @@ namespace Ryujinx.Audio.Renderer.Server inputBufferIndex, outputBufferIndex, 0, - Memory.Empty, + Memory.Empty, ref bqf1, bqfState[..1], bqfState.Slice(1, 1), @@ -946,7 +949,7 @@ namespace Ryujinx.Audio.Renderer.Server isFirstMixBuffer = false; } - private void GenerateMix(ref MixState mix) + private void GenerateMix(ref MixInfo mix) { if (mix.HasAnyDestination()) { @@ -975,7 +978,7 @@ namespace Ryujinx.Audio.Renderer.Server if (mixId < _mixContext.GetCount() && mixId != Constants.UnusedSplitterIdInt) { - ref MixState destinationMix = ref _mixContext.GetState(mixId); + ref MixInfo destinationMix = ref _mixContext.GetState(mixId); uint inputBufferIndex = mix.BufferOffset + ((uint)destinationIndex % mix.BufferCount); @@ -1014,7 +1017,7 @@ namespace Ryujinx.Audio.Renderer.Server } else { - ref MixState destinationMix = ref _mixContext.GetState(mix.DestinationMixId); + ref MixInfo destinationMix = ref _mixContext.GetState(mix.DestinationMixId); for (uint bufferIndex = 0; bufferIndex < mix.BufferCount; bufferIndex++) { @@ -1036,7 +1039,7 @@ namespace Ryujinx.Audio.Renderer.Server } } - private void GenerateSubMix(ref MixState subMix) + private void GenerateSubMix(ref MixInfo subMix) { _commandBuffer.GenerateDepopForMixBuffers( _rendererContext.DepopBuffer, @@ -1072,11 +1075,11 @@ namespace Ryujinx.Audio.Renderer.Server { for (int id = 0; id < _mixContext.GetCount(); id++) { - ref MixState sortedState = ref _mixContext.GetSortedState(id); + ref MixInfo sortedInfo = ref _mixContext.GetSortedState(id); - if (sortedState.IsUsed && sortedState.MixId != Constants.FinalMixId) + if (sortedInfo.IsUsed && sortedInfo.MixId != Constants.FinalMixId) { - int nodeId = sortedState.NodeId; + int nodeId = sortedInfo.NodeId; PerformanceEntryAddresses performanceEntry = new(); @@ -1089,7 +1092,7 @@ namespace Ryujinx.Audio.Renderer.Server GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); } - GenerateSubMix(ref sortedState); + GenerateSubMix(ref sortedInfo); if (performanceInitialized) { @@ -1101,7 +1104,7 @@ namespace Ryujinx.Audio.Renderer.Server private void GenerateFinalMix() { - ref MixState finalMix = ref _mixContext.GetFinalState(); + ref MixInfo finalMix = ref _mixContext.GetFinalState(); _commandBuffer.GenerateDepopForMixBuffers( _rendererContext.DepopBuffer, @@ -1180,16 +1183,16 @@ namespace Ryujinx.Audio.Renderer.Server } } - private void GenerateCircularBuffer(CircularBufferSink sink, ref MixState finalMix) + private void GenerateCircularBuffer(CircularBufferSink sink, ref MixInfo finalMix) { _commandBuffer.GenerateCircularBuffer(finalMix.BufferOffset, sink, Constants.InvalidNodeId); } - private void GenerateDevice(DeviceSink sink, ref MixState finalMix) + private void GenerateDevice(DeviceSink sink, ref MixInfo finalMix) { - if (_commandBuffer.CommandList.SampleRate != 48000 && sink.UpsamplerState == null) + if (_commandBuffer.CommandList.SampleRate != 48000 && sink.UpsamplerInfo == null) { - sink.UpsamplerState = _rendererContext.UpsamplerManager.Allocate(); + sink.UpsamplerInfo = _rendererContext.UpsamplerManager.Allocate(); } bool useCustomDownMixingCommand = _rendererContext.ChannelCount == 2 && sink.Parameter.DownMixParameterEnabled; @@ -1216,11 +1219,11 @@ namespace Ryujinx.Audio.Renderer.Server CommandList commandList = _commandBuffer.CommandList; - if (sink.UpsamplerState != null) + if (sink.UpsamplerInfo != null) { _commandBuffer.GenerateUpsample( finalMix.BufferOffset, - sink.UpsamplerState, + sink.UpsamplerInfo, sink.Parameter.InputCount, sink.Parameter.Input.AsSpan(), commandList.BufferCount, @@ -1237,7 +1240,7 @@ namespace Ryujinx.Audio.Renderer.Server Constants.InvalidNodeId); } - private void GenerateSink(BaseSink sink, ref MixState finalMix) + private void GenerateSink(BaseSink sink, ref MixInfo finalMix) { bool performanceInitialized = false; @@ -1275,7 +1278,7 @@ namespace Ryujinx.Audio.Renderer.Server public void GenerateSinks() { - ref MixState finalMix = ref _mixContext.GetFinalState(); + ref MixInfo finalMix = ref _mixContext.GetFinalState(); for (int i = 0; i < _sinkContext.GetCount(); i++) { diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs index cff754b82..8abe81e1f 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs @@ -194,5 +194,10 @@ namespace Ryujinx.Audio.Renderer.Server { return 0; } + + public uint Estimate(FillBufferCommand command) + { + return 0; + } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs index 1e9b6c53e..85e340393 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs @@ -486,5 +486,10 @@ namespace Ryujinx.Audio.Renderer.Server { return 0; } + + public uint Estimate(FillBufferCommand command) + { + return 0; + } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs index 85e016019..4b0eec4f3 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs @@ -3,7 +3,7 @@ using Ryujinx.Audio.Renderer.Dsp.Command; using Ryujinx.Audio.Renderer.Parameter.Effect; using System; using System.Diagnostics; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; +using Ryujinx.Audio.Renderer.Parameter; namespace Ryujinx.Audio.Renderer.Server { @@ -656,5 +656,10 @@ namespace Ryujinx.Audio.Renderer.Server { return 0; } + + public virtual uint Estimate(FillBufferCommand command) + { + return 0; + } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs index fe6103f2b..906065792 100644 --- a/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs +++ b/src/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs @@ -286,5 +286,10 @@ namespace Ryujinx.Audio.Renderer.Server return 8683; } } + + public override uint Estimate(FillBufferCommand command) + { + return 0; + } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs index 77d9b5c29..6324689e4 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/BaseEffect.cs @@ -174,6 +174,19 @@ namespace Ryujinx.Audio.Renderer.Server.Effect updateErrorInfo = new ErrorInfo(); } + + /// + /// Update the internal state from a user version 3 parameter. + /// + /// The possible that was generated. + /// The user parameter. + /// The mapper to use. + public virtual void Update(out ErrorInfo updateErrorInfo, in EffectInParameterVersion3 parameter, PoolMapper mapper) + { + Debug.Assert(IsTypeValid(in parameter)); + + updateErrorInfo = new ErrorInfo(); + } /// /// Get the work buffer DSP address at the given index. diff --git a/src/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs b/src/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs index 3b3e1021c..f920c6873 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Effect/BiquadFilterEffect.cs @@ -1,4 +1,5 @@ using Ryujinx.Audio.Renderer.Common; +using Ryujinx.Audio.Renderer.Dsp; using Ryujinx.Audio.Renderer.Dsp.State; using Ryujinx.Audio.Renderer.Parameter; using Ryujinx.Audio.Renderer.Parameter.Effect; @@ -17,7 +18,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect /// /// The biquad filter parameter. /// - public BiquadFilterEffectParameter Parameter; + public BiquadFilterEffectParameter2 Parameter; /// /// The biquad filter state. @@ -29,7 +30,7 @@ namespace Ryujinx.Audio.Renderer.Server.Effect /// public BiquadFilterEffect() { - Parameter = new BiquadFilterEffectParameter(); + Parameter = new BiquadFilterEffectParameter2(); State = new BiquadFilterState[Constants.ChannelCountMax]; } @@ -44,6 +45,11 @@ namespace Ryujinx.Audio.Renderer.Server.Effect { Update(out updateErrorInfo, in parameter, mapper); } + + public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in EffectInParameterVersion3 parameter, PoolMapper mapper) + { + Update(out updateErrorInfo, in parameter, mapper); + } public void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, in T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter { @@ -51,7 +57,17 @@ namespace Ryujinx.Audio.Renderer.Server.Effect UpdateParameterBase(in parameter); - Parameter = MemoryMarshal.Cast(parameter.SpecificData)[0]; + if (typeof(T) == typeof(EffectInParameterVersion3)) + { + Parameter = MemoryMarshal.Cast(parameter.SpecificData)[0]; + } + else + { + BiquadFilterEffectParameter1 oldParameter = + MemoryMarshal.Cast(parameter.SpecificData)[0]; + Parameter = BiquadFilterHelper.ToBiquadFilterEffectParameter2(oldParameter); + } + IsEnabled = parameter.IsEnabled; updateErrorInfo = new BehaviourParameter.ErrorInfo(); diff --git a/src/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs b/src/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs index 9c4312ad6..360241278 100644 --- a/src/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs +++ b/src/Ryujinx.Audio/Renderer/Server/ICommandProcessingTimeEstimator.cs @@ -38,5 +38,6 @@ namespace Ryujinx.Audio.Renderer.Server uint Estimate(CompressorCommand command); uint Estimate(BiquadFilterAndMixCommand command); uint Estimate(MultiTapBiquadFilterAndMixCommand command); + uint Estimate(FillBufferCommand command); } } diff --git a/src/Ryujinx.Audio/Renderer/Server/MemoryPool/AddressInfo.cs b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/AddressInfo.cs index 3337e44b0..0ae6d518d 100644 --- a/src/Ryujinx.Audio/Renderer/Server/MemoryPool/AddressInfo.cs +++ b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/AddressInfo.cs @@ -20,14 +20,14 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool /// public ulong Size; - private unsafe MemoryPoolState* _memoryPools; + private unsafe MemoryPoolInfo* _memoryPools; /// /// The forced DSP address of the region. /// public DspAddress ForceMappedDspAddress; - private readonly unsafe ref MemoryPoolState MemoryPoolState => ref *_memoryPools; + private readonly unsafe ref MemoryPoolInfo MemoryPoolInfo => ref *_memoryPools; public readonly unsafe bool HasMemoryPoolState => (nint)_memoryPools != nint.Zero; @@ -53,7 +53,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool return new AddressInfo { CpuAddress = cpuAddress, - _memoryPools = MemoryPoolState.Null, + _memoryPools = MemoryPoolInfo.Null, Size = size, ForceMappedDspAddress = 0, }; @@ -73,19 +73,19 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool unsafe { - _memoryPools = MemoryPoolState.Null; + _memoryPools = MemoryPoolInfo.Null; } } /// - /// Set the associated. + /// Set the associated. /// - /// The associated. - public void SetupMemoryPool(Span memoryPoolState) + /// The associated. + public void SetupMemoryPool(Span memoryPoolState) { unsafe { - fixed (MemoryPoolState* ptr = &MemoryMarshal.GetReference(memoryPoolState)) + fixed (MemoryPoolInfo* ptr = &MemoryMarshal.GetReference(memoryPoolState)) { SetupMemoryPool(ptr); } @@ -93,27 +93,27 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Set the associated. + /// Set the associated. /// - /// The associated. - public unsafe void SetupMemoryPool(MemoryPoolState* memoryPoolState) + /// The associated. + public unsafe void SetupMemoryPool(MemoryPoolInfo* memoryPoolState) { _memoryPools = memoryPoolState; } /// - /// Check if the is mapped. + /// Check if the is mapped. /// - /// Returns true if the is mapped. + /// Returns true if the is mapped. public readonly bool HasMappedMemoryPool() { - return HasMemoryPoolState && MemoryPoolState.IsMapped(); + return HasMemoryPoolState && MemoryPoolInfo.IsMapped(); } /// /// Get the DSP address associated to the . /// - /// If true, mark the as used. + /// If true, mark the as used. /// Returns the DSP address associated to the . public readonly DspAddress GetReference(bool markUsed) { @@ -124,10 +124,10 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool if (markUsed) { - MemoryPoolState.IsUsed = true; + MemoryPoolInfo.IsUsed = true; } - return MemoryPoolState.Translate(CpuAddress, Size); + return MemoryPoolInfo.Translate(CpuAddress, Size); } } } diff --git a/src/Ryujinx.Audio/Renderer/Server/MemoryPool/MemoryPoolState.cs b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/MemoryPoolInfo.cs similarity index 73% rename from src/Ryujinx.Audio/Renderer/Server/MemoryPool/MemoryPoolState.cs rename to src/Ryujinx.Audio/Renderer/Server/MemoryPool/MemoryPoolInfo.cs index 50153af37..eb0117f50 100644 --- a/src/Ryujinx.Audio/Renderer/Server/MemoryPool/MemoryPoolState.cs +++ b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/MemoryPoolInfo.cs @@ -8,62 +8,62 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool /// Server state for a memory pool. /// [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = Alignment)] - public struct MemoryPoolState + public struct MemoryPoolInfo { public const int Alignment = 0x10; /// - /// The location of the . + /// The location of the . /// public enum LocationType : uint { /// - /// located on the CPU side for user use. + /// located on the CPU side for user use. /// Cpu, /// - /// located on the DSP side for system use. + /// located on the DSP side for system use. /// Dsp, } /// - /// The CPU address associated to the . + /// The CPU address associated to the . /// public CpuAddress CpuAddress; /// - /// The DSP address associated to the . + /// The DSP address associated to the . /// public DspAddress DspAddress; /// - /// The size associated to the . + /// The size associated to the . /// public ulong Size; /// - /// The associated to the . + /// The associated to the . /// public LocationType Location; /// - /// Set to true if the is used. + /// Set to true if the is used. /// [MarshalAs(UnmanagedType.I1)] public bool IsUsed; - public static unsafe MemoryPoolState* Null => (MemoryPoolState*)nint.Zero.ToPointer(); + public static unsafe MemoryPoolInfo* Null => (MemoryPoolInfo*)nint.Zero.ToPointer(); /// - /// Create a new with the given . + /// Create a new with the given . /// /// The location type to use. - /// A new with the given . - public static MemoryPoolState Create(LocationType location) + /// A new with the given . + public static MemoryPoolInfo Create(LocationType location) { - return new MemoryPoolState + return new MemoryPoolInfo { CpuAddress = 0, DspAddress = 0, @@ -73,7 +73,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Set the and size of the . + /// Set the and size of the . /// /// The . /// The size. @@ -84,11 +84,11 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Check if the given and size is contains in the . + /// Check if the given and size is contains in the . /// /// The . /// The size. - /// True if the is contained inside the . + /// True if the is contained inside the . public readonly bool Contains(CpuAddress targetCpuAddress, ulong size) { if (CpuAddress <= targetCpuAddress && size + targetCpuAddress <= Size + CpuAddress) @@ -118,9 +118,9 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Is the mapped on the DSP? + /// Is the mapped on the DSP? /// - /// Returns true if the is mapped on the DSP. + /// Returns true if the is mapped on the DSP. public readonly bool IsMapped() { return DspAddress != 0; diff --git a/src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs index 535e2fd79..2b7153b54 100644 --- a/src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs +++ b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs @@ -18,7 +18,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool const uint CurrentProcessPseudoHandle = 0xFFFF8001; /// - /// The result of . + /// The result of . /// public enum UpdateResult : uint { @@ -49,9 +49,9 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool private readonly uint _processHandle; /// - /// The that will be manipulated. + /// The that will be manipulated. /// - private readonly Memory _memoryPools; + private readonly Memory _memoryPools; /// /// If set to true, this will try to force map memory pool even if their state are considered invalid. @@ -67,7 +67,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool { _processHandle = processHandle; _isForceMapEnabled = isForceMapEnabled; - _memoryPools = Memory.Empty; + _memoryPools = Memory.Empty; } /// @@ -76,7 +76,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool /// The handle of the process owning the CPU memory manipulated. /// The user memory pools. /// If set to true, this will try to force map memory pool even if their state are considered invalid. - public PoolMapper(uint processHandle, Memory memoryPool, bool isForceMapEnabled) + public PoolMapper(uint processHandle, Memory memoryPool, bool isForceMapEnabled) { _processHandle = processHandle; _memoryPools = memoryPool; @@ -84,15 +84,15 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Initialize the for system use. + /// Initialize the for system use. /// - /// The for system use. + /// The for system use. /// The to assign. /// The size to assign. /// Returns true if mapping on the succeeded. - public bool InitializeSystemPool(ref MemoryPoolState memoryPool, CpuAddress cpuAddress, ulong size) + public bool InitializeSystemPool(ref MemoryPoolInfo memoryPool, CpuAddress cpuAddress, ulong size) { - if (memoryPool.Location != MemoryPoolState.LocationType.Dsp) + if (memoryPool.Location != MemoryPoolInfo.LocationType.Dsp) { return false; } @@ -101,13 +101,13 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Initialize the . + /// Initialize the . /// - /// The . + /// The . /// The to assign. /// The size to assign. /// Returns true if mapping on the succeeded. - public bool InitializePool(ref MemoryPoolState memoryPool, CpuAddress cpuAddress, ulong size) + public bool InitializePool(ref MemoryPoolInfo memoryPool, CpuAddress cpuAddress, ulong size) { memoryPool.SetCpuAddress(cpuAddress, size); @@ -115,18 +115,18 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Get the process handle associated to the . + /// Get the process handle associated to the . /// - /// The . - /// Returns the process handle associated to the . - public uint GetProcessHandle(ref MemoryPoolState memoryPool) + /// The . + /// Returns the process handle associated to the . + public uint GetProcessHandle(ref MemoryPoolInfo memoryPool) { - if (memoryPool.Location == MemoryPoolState.LocationType.Cpu) + if (memoryPool.Location == MemoryPoolInfo.LocationType.Cpu) { return CurrentProcessPseudoHandle; } - if (memoryPool.Location == MemoryPoolState.LocationType.Dsp) + if (memoryPool.Location == MemoryPoolInfo.LocationType.Dsp) { return _processHandle; } @@ -135,11 +135,11 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Map the on the . + /// Map the on the . /// - /// The to map. + /// The to map. /// Returns the DSP address mapped. - public DspAddress Map(ref MemoryPoolState memoryPool) + public DspAddress Map(ref MemoryPoolInfo memoryPool) { DspAddress result = AudioProcessorMemoryManager.Map(GetProcessHandle(ref memoryPool), memoryPool.CpuAddress, memoryPool.Size); @@ -152,11 +152,11 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Unmap the from the . + /// Unmap the from the . /// - /// The to unmap. + /// The to unmap. /// Returns true if unmapped. - public bool Unmap(ref MemoryPoolState memoryPool) + public bool Unmap(ref MemoryPoolInfo memoryPool) { if (memoryPool.IsUsed) { @@ -172,12 +172,12 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Find a associated to the region given. + /// Find a associated to the region given. /// /// The region . /// The region size. - /// Returns the found or if not found. - private Span FindMemoryPool(CpuAddress cpuAddress, ulong size) + /// Returns the found or if not found. + private Span FindMemoryPool(CpuAddress cpuAddress, ulong size) { if (!_memoryPools.IsEmpty && _memoryPools.Length > 0) { @@ -190,7 +190,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } } - return Span.Empty; + return Span.Empty; } /// @@ -201,7 +201,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool { if (_isForceMapEnabled) { - Span memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size); + Span memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size); if (!memoryPool.IsEmpty) { @@ -243,13 +243,13 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Update a using user parameters. + /// Update a using user parameters. /// - /// The to update. + /// The to update. /// Input user parameter. /// Output user parameter. /// Returns the of the operations performed. - public UpdateResult Update(ref MemoryPoolState memoryPool, in MemoryPoolInParameter inParameter, ref MemoryPoolOutStatus outStatus) + public UpdateResult Update(ref MemoryPoolInfo memoryPool, in MemoryPoolInParameter inParameter, ref MemoryPoolOutStatus outStatus) { MemoryPoolUserState inputState = inParameter.State; @@ -321,7 +321,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool if (_memoryPools.Length > 0) { - Span memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size); + Span memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size); if (!memoryPool.IsEmpty) { @@ -343,7 +343,7 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool { unsafe { - addressInfo.SetupMemoryPool(MemoryPoolState.Null); + addressInfo.SetupMemoryPool(MemoryPoolInfo.Null); } } @@ -351,12 +351,12 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool } /// - /// Remove the usage flag from all the . + /// Remove the usage flag from all the . /// - /// The to reset. - public static void ClearUsageState(Memory memoryPool) + /// The to reset. + public static void ClearUsageState(Memory memoryPool) { - foreach (ref MemoryPoolState info in memoryPool.Span) + foreach (ref MemoryPoolInfo info in memoryPool.Span) { info.IsUsed = false; } diff --git a/src/Ryujinx.Audio/Renderer/Server/Mix/MixContext.cs b/src/Ryujinx.Audio/Renderer/Server/Mix/MixContext.cs index 8991ceaf9..cdb6511cb 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Mix/MixContext.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Mix/MixContext.cs @@ -17,12 +17,12 @@ namespace Ryujinx.Audio.Renderer.Server.Mix private uint _mixesCount; /// - /// Storage for . + /// Storage for . /// - private Memory _mixes; + private Memory _mixes; /// - /// Storage of the sorted indices to . + /// Storage of the sorted indices to . /// private Memory _sortedMixes; @@ -49,10 +49,10 @@ namespace Ryujinx.Audio.Renderer.Server.Mix /// Initialize the . /// /// The storage for sorted indices. - /// The storage of . + /// The storage of . /// The storage used for the . /// The storage used for the . - public void Initialize(Memory sortedMixes, Memory mixes, Memory nodeStatesWorkBuffer, Memory edgeMatrixWorkBuffer) + public void Initialize(Memory sortedMixes, Memory mixes, Memory nodeStatesWorkBuffer, Memory edgeMatrixWorkBuffer) { _mixesCount = (uint)mixes.Length; _mixes = mixes; @@ -82,30 +82,30 @@ namespace Ryujinx.Audio.Renderer.Server.Mix } /// - /// Get a reference to the final . + /// Get a reference to the final . /// - /// A reference to the final . - public ref MixState GetFinalState() + /// A reference to the final . + public ref MixInfo GetFinalState() { return ref GetState(Constants.FinalMixId); } /// - /// Get a reference to a at the given . + /// Get a reference to a at the given . /// /// The index to use. - /// A reference to a at the given . - public ref MixState GetState(int id) + /// A reference to a at the given . + public ref MixInfo GetState(int id) { return ref SpanIOHelper.GetFromMemory(_mixes, id, _mixesCount); } /// - /// Get a reference to a at the given of the sorted mix info. + /// Get a reference to a at the given of the sorted mix info. /// /// The index to use. - /// A reference to a at the given . - public ref MixState GetSortedState(int id) + /// A reference to a at the given . + public ref MixInfo GetSortedState(int id) { Debug.Assert(id >= 0 && id < _mixesCount); @@ -122,18 +122,18 @@ namespace Ryujinx.Audio.Renderer.Server.Mix } /// - /// Update the internal distance from the final mix value of every . + /// Update the internal distance from the final mix value of every . /// private void UpdateDistancesFromFinalMix() { - foreach (ref MixState mix in _mixes.Span) + foreach (ref MixInfo mix in _mixes.Span) { mix.ClearDistanceFromFinalMix(); } for (int i = 0; i < GetCount(); i++) { - ref MixState mix = ref GetState(i); + ref MixInfo mix = ref GetState(i); SetSortedState(i, i); @@ -149,13 +149,13 @@ namespace Ryujinx.Audio.Renderer.Server.Mix { if (mixId == Constants.UnusedMixId) { - distance = MixState.InvalidDistanceFromFinalMix; + distance = MixInfo.InvalidDistanceFromFinalMix; break; } - ref MixState distanceMix = ref GetState(mixId); + ref MixInfo distanceMix = ref GetState(mixId); - if (distanceMix.DistanceFromFinalMix != MixState.InvalidDistanceFromFinalMix) + if (distanceMix.DistanceFromFinalMix != MixInfo.InvalidDistanceFromFinalMix) { distance = distanceMix.DistanceFromFinalMix + 1; break; @@ -171,12 +171,12 @@ namespace Ryujinx.Audio.Renderer.Server.Mix if (distance > GetCount()) { - distance = MixState.InvalidDistanceFromFinalMix; + distance = MixInfo.InvalidDistanceFromFinalMix; } } else { - distance = MixState.InvalidDistanceFromFinalMix; + distance = MixInfo.InvalidDistanceFromFinalMix; } mix.DistanceFromFinalMix = distance; @@ -185,13 +185,13 @@ namespace Ryujinx.Audio.Renderer.Server.Mix } /// - /// Update the internal mix buffer offset of all . + /// Update the internal mix buffer offset of all . /// private void UpdateMixBufferOffset() { uint offset = 0; - foreach (ref MixState mix in _mixes.Span) + foreach (ref MixInfo mix in _mixes.Span) { mix.BufferOffset = offset; @@ -210,10 +210,10 @@ namespace Ryujinx.Audio.Renderer.Server.Mix Array.Sort(sortedMixesTemp, (a, b) => { - ref MixState stateA = ref GetState(a); - ref MixState stateB = ref GetState(b); + ref MixInfo infoA = ref GetState(a); + ref MixInfo infoB = ref GetState(b); - return stateB.DistanceFromFinalMix.CompareTo(stateA.DistanceFromFinalMix); + return infoB.DistanceFromFinalMix.CompareTo(infoA.DistanceFromFinalMix); }); sortedMixesTemp.AsSpan().CopyTo(_sortedMixes.Span); diff --git a/src/Ryujinx.Audio/Renderer/Server/Mix/MixState.cs b/src/Ryujinx.Audio/Renderer/Server/Mix/MixInfo.cs similarity index 93% rename from src/Ryujinx.Audio/Renderer/Server/Mix/MixState.cs rename to src/Ryujinx.Audio/Renderer/Server/Mix/MixInfo.cs index 34b3ed4bd..eae141a66 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Mix/MixState.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Mix/MixInfo.cs @@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Server.Mix /// Server state for a mix. /// [StructLayout(LayoutKind.Sequential, Size = 0x940, Pack = Alignment)] - public struct MixState + public struct MixInfo { public const uint InvalidDistanceFromFinalMix = 0x80000000; @@ -136,11 +136,11 @@ namespace Ryujinx.Audio.Renderer.Server.Mix } /// - /// Create a new + /// Create a new /// /// - /// - public MixState(Memory effectProcessingOrderArray, ref BehaviourContext behaviourContext) : this() + /// + public MixInfo(Memory effectProcessingOrderArray, ref BehaviourInfo behaviourInfo) : this() { MixId = UnusedMixId; @@ -158,7 +158,7 @@ namespace Ryujinx.Audio.Renderer.Server.Mix EffectProcessingOrderArrayMaxCount = (uint)effectProcessingOrderArray.Length; - IsLongSizePreDelaySupported = behaviourContext.IsLongSizePreDelaySupported(); + IsLongSizePreDelaySupported = behaviourInfo.IsLongSizePreDelaySupported(); ClearEffectProcessingOrder(); } @@ -257,9 +257,9 @@ namespace Ryujinx.Audio.Renderer.Server.Mix /// The input parameter of the mix. /// The effect context. /// The splitter context. - /// The behaviour context. + /// The behaviour context. /// Return true if the mix was changed. - public bool Update(EdgeMatrix edgeMatrix, in MixParameter parameter, EffectContext effectContext, SplitterContext splitterContext, BehaviourContext behaviourContext) + public bool Update(EdgeMatrix edgeMatrix, in MixParameter parameter, EffectContext effectContext, SplitterContext splitterContext, BehaviourInfo behaviourInfo) { bool isDirty; @@ -271,7 +271,7 @@ namespace Ryujinx.Audio.Renderer.Server.Mix NodeId = parameter.NodeId; parameter.MixBufferVolume.CopyTo(MixBufferVolume); - if (behaviourContext.IsSplitterSupported()) + if (behaviourInfo.IsSplitterSupported()) { isDirty = UpdateConnection(edgeMatrix, in parameter, ref splitterContext); } @@ -279,10 +279,7 @@ namespace Ryujinx.Audio.Renderer.Server.Mix { isDirty = DestinationMixId != parameter.DestinationMixId; - if (DestinationMixId != parameter.DestinationMixId) - { - DestinationMixId = parameter.DestinationMixId; - } + DestinationMixId = parameter.DestinationMixId; DestinationSplitterId = UnusedSplitterId; } diff --git a/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs b/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs index da5a0ad45..e430d99c3 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Performance/PerformanceManager.cs @@ -10,11 +10,11 @@ namespace Ryujinx.Audio.Renderer.Server.Performance /// Get the required size for a single performance frame. /// /// The audio renderer configuration. - /// The behaviour context. + /// The behaviour context. /// The required size for a single performance frame. - public static ulong GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref AudioRendererConfiguration parameter, ref BehaviourContext behaviourContext) + public static ulong GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref AudioRendererConfiguration parameter, ref BehaviourInfo behaviourInfo) { - uint version = behaviourContext.GetPerformanceMetricsDataFormat(); + uint version = behaviourInfo.GetPerformanceMetricsDataFormat(); if (version == 2) { @@ -81,11 +81,11 @@ namespace Ryujinx.Audio.Renderer.Server.Performance /// /// The backing memory available for use by the manager. /// The audio renderer configuration. - /// The behaviour context; + /// The behaviour context; /// A new . - public static PerformanceManager Create(Memory performanceBuffer, ref AudioRendererConfiguration parameter, BehaviourContext behaviourContext) + public static PerformanceManager Create(Memory performanceBuffer, ref AudioRendererConfiguration parameter, BehaviourInfo behaviourInfo) { - uint version = behaviourContext.GetPerformanceMetricsDataFormat(); + uint version = behaviourInfo.GetPerformanceMetricsDataFormat(); return version switch { diff --git a/src/Ryujinx.Audio/Renderer/Server/RendererSystemContext.cs b/src/Ryujinx.Audio/Renderer/Server/RendererSystemContext.cs index 090850018..fa7a24d09 100644 --- a/src/Ryujinx.Audio/Renderer/Server/RendererSystemContext.cs +++ b/src/Ryujinx.Audio/Renderer/Server/RendererSystemContext.cs @@ -1,3 +1,4 @@ +using Ryujinx.Audio.Renderer.Server.Mix; using Ryujinx.Audio.Renderer.Server.Upsampler; using System; @@ -19,7 +20,7 @@ namespace Ryujinx.Audio.Renderer.Server /// /// The target channel count for sink. /// - /// See for usage. + /// See for usage. public uint ChannelCount; /// @@ -28,12 +29,12 @@ namespace Ryujinx.Audio.Renderer.Server public uint MixBufferCount; /// - /// Instance of the used to derive bug fixes and features of the current audio renderer revision. + /// Instance of the used to derive bug fixes and features of the current audio renderer revision. /// - public BehaviourContext BehaviourContext; + public BehaviourInfo BehaviourInfo; /// - /// Instance of the used for upsampling (see ) + /// Instance of the used for upsampling (see ) /// public UpsamplerManager UpsamplerManager; diff --git a/src/Ryujinx.Audio/Renderer/Server/Sink/DeviceSink.cs b/src/Ryujinx.Audio/Renderer/Server/Sink/DeviceSink.cs index afe2d4b1b..c590b69d9 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Sink/DeviceSink.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Sink/DeviceSink.cs @@ -28,7 +28,7 @@ namespace Ryujinx.Audio.Renderer.Server.Sink /// The upsampler instance used by this sink. /// /// Null if no upsampling is needed. - public UpsamplerState UpsamplerState; + public UpsamplerInfo UpsamplerInfo; /// /// Create a new . @@ -40,9 +40,9 @@ namespace Ryujinx.Audio.Renderer.Server.Sink public override void CleanUp() { - UpsamplerState?.Release(); + UpsamplerInfo?.Release(); - UpsamplerState = null; + UpsamplerInfo = null; base.CleanUp(); } diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs index 6dddb4315..7d914e137 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterContext.cs @@ -55,22 +55,27 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// If set to true, the previous mix volume is explicitly resetted using the input parameter, instead of implicitly on first use. /// public bool IsSplitterPrevVolumeResetSupported { get; private set; } + + /// + /// If set to true, the previous mix volume is explicitly resetted using the input parameter, instead of implicitly on first use. + /// + public bool IsBiquadFilterParameterFloatSupported { get; private set; } /// /// Initialize . /// - /// The behaviour context. + /// The behaviour context. /// The audio renderer configuration. /// The . /// Memory to store the biquad filtering state for splitters during processing. /// Return true if the initialization was successful. public bool Initialize( - ref BehaviourContext behaviourContext, + ref BehaviourInfo behaviourInfo, ref AudioRendererConfiguration parameter, WorkBufferAllocator workBufferAllocator, Memory splitterBqfStates) { - if (!behaviourContext.IsSplitterSupported() || parameter.SplitterCount <= 0 || parameter.SplitterDestinationCount <= 0) + if (!behaviourInfo.IsSplitterSupported() || parameter.SplitterCount <= 0 || parameter.SplitterDestinationCount <= 0) { Setup(Memory.Empty, Memory.Empty, Memory.Empty, false); @@ -94,7 +99,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter Memory splitterDestinationsV1 = Memory.Empty; Memory splitterDestinationsV2 = Memory.Empty; - if (!behaviourContext.IsBiquadFilterParameterForSplitterEnabled()) + if (!behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()) { Version = 1; @@ -144,11 +149,12 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter } } - IsSplitterPrevVolumeResetSupported = behaviourContext.IsSplitterPrevVolumeResetSupported(); + IsSplitterPrevVolumeResetSupported = behaviourInfo.IsSplitterPrevVolumeResetSupported(); + IsBiquadFilterParameterFloatSupported = behaviourInfo.IsBiquadFilterParameterFloatSupported(); SplitterState.InitializeSplitters(splitters.Span); - Setup(splitters, splitterDestinationsV1, splitterDestinationsV2, behaviourContext.IsSplitterBugFixed()); + Setup(splitters, splitterDestinationsV1, splitterDestinationsV2, behaviourInfo.IsSplitterBugFixed()); return true; } @@ -157,16 +163,16 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// Get the work buffer size while adding the size needed for splitter to operate. /// /// The current size. - /// The behaviour context. + /// The behaviour context. /// The renderer configuration. /// Return the new size taking splitter into account. - public static ulong GetWorkBufferSize(ulong size, ref BehaviourContext behaviourContext, ref AudioRendererConfiguration parameter) + public static ulong GetWorkBufferSize(ulong size, ref BehaviourInfo behaviourInfo, ref AudioRendererConfiguration parameter) { - if (behaviourContext.IsSplitterSupported()) + if (behaviourInfo.IsSplitterSupported()) { size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterCount, SplitterState.Alignment); - if (behaviourContext.IsBiquadFilterParameterForSplitterEnabled()) + if (behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()) { size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterDestinationCount, SplitterDestinationVersion2.Alignment); } @@ -175,12 +181,10 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterDestinationCount, SplitterDestinationVersion1.Alignment); } - if (behaviourContext.IsSplitterBugFixed()) + if (behaviourInfo.IsSplitterBugFixed()) { size = WorkBufferAllocator.GetTargetSize(size, parameter.SplitterDestinationCount, 0x10); } - - return size; } return size; @@ -227,7 +231,16 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter return 0; } - int length = _splitterDestinationsV2.IsEmpty ? _splitterDestinationsV1.Length : _splitterDestinationsV2.Length; + int length; + + if (_splitterDestinationsV2.IsEmpty) + { + length = _splitterDestinationsV1.Length; + } + else + { + length = _splitterDestinationsV2.Length; + } return length / _splitters.Length; } @@ -278,8 +291,17 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter if (parameter.IsMagicValid()) { - int length = _splitterDestinationsV2.IsEmpty ? _splitterDestinationsV1.Length : _splitterDestinationsV2.Length; + int length; + if (_splitterDestinationsV2.IsEmpty) + { + length = _splitterDestinationsV1.Length; + } + else + { + length = _splitterDestinationsV2.Length; + } + if (parameter.Id >= 0 && parameter.Id < length) { SplitterDestination destination = GetDestination(parameter.Id); @@ -315,9 +337,19 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter } else if (Version == 2) { - if (!UpdateData(ref input)) + if (IsBiquadFilterParameterFloatSupported) { - break; + if (!UpdateData(ref input)) + { + break; + } + } + else + { + if (!UpdateData(ref input)) + { + break; + } } } else @@ -381,10 +413,8 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter { return new SplitterDestination(ref SpanIOHelper.GetFromMemory(_splitterDestinationsV1, id, (uint)_splitterDestinationsV1.Length)); } - else - { - return new SplitterDestination(ref SpanIOHelper.GetFromMemory(_splitterDestinationsV2, id, (uint)_splitterDestinationsV2.Length)); - } + + return new SplitterDestination(ref SpanIOHelper.GetFromMemory(_splitterDestinationsV2, id, (uint)_splitterDestinationsV2.Length)); } /// diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs index 1a46d41fd..1253e5d2c 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs @@ -31,15 +31,11 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter { return 0; } - else - { - return _v1.Id; - } - } - else - { - return _v2.Id; + + return _v1.Id; } + + return _v2.Id; } } @@ -56,15 +52,11 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter { return 0; } - else - { - return _v1.DestinationId; - } - } - else - { - return _v2.DestinationId; + + return _v1.DestinationId; } + + return _v2.DestinationId; } } @@ -82,15 +74,11 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter { return Span.Empty; } - else - { - return _v1.MixBufferVolume; - } - } - else - { - return _v2.MixBufferVolume; + + return _v1.MixBufferVolume; } + + return _v2.MixBufferVolume; } } @@ -108,15 +96,11 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter { return Span.Empty; } - else - { - return _v1.PreviousMixBufferVolume; - } - } - else - { - return _v2.PreviousMixBufferVolume; + + return _v1.PreviousMixBufferVolume; } + + return _v2.PreviousMixBufferVolume; } } @@ -135,15 +119,11 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter { return new SplitterDestination(); } - else - { - return new SplitterDestination(ref _v1.Next); - } - } - else - { - return new SplitterDestination(ref _v2.Next); + + return new SplitterDestination(ref _v1.Next); } + + return new SplitterDestination(ref _v2.Next); } } } @@ -169,6 +149,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter _v2 = ref v2; } + /// /// Creates a new splitter destination wrapper for the splitter destination data. /// @@ -233,7 +214,12 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// True if the splitter destination is used and has a destination. public readonly bool IsConfigured() { - return Unsafe.IsNullRef(ref _v2) ? _v1.IsConfigured() : _v2.IsConfigured(); + if (Unsafe.IsNullRef(ref _v2)) + { + return _v1.IsConfigured(); + } + + return _v2.IsConfigured(); } /// @@ -243,7 +229,12 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// The volume for the given destination. public float GetMixVolume(int destinationIndex) { - return Unsafe.IsNullRef(ref _v2) ? _v1.GetMixVolume(destinationIndex) : _v2.GetMixVolume(destinationIndex); + if (Unsafe.IsNullRef(ref _v2)) + { + return _v1.GetMixVolume(destinationIndex); + } + + return _v2.GetMixVolume(destinationIndex); } /// @@ -253,7 +244,12 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// The volume for the given destination. public float GetMixVolumePrev(int destinationIndex) { - return Unsafe.IsNullRef(ref _v2) ? _v1.GetMixVolumePrev(destinationIndex) : _v2.GetMixVolumePrev(destinationIndex); + if (Unsafe.IsNullRef(ref _v2)) + { + return _v1.GetMixVolumePrev(destinationIndex); + } + + return _v2.GetMixVolumePrev(destinationIndex); } /// @@ -280,13 +276,13 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter if (Unsafe.IsNullRef(ref _v2)) { Debug.Assert(!Unsafe.IsNullRef(ref next._v1)); - + _v1.Link(ref next._v1); } else { Debug.Assert(!Unsafe.IsNullRef(ref next._v2)); - + _v2.Link(ref next._v2); } } @@ -308,6 +304,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// /// Checks if any biquad filter is enabled. + /// Virtual function at function table + 0x8. /// /// True if any biquad filter is enabled. public bool IsBiquadFilterEnabled() @@ -326,13 +323,14 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// /// Gets the biquad filter parameters. + /// /// Virtual function at function table + 0x10. /// /// Biquad filter index (0 or 1). /// Biquad filter parameters. - public ref BiquadFilterParameter GetBiquadFilterParameter(int index) + public ref BiquadFilterParameter2 GetBiquadFilterParameter(int index) { Debug.Assert(!Unsafe.IsNullRef(ref _v2)); - + return ref _v2.GetBiquadFilterParameter(index); } diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs index 3102ccdf0..7fb455241 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestinationVersion2.cs @@ -1,3 +1,4 @@ +using Ryujinx.Audio.Renderer.Dsp; using Ryujinx.Audio.Renderer.Parameter; using Ryujinx.Common.Memory; using Ryujinx.Common.Utilities; @@ -11,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// /// Server state for a splitter destination (version 2). /// - [StructLayout(LayoutKind.Sequential, Size = 0x110, Pack = Alignment)] + [StructLayout(LayoutKind.Sequential, Size = 0x128, Pack = Alignment)] public struct SplitterDestinationVersion2 { public const int Alignment = 0x10; @@ -78,7 +79,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter } } - private Array2 _biquadFilters; + private Array2 _biquadFilters; private Array2 _isPreviousBiquadFilterEnabled; @@ -109,7 +110,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter parameter.MixBufferVolume.CopyTo(MixBufferVolume); - _biquadFilters = parameter.BiquadFilters; + _biquadFilters = parameter.BiquadFilters2; bool resetPrevVolume = isPrevVolumeResetSupported ? parameter.ResetPrevVolume : !IsUsed && parameter.IsUsed; if (resetPrevVolume) @@ -218,7 +219,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// True if any biquad filter is enabled. public bool IsBiquadFilterEnabled() { - Span biquadFiltersSpan = _biquadFilters.AsSpan(); + Span biquadFiltersSpan = _biquadFilters.AsSpan(); return biquadFiltersSpan[0].Enable || biquadFiltersSpan[1].Enable; } @@ -236,7 +237,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter /// /// Biquad filter index (0 or 1). /// Biquad filter parameters. - public ref BiquadFilterParameter GetBiquadFilterParameter(int index) + public ref BiquadFilterParameter2 GetBiquadFilterParameter(int index) { return ref _biquadFilters[index]; } diff --git a/src/Ryujinx.Audio/Renderer/Server/StateUpdater.cs b/src/Ryujinx.Audio/Renderer/Server/StateUpdater.cs index 27207a90d..a02d70240 100644 --- a/src/Ryujinx.Audio/Renderer/Server/StateUpdater.cs +++ b/src/Ryujinx.Audio/Renderer/Server/StateUpdater.cs @@ -27,39 +27,39 @@ namespace Ryujinx.Audio.Renderer.Server private Memory _output; private readonly uint _processHandle; - private BehaviourContext _behaviourContext; + private BehaviourInfo _behaviourInfo; private readonly ref readonly UpdateDataHeader _inputHeader; private readonly Memory _outputHeader; private readonly ref UpdateDataHeader OutputHeader => ref _outputHeader.Span[0]; - public StateUpdater(ReadOnlySequence input, Memory output, uint processHandle, BehaviourContext behaviourContext) + public StateUpdater(ReadOnlySequence input, Memory output, uint processHandle, BehaviourInfo behaviourInfo) { _inputReader = new SequenceReader(input); _output = output; _outputOrigin = _output; _processHandle = processHandle; - _behaviourContext = behaviourContext; + _behaviourInfo = behaviourInfo; _inputHeader = ref _inputReader.GetRefOrRefToCopy(out _); _outputHeader = SpanMemoryManager.Cast(_output[..Unsafe.SizeOf()]); - OutputHeader.Initialize(_behaviourContext.UserRevision); + OutputHeader.Initialize(_behaviourInfo.UserRevision); _output = _output[Unsafe.SizeOf()..]; } - public ResultCode UpdateBehaviourContext() + public ResultCode UpdateBehaviourInfo() { ref readonly BehaviourParameter parameter = ref _inputReader.GetRefOrRefToCopy(out _); - if (!BehaviourContext.CheckValidRevision(parameter.UserRevision) || parameter.UserRevision != _behaviourContext.UserRevision) + if (!BehaviourInfo.CheckValidRevision(parameter.UserRevision) || parameter.UserRevision != _behaviourInfo.UserRevision) { return ResultCode.InvalidUpdateInfo; } - _behaviourContext.ClearError(); - _behaviourContext.UpdateFlags(parameter.Flags); + _behaviourInfo.ClearError(); + _behaviourInfo.UpdateFlags(parameter.Flags); if (_inputHeader.BehaviourSize != Unsafe.SizeOf()) { @@ -69,16 +69,16 @@ namespace Ryujinx.Audio.Renderer.Server return ResultCode.Success; } - public ResultCode UpdateMemoryPools(Span memoryPools) + public ResultCode UpdateMemoryPools(Span memoryPools) { - PoolMapper mapper = new(_processHandle, _behaviourContext.IsMemoryPoolForceMappingEnabled()); + PoolMapper mapper = new(_processHandle, _behaviourInfo.IsMemoryPoolForceMappingEnabled()); if (memoryPools.Length * Unsafe.SizeOf() != _inputHeader.MemoryPoolsSize) { return ResultCode.InvalidUpdateInfo; } - foreach (ref MemoryPoolState memoryPool in memoryPools) + foreach (ref MemoryPoolInfo memoryPool in memoryPools) { ref readonly MemoryPoolInParameter parameter = ref _inputReader.GetRefOrRefToCopy(out _); @@ -125,10 +125,10 @@ namespace Ryujinx.Audio.Renderer.Server return ResultCode.Success; } - - public ResultCode UpdateVoices(VoiceContext context, PoolMapper mapper) + + public ResultCode UpdateVoices2(VoiceContext context, PoolMapper mapper) { - if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.VoicesSize) + if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.VoicesSize) { return ResultCode.InvalidUpdateInfo; } @@ -140,27 +140,27 @@ namespace Ryujinx.Audio.Renderer.Server // First make everything not in use. for (int i = 0; i < context.GetCount(); i++) { - ref VoiceState state = ref context.GetState(i); + ref VoiceInfo info = ref context.GetState(i); - state.InUse = false; + info.InUse = false; } - Memory[] voiceUpdateStatesArray = ArrayPool>.Shared.Rent(Constants.VoiceChannelCountMax); + Memory[] voiceStatesArray = ArrayPool>.Shared.Rent(Constants.VoiceChannelCountMax); - Span> voiceUpdateStates = voiceUpdateStatesArray.AsSpan(0, Constants.VoiceChannelCountMax); + Span> voiceStates = voiceStatesArray.AsSpan(0, Constants.VoiceChannelCountMax); // Start processing for (int i = 0; i < context.GetCount(); i++) { - ref readonly VoiceInParameter parameter = ref _inputReader.GetRefOrRefToCopy(out _); + ref readonly VoiceInParameter2 parameter = ref _inputReader.GetRefOrRefToCopy(out _); - voiceUpdateStates.Fill(Memory.Empty); + voiceStates.Fill(Memory.Empty); ref VoiceOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; if (parameter.InUse) { - ref VoiceState currentVoiceState = ref context.GetState(i); + ref VoiceInfo currentVoiceInfo = ref context.GetState(i); Span channelResourceIdsSpan = parameter.ChannelResourceIds.AsSpan(); @@ -170,36 +170,123 @@ namespace Ryujinx.Audio.Renderer.Server Debug.Assert(channelId >= 0 && channelId < context.GetCount()); - voiceUpdateStates[channelResourceIndex] = context.GetUpdateStateForCpu(channelId); + voiceStates[channelResourceIndex] = context.GetUpdateStateForCpu(channelId); } if (parameter.IsNew) { - currentVoiceState.Initialize(); + currentVoiceInfo.Initialize(); } - currentVoiceState.UpdateParameters(out ErrorInfo updateParameterError, in parameter, mapper, ref _behaviourContext); + currentVoiceInfo.UpdateParameters2(out ErrorInfo updateParameterError, in parameter, mapper, ref _behaviourInfo); if (updateParameterError.ErrorCode != ResultCode.Success) { - _behaviourContext.AppendError(ref updateParameterError); + _behaviourInfo.AppendError(ref updateParameterError); } - currentVoiceState.UpdateWaveBuffers(out ErrorInfo[] waveBufferUpdateErrorInfos, in parameter, voiceUpdateStates, mapper, ref _behaviourContext); + currentVoiceInfo.UpdateWaveBuffers2(out ErrorInfo[] waveBufferUpdateErrorInfos, in parameter, voiceStates, mapper, ref _behaviourInfo); foreach (ref ErrorInfo errorInfo in waveBufferUpdateErrorInfos.AsSpan()) { if (errorInfo.ErrorCode != ResultCode.Success) { - _behaviourContext.AppendError(ref errorInfo); + _behaviourInfo.AppendError(ref errorInfo); } } - currentVoiceState.WriteOutStatus(ref outStatus, in parameter, voiceUpdateStates); + currentVoiceInfo.WriteOutStatus2(ref outStatus, in parameter, voiceStates); } } - ArrayPool>.Shared.Return(voiceUpdateStatesArray); + ArrayPool>.Shared.Return(voiceStatesArray); + + int currentOutputSize = _output.Length; + + OutputHeader.VoicesSize = (uint)(Unsafe.SizeOf() * context.GetCount()); + OutputHeader.TotalSize += OutputHeader.VoicesSize; + + Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.VoicesSize); + + _inputReader.SetConsumed(initialInputConsumed + _inputHeader.VoicesSize); + + return ResultCode.Success; + } + + public ResultCode UpdateVoices1(VoiceContext context, PoolMapper mapper) + { + if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.VoicesSize) + { + return ResultCode.InvalidUpdateInfo; + } + + int initialOutputSize = _output.Length; + + long initialInputConsumed = _inputReader.Consumed; + + // First make everything not in use. + for (int i = 0; i < context.GetCount(); i++) + { + ref VoiceInfo info = ref context.GetState(i); + + info.InUse = false; + } + + Memory[] voiceStatesArray = ArrayPool>.Shared.Rent(Constants.VoiceChannelCountMax); + + Span> voiceStates = voiceStatesArray.AsSpan(0, Constants.VoiceChannelCountMax); + + // Start processing + for (int i = 0; i < context.GetCount(); i++) + { + ref readonly VoiceInParameter1 parameter = ref _inputReader.GetRefOrRefToCopy(out _); + + voiceStates.Fill(Memory.Empty); + + ref VoiceOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; + + if (parameter.InUse) + { + ref VoiceInfo currentVoiceInfo = ref context.GetState(i); + + Span channelResourceIdsSpan = parameter.ChannelResourceIds.AsSpan(); + + for (int channelResourceIndex = 0; channelResourceIndex < parameter.ChannelCount; channelResourceIndex++) + { + int channelId = channelResourceIdsSpan[channelResourceIndex]; + + Debug.Assert(channelId >= 0 && channelId < context.GetCount()); + + voiceStates[channelResourceIndex] = context.GetUpdateStateForCpu(channelId); + } + + if (parameter.IsNew) + { + currentVoiceInfo.Initialize(); + } + + currentVoiceInfo.UpdateParameters1(out ErrorInfo updateParameterError, in parameter, mapper, ref _behaviourInfo); + + if (updateParameterError.ErrorCode != ResultCode.Success) + { + _behaviourInfo.AppendError(ref updateParameterError); + } + + currentVoiceInfo.UpdateWaveBuffers1(out ErrorInfo[] waveBufferUpdateErrorInfos, in parameter, voiceStates, mapper, ref _behaviourInfo); + + foreach (ref ErrorInfo errorInfo in waveBufferUpdateErrorInfos.AsSpan()) + { + if (errorInfo.ErrorCode != ResultCode.Success) + { + _behaviourInfo.AppendError(ref errorInfo); + } + } + + currentVoiceInfo.WriteOutStatus1(ref outStatus, in parameter, voiceStates); + } + } + + ArrayPool>.Shared.Return(voiceStatesArray); int currentOutputSize = _output.Length; @@ -235,7 +322,12 @@ namespace Ryujinx.Audio.Renderer.Server public ResultCode UpdateEffects(EffectContext context, bool isAudioRendererActive, PoolMapper mapper) { - if (_behaviourContext.IsEffectInfoVersion2Supported()) + if (_behaviourInfo.IsBiquadFilterParameterFloatSupported()) + { + return UpdateEffectsVersion3(context, isAudioRendererActive, mapper); + } + + if (_behaviourInfo.IsEffectInfoVersion2Supported()) { return UpdateEffectsVersion2(context, isAudioRendererActive, mapper); } @@ -243,6 +335,60 @@ namespace Ryujinx.Audio.Renderer.Server return UpdateEffectsVersion1(context, isAudioRendererActive, mapper); } + public ResultCode UpdateEffectsVersion3(EffectContext context, bool isAudioRendererActive, PoolMapper mapper) + { + if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.EffectsSize) + { + return ResultCode.InvalidUpdateInfo; + } + + int initialOutputSize = _output.Length; + + long initialInputConsumed = _inputReader.Consumed; + + for (int i = 0; i < context.GetCount(); i++) + { + ref readonly EffectInParameterVersion3 parameter = ref _inputReader.GetRefOrRefToCopy(out _); + + ref EffectOutStatusVersion2 outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; + + ref BaseEffect effect = ref context.GetEffect(i); + + if (!effect.IsTypeValid(in parameter)) + { + ResetEffect(ref effect, in parameter, mapper); + } + + effect.Update(out ErrorInfo updateErrorInfo, in parameter, mapper); + + if (updateErrorInfo.ErrorCode != ResultCode.Success) + { + _behaviourInfo.AppendError(ref updateErrorInfo); + } + + effect.StoreStatus(ref outStatus, isAudioRendererActive); + + if (parameter.IsNew) + { + effect.InitializeResultState(ref context.GetDspState(i)); + effect.InitializeResultState(ref context.GetState(i)); + } + + effect.UpdateResultState(ref outStatus.ResultState, ref context.GetState(i)); + } + + int currentOutputSize = _output.Length; + + OutputHeader.EffectsSize = (uint)(Unsafe.SizeOf() * context.GetCount()); + OutputHeader.TotalSize += OutputHeader.EffectsSize; + + Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.EffectsSize); + + _inputReader.SetConsumed(initialInputConsumed + _inputHeader.EffectsSize); + + return ResultCode.Success; + } + public ResultCode UpdateEffectsVersion2(EffectContext context, bool isAudioRendererActive, PoolMapper mapper) { if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.EffectsSize) @@ -271,7 +417,7 @@ namespace Ryujinx.Audio.Renderer.Server if (updateErrorInfo.ErrorCode != ResultCode.Success) { - _behaviourContext.AppendError(ref updateErrorInfo); + _behaviourInfo.AppendError(ref updateErrorInfo); } effect.StoreStatus(ref outStatus, isAudioRendererActive); @@ -325,7 +471,7 @@ namespace Ryujinx.Audio.Renderer.Server if (updateErrorInfo.ErrorCode != ResultCode.Success) { - _behaviourContext.AppendError(ref updateErrorInfo); + _behaviourInfo.AppendError(ref updateErrorInfo); } effect.StoreStatus(ref outStatus, isAudioRendererActive); @@ -384,7 +530,7 @@ namespace Ryujinx.Audio.Renderer.Server uint inputMixSize; uint inputSize = 0; - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) + if (_behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()) { ref readonly MixInParameterDirtyOnlyUpdate parameter = ref _inputReader.GetRefOrRefToCopy(out _); @@ -423,12 +569,12 @@ namespace Ryujinx.Audio.Renderer.Server int mixId = i; - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) + if (_behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()) { mixId = parameter.MixId; } - ref MixState mix = ref mixContext.GetState(mixId); + ref MixInfo mix = ref mixContext.GetState(mixId); if (parameter.IsUsed != mix.IsUsed) { @@ -444,13 +590,13 @@ namespace Ryujinx.Audio.Renderer.Server if (mix.IsUsed) { - isMixContextDirty |= mix.Update(mixContext.EdgeMatrix, in parameter, effectContext, splitterContext, _behaviourContext); + isMixContextDirty |= mix.Update(mixContext.EdgeMatrix, in parameter, effectContext, splitterContext, _behaviourInfo); } } if (isMixContextDirty) { - if (_behaviourContext.IsSplitterSupported() && splitterContext.UsingSplitter()) + if (_behaviourInfo.IsSplitterSupported() && splitterContext.UsingSplitter()) { if (!mixContext.Sort(splitterContext)) { @@ -507,7 +653,7 @@ namespace Ryujinx.Audio.Renderer.Server if (updateErrorInfo.ErrorCode != ResultCode.Success) { - _behaviourContext.AppendError(ref updateErrorInfo); + _behaviourInfo.AppendError(ref updateErrorInfo); } } @@ -555,7 +701,7 @@ namespace Ryujinx.Audio.Renderer.Server { ref BehaviourErrorInfoOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - _behaviourContext.CopyErrorInfo(outStatus.ErrorInfos.AsSpan(), out outStatus.ErrorInfosCount); + _behaviourInfo.CopyErrorInfo(outStatus.ErrorInfos.AsSpan(), out outStatus.ErrorInfosCount); OutputHeader.BehaviourSize = (uint)Unsafe.SizeOf(); OutputHeader.TotalSize += OutputHeader.BehaviourSize; diff --git a/src/Ryujinx.Audio/Renderer/Server/Types/PlayState.cs b/src/Ryujinx.Audio/Renderer/Server/Types/PlayState.cs index 46aae05ab..4b72274ce 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Types/PlayState.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Types/PlayState.cs @@ -1,7 +1,9 @@ +using Ryujinx.Audio.Renderer.Server.Voice; + namespace Ryujinx.Audio.Renderer.Server.Types { /// - /// The internal play state of a + /// The internal play state of a /// public enum PlayState { @@ -24,7 +26,7 @@ namespace Ryujinx.Audio.Renderer.Server.Types /// /// /// This is changed to the state after command generation. - /// + /// /// Stopping, diff --git a/src/Ryujinx.Audio/Renderer/Server/Upsampler/UpsamplerState.cs b/src/Ryujinx.Audio/Renderer/Server/Upsampler/UpsamplerInfo.cs similarity index 82% rename from src/Ryujinx.Audio/Renderer/Server/Upsampler/UpsamplerState.cs rename to src/Ryujinx.Audio/Renderer/Server/Upsampler/UpsamplerInfo.cs index 39a58c91a..d84d8fa70 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Upsampler/UpsamplerState.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Upsampler/UpsamplerInfo.cs @@ -5,7 +5,7 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler /// /// Server state for a upsampling. /// - public class UpsamplerState + public class UpsamplerInfo { /// /// The output buffer containing the target samples. @@ -18,7 +18,7 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler public uint SampleCount { get; } /// - /// The index of the . (used to free it) + /// The index of the . (used to free it) /// private readonly int _index; @@ -43,13 +43,13 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler public UpsamplerBufferState[] BufferStates; /// - /// Create a new . + /// Create a new . /// /// The upsampler manager. - /// The index of the . (used to free it) + /// The index of the . (used to free it) /// The output buffer used to contain the target samples. /// The target sample count. - public UpsamplerState(UpsamplerManager manager, int index, Memory outputBuffer, uint sampleCount) + public UpsamplerInfo(UpsamplerManager manager, int index, Memory outputBuffer, uint sampleCount) { _manager = manager; _index = index; @@ -58,7 +58,7 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler } /// - /// Release the . + /// Release the . /// public void Release() { diff --git a/src/Ryujinx.Audio/Renderer/Server/Upsampler/UpsamplerManager.cs b/src/Ryujinx.Audio/Renderer/Server/Upsampler/UpsamplerManager.cs index 8b3f39439..942345f8d 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Upsampler/UpsamplerManager.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Upsampler/UpsamplerManager.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler /// /// The upsamplers instances. /// - private readonly UpsamplerState[] _upsamplers; + private readonly UpsamplerInfo[] _upsamplers; /// /// The count of upsamplers. @@ -39,14 +39,14 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler _upSamplerWorkBuffer = upSamplerWorkBuffer; _count = count; - _upsamplers = new UpsamplerState[_count]; + _upsamplers = new UpsamplerInfo[_count]; } /// - /// Allocate a new . + /// Allocate a new . /// - /// A new or null if out of memory. - public UpsamplerState Allocate() + /// A new or null if out of memory. + public UpsamplerInfo Allocate() { int workBufferOffset = 0; @@ -56,7 +56,7 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler { if (_upsamplers[i] == null) { - _upsamplers[i] = new UpsamplerState(this, i, _upSamplerWorkBuffer.Slice(workBufferOffset, Constants.UpSampleEntrySize), Constants.TargetSampleCount); + _upsamplers[i] = new UpsamplerInfo(this, i, _upSamplerWorkBuffer.Slice(workBufferOffset, Constants.UpSampleEntrySize), Constants.TargetSampleCount); return _upsamplers[i]; } @@ -69,9 +69,9 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler } /// - /// Free a at the given index. + /// Free a at the given index. /// - /// The index of the to free. + /// The index of the to free. public void Free(int index) { lock (_lock) diff --git a/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceContext.cs b/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceContext.cs index 827d24fe5..5cb334ddd 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceContext.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceContext.cs @@ -11,14 +11,14 @@ namespace Ryujinx.Audio.Renderer.Server.Voice public class VoiceContext { /// - /// Storage of the sorted indices to . + /// Storage of the sorted indices to . /// private Memory _sortedVoices; /// - /// Storage for . + /// Storage for . /// - private Memory _voices; + private Memory _voices; /// /// Storage for . @@ -26,27 +26,27 @@ namespace Ryujinx.Audio.Renderer.Server.Voice private Memory _voiceChannelResources; /// - /// Storage for that are used during audio renderer server updates. + /// Storage for that are used during audio renderer server updates. /// - private Memory _voiceUpdateStatesCpu; + private Memory _voiceStatesCpu; /// - /// Storage for for the . + /// Storage for for the . /// - private Memory _voiceUpdateStatesDsp; + private Memory _voiceStatesDsp; /// /// The total voice count. /// private uint _voiceCount; - public void Initialize(Memory sortedVoices, Memory voices, Memory voiceChannelResources, Memory voiceUpdateStatesCpu, Memory voiceUpdateStatesDsp, uint voiceCount) + public void Initialize(Memory sortedVoices, Memory voices, Memory voiceChannelResources, Memory voiceStatesCpu, Memory voiceStatesDsp, uint voiceCount) { _sortedVoices = sortedVoices; _voices = voices; _voiceChannelResources = voiceChannelResources; - _voiceUpdateStatesCpu = voiceUpdateStatesCpu; - _voiceUpdateStatesDsp = voiceUpdateStatesDsp; + _voiceStatesCpu = voiceStatesCpu; + _voiceStatesDsp = voiceStatesDsp; _voiceCount = voiceCount; } @@ -70,38 +70,38 @@ namespace Ryujinx.Audio.Renderer.Server.Voice } /// - /// Get a at the given . + /// Get a at the given . /// /// The index to use. - /// A at the given . - /// The returned should only be used when updating the server state. - public Memory GetUpdateStateForCpu(int id) + /// A at the given . + /// The returned should only be used when updating the server state. + public Memory GetUpdateStateForCpu(int id) { - return SpanIOHelper.GetMemory(_voiceUpdateStatesCpu, id, _voiceCount); + return SpanIOHelper.GetMemory(_voiceStatesCpu, id, _voiceCount); } /// - /// Get a at the given . + /// Get a at the given . /// /// The index to use. - /// A at the given . - /// The returned should only be used in the context of processing on the . - public Memory GetUpdateStateForDsp(int id) + /// A at the given . + /// The returned should only be used in the context of processing on the . + public Memory GetUpdateStateForDsp(int id) { - return SpanIOHelper.GetMemory(_voiceUpdateStatesDsp, id, _voiceCount); + return SpanIOHelper.GetMemory(_voiceStatesDsp, id, _voiceCount); } /// - /// Get a reference to a at the given . + /// Get a reference to a at the given . /// /// The index to use. - /// A reference to a at the given . - public ref VoiceState GetState(int id) + /// A reference to a at the given . + public ref VoiceInfo GetState(int id) { return ref SpanIOHelper.GetFromMemory(_voices, id, _voiceCount); } - public ref VoiceState GetSortedState(int id) + public ref VoiceInfo GetSortedState(int id) { Debug.Assert(id >= 0 && id < _voiceCount); @@ -113,7 +113,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// public void UpdateForCommandGeneration() { - _voiceUpdateStatesDsp.CopyTo(_voiceUpdateStatesCpu); + _voiceStatesDsp.CopyTo(_voiceStatesCpu); } /// @@ -130,14 +130,14 @@ namespace Ryujinx.Audio.Renderer.Server.Voice sortedVoicesTemp.Sort((a, b) => { - ref VoiceState aState = ref GetState(a); - ref VoiceState bState = ref GetState(b); + ref VoiceInfo aInfo = ref GetState(a); + ref VoiceInfo bInfo = ref GetState(b); - int result = aState.Priority.CompareTo(bState.Priority); + int result = aInfo.Priority.CompareTo(bInfo.Priority); if (result == 0) { - return aState.SortingOrder.CompareTo(bState.SortingOrder); + return aInfo.SortingOrder.CompareTo(bInfo.SortingOrder); } return result; diff --git a/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs b/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceInfo.cs similarity index 66% rename from src/Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs rename to src/Ryujinx.Audio/Renderer/Server/Voice/VoiceInfo.cs index 9fcff199d..ba6158b71 100644 --- a/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs +++ b/src/Ryujinx.Audio/Renderer/Server/Voice/VoiceInfo.cs @@ -1,5 +1,6 @@ using Ryujinx.Audio.Common; using Ryujinx.Audio.Renderer.Common; +using Ryujinx.Audio.Renderer.Dsp; using Ryujinx.Audio.Renderer.Dsp.State; using Ryujinx.Audio.Renderer.Parameter; using Ryujinx.Audio.Renderer.Server.MemoryPool; @@ -9,13 +10,13 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; +using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter1; using PlayState = Ryujinx.Audio.Renderer.Server.Types.PlayState; namespace Ryujinx.Audio.Renderer.Server.Voice { [StructLayout(LayoutKind.Sequential, Pack = Alignment)] - public struct VoiceState + public struct VoiceInfo { public const int Alignment = 0x10; @@ -102,7 +103,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// /// Biquad filters to apply to the output of the voice. /// - public Array2 BiquadFilters; + public Array2 BiquadFilters; /// /// Total count of of the voice. @@ -185,7 +186,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice public Span BiquadFilterNeedInitialization => SpanHelpers.AsSpan(ref _biquadFilterNeedInitialization); /// - /// Initialize the . + /// Initialize the . /// public void Initialize() { @@ -215,7 +216,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice } /// - /// Initialize the in this . + /// Initialize the in this . /// private void InitializeWaveBuffers() { @@ -250,13 +251,13 @@ namespace Ryujinx.Audio.Renderer.Server.Voice { return MixId != Constants.UnusedMixId || SplitterId != Constants.UnusedSplitterId; } - + /// /// Indicate if the server voice information needs to be updated. /// /// The user parameter. /// Return true, if the server voice information needs to be updated. - private readonly bool ShouldUpdateParameters(in VoiceInParameter parameter) + private readonly bool ShouldUpdateParameters2(in VoiceInParameter2 parameter) { if (DataSourceStateAddressInfo.CpuAddress == parameter.DataSourceStateAddress) { @@ -268,14 +269,31 @@ namespace Ryujinx.Audio.Renderer.Server.Voice DataSourceStateUnmapped; } + /// + /// Indicate if the server voice information needs to be updated. + /// + /// The user parameter. + /// Return true, if the server voice information needs to be updated. + private readonly bool ShouldUpdateParameters1(in VoiceInParameter1 parameter) + { + if (DataSourceStateAddressInfo.CpuAddress == parameter.DataSourceStateAddress) + { + return DataSourceStateAddressInfo.Size != parameter.DataSourceStateSize; + } + + return DataSourceStateAddressInfo.CpuAddress != parameter.DataSourceStateAddress || + DataSourceStateAddressInfo.Size != parameter.DataSourceStateSize || + DataSourceStateUnmapped; + } + /// /// Update the internal state from a user parameter. /// /// The possible that was generated. /// The user parameter. /// The mapper to use. - /// The behaviour context. - public void UpdateParameters(out ErrorInfo outErrorInfo, in VoiceInParameter parameter, PoolMapper poolMapper, ref BehaviourContext behaviourContext) + /// The behaviour context. + public void UpdateParameters2(out ErrorInfo outErrorInfo, in VoiceInParameter2 parameter, PoolMapper poolMapper, ref BehaviourInfo behaviourInfo) { InUse = parameter.InUse; Id = parameter.Id; @@ -296,14 +314,14 @@ namespace Ryujinx.Audio.Renderer.Server.Voice WaveBuffersCount = parameter.WaveBuffersCount; WaveBuffersIndex = parameter.WaveBuffersIndex; - if (behaviourContext.IsFlushVoiceWaveBuffersSupported()) + if (behaviourInfo.IsFlushVoiceWaveBuffersSupported()) { FlushWaveBufferCount += parameter.FlushWaveBufferCount; } MixId = parameter.MixId; - if (behaviourContext.IsSplitterSupported()) + if (behaviourInfo.IsSplitterSupported()) { SplitterId = parameter.SplitterId; } @@ -316,7 +334,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice DecodingBehaviour behaviour = DecodingBehaviour.Default; - if (behaviourContext.IsDecodingBehaviourFlagSupported()) + if (behaviourInfo.IsDecodingBehaviourFlagSupported()) { behaviour = parameter.DecodingBehaviourFlags; } @@ -328,7 +346,78 @@ namespace Ryujinx.Audio.Renderer.Server.Voice VoiceDropFlag = false; } - if (ShouldUpdateParameters(in parameter)) + if (ShouldUpdateParameters2(in parameter)) + { + DataSourceStateUnmapped = !poolMapper.TryAttachBuffer(out outErrorInfo, ref DataSourceStateAddressInfo, parameter.DataSourceStateAddress, parameter.DataSourceStateSize); + } + else + { + outErrorInfo = new ErrorInfo(); + } + } + + /// + /// Update the internal state from a user parameter. + /// + /// The possible that was generated. + /// The user paramter2. + /// The mapper to use. + /// The behaviour context. + public void UpdateParameters1(out ErrorInfo outErrorInfo, in VoiceInParameter1 parameter, PoolMapper poolMapper, ref BehaviourInfo behaviourInfo) + { + InUse = parameter.InUse; + Id = parameter.Id; + NodeId = parameter.NodeId; + + UpdatePlayState(parameter.PlayState); + + SrcQuality = parameter.SrcQuality; + + Priority = parameter.Priority; + SortingOrder = parameter.SortingOrder; + SampleRate = parameter.SampleRate; + SampleFormat = parameter.SampleFormat; + ChannelsCount = parameter.ChannelCount; + Pitch = parameter.Pitch; + Volume = parameter.Volume; + BiquadFilters[0] = BiquadFilterHelper.ToBiquadFilterParameter2(parameter.BiquadFilters[0]); + BiquadFilters[1] = BiquadFilterHelper.ToBiquadFilterParameter2(parameter.BiquadFilters[1]); + WaveBuffersCount = parameter.WaveBuffersCount; + WaveBuffersIndex = parameter.WaveBuffersIndex; + + if (behaviourInfo.IsFlushVoiceWaveBuffersSupported()) + { + FlushWaveBufferCount += parameter.FlushWaveBufferCount; + } + + MixId = parameter.MixId; + + if (behaviourInfo.IsSplitterSupported()) + { + SplitterId = parameter.SplitterId; + } + else + { + SplitterId = Constants.UnusedSplitterId; + } + + parameter.ChannelResourceIds.AsSpan().CopyTo(ChannelResourceIds.AsSpan()); + + DecodingBehaviour behaviour = DecodingBehaviour.Default; + + if (behaviourInfo.IsDecodingBehaviourFlagSupported()) + { + behaviour = parameter.DecodingBehaviourFlags; + } + + DecodingBehaviour = behaviour; + + if (parameter.ResetVoiceDropFlag) + { + VoiceDropFlag = false; + } + + if (ShouldUpdateParameters1(in parameter)) { DataSourceStateUnmapped = !poolMapper.TryAttachBuffer(out outErrorInfo, ref DataSourceStateAddressInfo, parameter.DataSourceStateAddress, parameter.DataSourceStateSize); } @@ -375,14 +464,14 @@ namespace Ryujinx.Audio.Renderer.Server.Voice PlayState = newServerPlayState; } - + /// /// Write the status of the voice to the given user output. /// /// The given user output. /// The user parameter. - /// The voice states associated to the . - public void WriteOutStatus(ref VoiceOutStatus outStatus, in VoiceInParameter parameter, ReadOnlySpan> voiceUpdateStates) + /// The voice states associated to the . + public void WriteOutStatus2(ref VoiceOutStatus outStatus, in VoiceInParameter2 parameter, ReadOnlySpan> voiceStates) { #if DEBUG // Sanity check in debug mode of the internal state @@ -390,8 +479,8 @@ namespace Ryujinx.Audio.Renderer.Server.Voice { for (int i = 1; i < ChannelsCount; i++) { - ref VoiceUpdateState stateA = ref voiceUpdateStates[i - 1].Span[0]; - ref VoiceUpdateState stateB = ref voiceUpdateStates[i].Span[0]; + ref VoiceState stateA = ref voiceStates[i - 1].Span[0]; + ref VoiceState stateB = ref voiceStates[i].Span[0]; Debug.Assert(stateA.WaveBufferConsumed == stateB.WaveBufferConsumed); Debug.Assert(stateA.PlayedSampleCount == stateB.PlayedSampleCount); @@ -412,7 +501,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice } else { - ref VoiceUpdateState state = ref voiceUpdateStates[0].Span[0]; + ref VoiceState state = ref voiceStates[0].Span[0]; outStatus.VoiceDropFlag = VoiceDropFlag; outStatus.PlayedWaveBuffersCount = state.WaveBufferConsumed; @@ -421,19 +510,63 @@ namespace Ryujinx.Audio.Renderer.Server.Voice } /// - /// Update the internal state of all the of the . + /// Write the status of the voice to the given user output. + /// + /// The given user output. + /// The user parameter. + /// The voice states associated to the . + public void WriteOutStatus1(ref VoiceOutStatus outStatus, in VoiceInParameter1 parameter, ReadOnlySpan> voiceStates) + { +#if DEBUG + // Sanity check in debug mode of the internal state + if (!parameter.IsNew && !IsNew) + { + for (int i = 1; i < ChannelsCount; i++) + { + ref VoiceState stateA = ref voiceStates[i - 1].Span[0]; + ref VoiceState stateB = ref voiceStates[i].Span[0]; + + Debug.Assert(stateA.WaveBufferConsumed == stateB.WaveBufferConsumed); + Debug.Assert(stateA.PlayedSampleCount == stateB.PlayedSampleCount); + Debug.Assert(stateA.Offset == stateB.Offset); + Debug.Assert(stateA.WaveBufferIndex == stateB.WaveBufferIndex); + Debug.Assert(stateA.Fraction == stateB.Fraction); + Debug.Assert(stateA.IsWaveBufferValid.SequenceEqual(stateB.IsWaveBufferValid)); + } + } +#endif + if (parameter.IsNew || IsNew) + { + IsNew = true; + + outStatus.VoiceDropFlag = false; + outStatus.PlayedWaveBuffersCount = 0; + outStatus.PlayedSampleCount = 0; + } + else + { + ref VoiceState state = ref voiceStates[0].Span[0]; + + outStatus.VoiceDropFlag = VoiceDropFlag; + outStatus.PlayedWaveBuffersCount = state.WaveBufferConsumed; + outStatus.PlayedSampleCount = state.PlayedSampleCount; + } + } + + /// + /// Update the internal state of all the of the . /// /// An array of used to report errors when mapping any of the . /// The user parameter. - /// The voice states associated to the . + /// The voice states associated to the . /// The mapper to use. - /// The behaviour context. - public void UpdateWaveBuffers( + /// The behaviour context. + public void UpdateWaveBuffers2( out ErrorInfo[] errorInfos, - in VoiceInParameter parameter, - ReadOnlySpan> voiceUpdateStates, + in VoiceInParameter2 parameter, + ReadOnlySpan> voiceStates, PoolMapper mapper, - ref BehaviourContext behaviourContext) + ref BehaviourInfo behaviourInfo) { errorInfos = new ErrorInfo[Constants.VoiceWaveBufferCount * 2]; @@ -443,23 +576,61 @@ namespace Ryujinx.Audio.Renderer.Server.Voice for (int i = 0; i < parameter.ChannelCount; i++) { - voiceUpdateStates[i].Span[0].IsWaveBufferValid.Clear(); + voiceStates[i].Span[0].IsWaveBufferValid.Clear(); } } - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[0].Span[0]; + ref VoiceState voiceState = ref voiceStates[0].Span[0]; Span waveBuffersSpan = WaveBuffers.AsSpan(); Span pWaveBuffersSpan = parameter.WaveBuffers.AsSpan(); for (int i = 0; i < Constants.VoiceWaveBufferCount; i++) { - UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref waveBuffersSpan[i], ref pWaveBuffersSpan[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], mapper, ref behaviourContext); + UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref waveBuffersSpan[i], ref pWaveBuffersSpan[i], parameter.SampleFormat, voiceState.IsWaveBufferValid[i], mapper, ref behaviourInfo); } } /// - /// Update the internal state of one of the of the . + /// Update the internal state of all the of the . + /// + /// An array of used to report errors when mapping any of the . + /// The user parameter. + /// The voice states associated to the . + /// The mapper to use. + /// The behaviour context. + public void UpdateWaveBuffers1( + out ErrorInfo[] errorInfos, + in VoiceInParameter1 parameter, + ReadOnlySpan> voiceStates, + PoolMapper mapper, + ref BehaviourInfo behaviourInfo) + { + errorInfos = new ErrorInfo[Constants.VoiceWaveBufferCount * 2]; + + if (parameter.IsNew) + { + InitializeWaveBuffers(); + + for (int i = 0; i < parameter.ChannelCount; i++) + { + voiceStates[i].Span[0].IsWaveBufferValid.Clear(); + } + } + + ref VoiceState voiceState = ref voiceStates[0].Span[0]; + + Span waveBuffersSpan = WaveBuffers.AsSpan(); + Span pWaveBuffersSpan = parameter.WaveBuffers.AsSpan(); + + for (int i = 0; i < Constants.VoiceWaveBufferCount; i++) + { + UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref waveBuffersSpan[i], ref pWaveBuffersSpan[i], parameter.SampleFormat, voiceState.IsWaveBufferValid[i], mapper, ref behaviourInfo); + } + } + + /// + /// Update the internal state of one of the of the . /// /// A used to report errors when mapping the . /// The to update. @@ -467,7 +638,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// The from the user input. /// If set to true, the server side wavebuffer is considered valid. /// The mapper to use. - /// The behaviour context. + /// The behaviour context. private void UpdateWaveBuffer( Span errorInfos, ref WaveBuffer waveBuffer, @@ -475,7 +646,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice SampleFormat sampleFormat, bool isValid, PoolMapper mapper, - ref BehaviourContext behaviourContext) + ref BehaviourInfo behaviourInfo) { if (!isValid && waveBuffer.IsSendToAudioProcessor && waveBuffer.BufferAddressInfo.CpuAddress != 0) { @@ -502,7 +673,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice errorInfos[0] = bufferInfoError; - if (sampleFormat == SampleFormat.Adpcm && behaviourContext.IsAdpcmLoopContextBugFixed() && inputWaveBuffer.ContextAddress != 0) + if (sampleFormat == SampleFormat.Adpcm && behaviourInfo.IsAdpcmLoopContextBugFixed() && inputWaveBuffer.ContextAddress != 0) { bool adpcmLoopContextMapped = mapper.TryAttachBuffer(out ErrorInfo adpcmLoopContextInfoError, ref waveBuffer.ContextAddressInfo, @@ -511,13 +682,13 @@ namespace Ryujinx.Audio.Renderer.Server.Voice errorInfos[1] = adpcmLoopContextInfoError; - if (adpcmLoopContextMapped) + if (!adpcmLoopContextMapped || BufferInfoUnmapped) { - BufferInfoUnmapped = DataSourceStateUnmapped; + BufferInfoUnmapped = true; } else { - BufferInfoUnmapped = true; + BufferInfoUnmapped = false; } } else @@ -534,7 +705,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice } /// - /// Reset the resources associated to this . + /// Reset the resources associated to this . /// /// The voice context. private void ResetResources(VoiceContext context) @@ -549,9 +720,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice Debug.Assert(voiceChannelResource.IsUsed); - Memory dspSharedState = context.GetUpdateStateForDsp(channelResourceId); + Memory dspSharedState = context.GetUpdateStateForDsp(channelResourceId); - MemoryMarshal.Cast(dspSharedState.Span).Clear(); + MemoryMarshal.Cast(dspSharedState.Span).Clear(); voiceChannelResource.UpdateState(); } @@ -561,9 +732,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// Flush a certain amount of . /// /// The amount of wavebuffer to flush. - /// The voice states associated to the . + /// The voice states associated to the . /// The channel count from user input. - private void FlushWaveBuffers(uint waveBufferCount, Memory[] voiceUpdateStates, uint channelCount) + private void FlushWaveBuffers(uint waveBufferCount, Memory[] voiceStates, uint channelCount) { uint waveBufferIndex = WaveBuffersIndex; @@ -575,12 +746,17 @@ namespace Ryujinx.Audio.Renderer.Server.Voice for (int j = 0; j < channelCount; j++) { - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[j].Span[0]; - - voiceUpdateState.WaveBufferIndex = (voiceUpdateState.WaveBufferIndex + 1) % Constants.VoiceWaveBufferCount; - voiceUpdateState.WaveBufferConsumed++; - voiceUpdateState.IsWaveBufferValid[(int)waveBufferIndex] = false; + ref VoiceState voiceState = ref voiceStates[j].Span[0]; + + if (!waveBuffersSpan[(int)waveBufferIndex].IsSendToAudioProcessor || voiceState.IsWaveBufferValid[(int)waveBufferIndex]) + { + voiceState.WaveBufferIndex = (voiceState.WaveBufferIndex + 1) % Constants.VoiceWaveBufferCount; + voiceState.WaveBufferConsumed++; + voiceState.IsWaveBufferValid[(int)waveBufferIndex] = false; + } } + + waveBuffersSpan[(int)waveBufferIndex].IsSendToAudioProcessor = true; waveBufferIndex = (waveBufferIndex + 1) % Constants.VoiceWaveBufferCount; } @@ -589,13 +765,13 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// /// Update the internal parameters for command generation. /// - /// The voice states associated to the . + /// The voice states associated to the . /// Return true if this voice should be played. - public bool UpdateParametersForCommandGeneration(Memory[] voiceUpdateStates) + public bool UpdateParametersForCommandGeneration(Memory[] voiceStates) { if (FlushWaveBufferCount != 0) { - FlushWaveBuffers(FlushWaveBufferCount, voiceUpdateStates, ChannelsCount); + FlushWaveBuffers(FlushWaveBufferCount, voiceStates, ChannelsCount); FlushWaveBufferCount = 0; } @@ -615,9 +791,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice { for (int y = 0; y < ChannelsCount; y++) { - Debug.Assert(!voiceUpdateStates[y].Span[0].IsWaveBufferValid[i]); + Debug.Assert(!voiceStates[y].Span[0].IsWaveBufferValid[i]); - voiceUpdateStates[y].Span[0].IsWaveBufferValid[i] = true; + voiceStates[y].Span[0].IsWaveBufferValid[i] = true; } waveBuffer.IsSendToAudioProcessor = true; @@ -626,11 +802,11 @@ namespace Ryujinx.Audio.Renderer.Server.Voice WasPlaying = false; - ref VoiceUpdateState primaryVoiceUpdateState = ref voiceUpdateStates[0].Span[0]; + ref VoiceState primaryVoiceState = ref voiceStates[0].Span[0]; - for (int i = 0; i < primaryVoiceUpdateState.IsWaveBufferValid.Length; i++) + for (int i = 0; i < primaryVoiceState.IsWaveBufferValid.Length; i++) { - if (primaryVoiceUpdateState.IsWaveBufferValid[i]) + if (primaryVoiceState.IsWaveBufferValid[i]) { return true; } @@ -649,27 +825,27 @@ namespace Ryujinx.Audio.Renderer.Server.Voice for (int j = 0; j < ChannelsCount; j++) { - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[j].Span[0]; + ref VoiceState voiceState = ref voiceStates[j].Span[0]; - if (voiceUpdateState.IsWaveBufferValid[i]) + if (voiceState.IsWaveBufferValid[i]) { - voiceUpdateState.WaveBufferIndex = (voiceUpdateState.WaveBufferIndex + 1) % Constants.VoiceWaveBufferCount; - voiceUpdateState.WaveBufferConsumed++; + voiceState.WaveBufferIndex = (voiceState.WaveBufferIndex + 1) % Constants.VoiceWaveBufferCount; + voiceState.WaveBufferConsumed++; } - voiceUpdateState.IsWaveBufferValid[i] = false; + voiceState.IsWaveBufferValid[i] = false; } } for (int i = 0; i < ChannelsCount; i++) { - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[i].Span[0]; + ref VoiceState voiceState = ref voiceStates[i].Span[0]; - voiceUpdateState.Offset = 0; - voiceUpdateState.PlayedSampleCount = 0; - voiceUpdateState.Pitch.AsSpan().Clear(); - voiceUpdateState.Fraction = 0; - voiceUpdateState.LoopContext = new AdpcmLoopContext(); + voiceState.Offset = 0; + voiceState.PlayedSampleCount = 0; + voiceState.Pitch.AsSpan().Clear(); + voiceState.Fraction = 0; + voiceState.LoopContext = new AdpcmLoopContext(); } PlayState = PlayState.Stopped; @@ -715,16 +891,16 @@ namespace Ryujinx.Audio.Renderer.Server.Voice IsNew = false; } - Memory[] voiceUpdateStates = new Memory[Constants.VoiceChannelCountMax]; + Memory[] voiceStates = new Memory[Constants.VoiceChannelCountMax]; Span channelResourceIdsSpan = ChannelResourceIds.AsSpan(); for (int i = 0; i < ChannelsCount; i++) { - voiceUpdateStates[i] = context.GetUpdateStateForDsp(channelResourceIdsSpan[i]); + voiceStates[i] = context.GetUpdateStateForDsp(channelResourceIdsSpan[i]); } - return UpdateParametersForCommandGeneration(voiceUpdateStates); + return UpdateParametersForCommandGeneration(voiceStates); } } } diff --git a/src/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/ISampledDataStruct.cs b/src/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/ISampledDataStruct.cs index 312075bc4..5a6aab495 100644 --- a/src/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/ISampledDataStruct.cs +++ b/src/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/ISampledDataStruct.cs @@ -50,7 +50,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common ulong value = BinaryPrimitives.ReadUInt64LittleEndian(byteSpan); - return value; + return value << 1; } private static int GetSamplingNumberFieldOffset(ref T sampledDataStruct) where T : unmanaged, ISampledDataStruct diff --git a/src/Ryujinx.Horizon/Audio/AudioUserIpcServer.cs b/src/Ryujinx.Horizon/Audio/AudioUserIpcServer.cs index 20c824e1e..1de123f7f 100644 --- a/src/Ryujinx.Horizon/Audio/AudioUserIpcServer.cs +++ b/src/Ryujinx.Horizon/Audio/AudioUserIpcServer.cs @@ -33,11 +33,13 @@ namespace Ryujinx.Horizon.Audio AudioOutManager audioOutManager = new(_managers.AudioOutputManager); AudioInManager audioInManager = new(_managers.AudioInputManager); FinalOutputRecorderManager finalOutputRecorderManager = new(); + AudioSnoopManager audioSnoopManager = new(); _serverManager.RegisterObjectForServer(audioRendererManager, ServiceName.Encode("audren:u"), MaxSessionsCount); _serverManager.RegisterObjectForServer(audioOutManager, ServiceName.Encode("audout:u"), MaxSessionsCount); _serverManager.RegisterObjectForServer(audioInManager, ServiceName.Encode("audin:u"), MaxSessionsCount); _serverManager.RegisterObjectForServer(finalOutputRecorderManager, ServiceName.Encode("audrec:u"), MaxSessionsCount); + _serverManager.RegisterObjectForServer(audioSnoopManager, ServiceName.Encode("auddev"), MaxSessionsCount); } public void ServiceRequests() diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs index 583a04de3..4fda4bc61 100644 --- a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioDevice.cs @@ -23,10 +23,10 @@ namespace Ryujinx.Horizon.Sdk.Audio.Detail { _registry = registry; - BehaviourContext behaviourContext = new(); - behaviourContext.SetUserRevision((int)revision); + BehaviourInfo behaviourInfo = new(); + behaviourInfo.SetUserRevision((int)revision); - _isUsbDeviceSupported = behaviourContext.IsAudioUsbDeviceOutputSupported(); + _isUsbDeviceSupported = behaviourInfo.IsAudioUsbDeviceOutputSupported(); _sessions = registry.GetSessionByAppletResourceId(appletResourceId.Id); Os.CreateSystemEvent(out _audioEvent, EventClearMode.AutoClear, interProcess: true); diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererManager.cs index 40cbecc40..e7eedeccd 100644 --- a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererManager.cs +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioRendererManager.cs @@ -61,7 +61,7 @@ namespace Ryujinx.Horizon.Sdk.Audio.Detail [CmifCommand(1)] public Result GetWorkBufferSize(out long workBufferSize, AudioRendererParameterInternal parameter) { - if (BehaviourContext.CheckValidRevision(parameter.Configuration.Revision)) + if (BehaviourInfo.CheckValidRevision(parameter.Configuration.Revision)) { workBufferSize = (long)Ryujinx.Audio.Renderer.Server.AudioRendererManager.GetWorkBufferSize(ref parameter.Configuration); @@ -73,7 +73,7 @@ namespace Ryujinx.Horizon.Sdk.Audio.Detail { workBufferSize = 0; - Logger.Warning?.Print(LogClass.ServiceAudio, $"Library Revision REV{BehaviourContext.GetRevisionNumber(parameter.Configuration.Revision)} is not supported!"); + Logger.Warning?.Print(LogClass.ServiceAudio, $"Library Revision REV{BehaviourInfo.GetRevisionNumber(parameter.Configuration.Revision)} is not supported!"); return AudioResult.UnsupportedRevision; } diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioSnoopManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioSnoopManager.cs index cf1fe3d1d..5eb31a14b 100644 --- a/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioSnoopManager.cs +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/AudioSnoopManager.cs @@ -1,30 +1,64 @@ using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; namespace Ryujinx.Horizon.Sdk.Audio.Detail { partial class AudioSnoopManager : IAudioSnoopManager { + private byte[] _dspStatisticsParameter; + // Note: The interface changed completely on firmware 17.0.0, this implementation is for older firmware. - [CmifCommand(0)] + [CmifCommand(0)] // [6.0.0-16.1.0] public Result EnableDspUsageMeasurement() { return Result.Success; } - [CmifCommand(1)] + [CmifCommand(1)] // [6.0.0-16.1.0] public Result DisableDspUsageMeasurement() { return Result.Success; } - - [CmifCommand(6)] + + [CmifCommand(6)] // [6.0.0-16.1.0] public Result GetDspUsage(out uint usage) { usage = 0; return Result.Success; } + + [CmifCommand(0)] // 17.0.0+ + public Result GetDspStatistics(out uint statistics) => GetDspUsage(out statistics); + + [CmifCommand(1)] // 20.0.0+ + public Result GetAppletStateSummaries([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span summaries) + { + // Since we do not have any real applets, return empty state summaries. + summaries.Clear(); + + return Result.Success; + } + + [CmifCommand(2)] // 20.0.0+ + public Result SetDspStatisticsParameter([Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan parameter) + { + _dspStatisticsParameter = null; + _dspStatisticsParameter = new byte[0x100]; + parameter.CopyTo(_dspStatisticsParameter); + + return Result.Success; + } + + [CmifCommand(3)] // 20.0.0+ + public Result GetDspStatisticsParameter([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span parameter) + { + _dspStatisticsParameter.CopyTo(parameter); + + return Result.Success; + } } } diff --git a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioSnoopManager.cs b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioSnoopManager.cs index 72853886a..9a52beb30 100644 --- a/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioSnoopManager.cs +++ b/src/Ryujinx.Horizon/Sdk/Audio/Detail/IAudioSnoopManager.cs @@ -1,5 +1,6 @@ using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Sdk.Sf; +using System; namespace Ryujinx.Horizon.Sdk.Audio.Detail { @@ -8,5 +9,10 @@ namespace Ryujinx.Horizon.Sdk.Audio.Detail Result EnableDspUsageMeasurement(); Result DisableDspUsageMeasurement(); Result GetDspUsage(out uint usage); + + Result GetDspStatistics(out uint statistics); + Result GetAppletStateSummaries(Span summaries); + Result SetDspStatisticsParameter(ReadOnlySpan parameter); + Result GetDspStatisticsParameter(Span parameter); } } diff --git a/src/Ryujinx.Tests/Audio/Renderer/BiquadFilterParameterTests.cs b/src/Ryujinx.Tests/Audio/Renderer/BiquadFilterParameterTests.cs index 617b52457..76e8a180a 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/BiquadFilterParameterTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/BiquadFilterParameterTests.cs @@ -9,7 +9,8 @@ namespace Ryujinx.Tests.Audio.Renderer [Test] public void EnsureTypeSize() { - Assert.AreEqual(0xC, Unsafe.SizeOf()); + Assert.AreEqual(0xC, Unsafe.SizeOf()); + Assert.AreEqual(0x18, Unsafe.SizeOf()); } } } diff --git a/src/Ryujinx.Tests/Audio/Renderer/Common/VoiceUpdateStateTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Common/VoiceStateTests.cs similarity index 68% rename from src/Ryujinx.Tests/Audio/Renderer/Common/VoiceUpdateStateTests.cs rename to src/Ryujinx.Tests/Audio/Renderer/Common/VoiceStateTests.cs index 7b09d18cc..eff982670 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/Common/VoiceUpdateStateTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/Common/VoiceStateTests.cs @@ -4,12 +4,12 @@ using System.Runtime.CompilerServices; namespace Ryujinx.Tests.Audio.Renderer.Common { - class VoiceUpdateStateTests + class VoiceStateTests { [Test] public void EnsureTypeSize() { - Assert.LessOrEqual(Unsafe.SizeOf(), 0x100); + Assert.LessOrEqual(Unsafe.SizeOf(), 0x100); } } } diff --git a/src/Ryujinx.Tests/Audio/Renderer/Dsp/ResamplerTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Dsp/ResamplerTests.cs index f393c971a..b774b74e1 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/Dsp/ResamplerTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/Dsp/ResamplerTests.cs @@ -8,19 +8,19 @@ namespace Ryujinx.Tests.Audio.Renderer.Dsp class ResamplerTests { [Test] - [TestCase(VoiceInParameter.SampleRateConversionQuality.Low)] - [TestCase(VoiceInParameter.SampleRateConversionQuality.Default)] - [TestCase(VoiceInParameter.SampleRateConversionQuality.High)] - public void TestResamplerConsistencyUpsampling(VoiceInParameter.SampleRateConversionQuality quality) + [TestCase(SampleRateConversionQuality.Low)] + [TestCase(SampleRateConversionQuality.Default)] + [TestCase(SampleRateConversionQuality.High)] + public void TestResamplerConsistencyUpsampling(SampleRateConversionQuality quality) { DoResamplingTest(44100, 48000, quality); } [Test] - [TestCase(VoiceInParameter.SampleRateConversionQuality.Low)] - [TestCase(VoiceInParameter.SampleRateConversionQuality.Default)] - [TestCase(VoiceInParameter.SampleRateConversionQuality.High)] - public void TestResamplerConsistencyDownsampling(VoiceInParameter.SampleRateConversionQuality quality) + [TestCase(SampleRateConversionQuality.Low)] + [TestCase(SampleRateConversionQuality.Default)] + [TestCase(SampleRateConversionQuality.High)] + public void TestResamplerConsistencyDownsampling(SampleRateConversionQuality quality) { DoResamplingTest(48000, 44100, quality); } @@ -32,7 +32,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Dsp /// The input sample rate to test /// The output sample rate to test /// The resampler quality to use - private static void DoResamplingTest(int inputRate, int outputRate, VoiceInParameter.SampleRateConversionQuality quality) + private static void DoResamplingTest(int inputRate, int outputRate, SampleRateConversionQuality quality) { float inputSampleRate = inputRate; float outputSampleRate = outputRate; @@ -61,8 +61,8 @@ namespace Ryujinx.Tests.Audio.Renderer.Dsp float sumDifference = 0; int delay = quality switch { - VoiceInParameter.SampleRateConversionQuality.High => 3, - VoiceInParameter.SampleRateConversionQuality.Default => 1, + SampleRateConversionQuality.High => 3, + SampleRateConversionQuality.Default => 1, _ => 0, }; diff --git a/src/Ryujinx.Tests/Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameterTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameterTests.cs index 73c1ea9d3..d76478ed8 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameterTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameterTests.cs @@ -9,7 +9,8 @@ namespace Ryujinx.Tests.Audio.Renderer.Parameter.Effect [Test] public void EnsureTypeSize() { - Assert.AreEqual(0x18, Unsafe.SizeOf()); + Assert.AreEqual(0x18, Unsafe.SizeOf()); + Assert.AreEqual(0x24, Unsafe.SizeOf()); } } } diff --git a/src/Ryujinx.Tests/Audio/Renderer/Server/AddressInfoTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Server/AddressInfoTests.cs index 53a662584..6f855d3a4 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/Server/AddressInfoTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/Server/AddressInfoTests.cs @@ -16,8 +16,8 @@ namespace Ryujinx.Tests.Audio.Renderer.Server [Test] public void TestGetReference() { - MemoryPoolState[] memoryPoolState = new MemoryPoolState[1]; - memoryPoolState[0] = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); + MemoryPoolInfo[] memoryPoolState = new MemoryPoolInfo[1]; + memoryPoolState[0] = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Cpu); memoryPoolState[0].SetCpuAddress(0x1000000, 0x10000); memoryPoolState[0].DspAddress = 0x4000000; diff --git a/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs deleted file mode 100644 index 0b0ed7a54..000000000 --- a/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs +++ /dev/null @@ -1,413 +0,0 @@ -using NUnit.Framework; -using Ryujinx.Audio.Renderer.Server; - -namespace Ryujinx.Tests.Audio.Renderer.Server -{ - public class BehaviourContextTests - { - [Test] - public void TestCheckFeature() - { - int latestRevision = BehaviourContext.BaseRevisionMagic + BehaviourContext.LastRevision; - int previousRevision = BehaviourContext.BaseRevisionMagic + (BehaviourContext.LastRevision - 1); - int invalidRevision = BehaviourContext.BaseRevisionMagic + (BehaviourContext.LastRevision + 1); - - Assert.IsTrue(BehaviourContext.CheckFeatureSupported(latestRevision, latestRevision)); - Assert.IsFalse(BehaviourContext.CheckFeatureSupported(previousRevision, latestRevision)); - Assert.IsTrue(BehaviourContext.CheckFeatureSupported(latestRevision, previousRevision)); - // In case we get an invalid revision, this is supposed to auto default to REV1 internally.. idk what the hell Nintendo was thinking here.. - Assert.IsTrue(BehaviourContext.CheckFeatureSupported(invalidRevision, latestRevision)); - } - - [Test] - public void TestsMemoryPoolForceMappingEnabled() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision1); - - Assert.IsFalse(behaviourContext.IsMemoryPoolForceMappingEnabled()); - - behaviourContext.UpdateFlags(0x1); - - Assert.IsTrue(behaviourContext.IsMemoryPoolForceMappingEnabled()); - } - - [Test] - public void TestRevision1() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision1); - - Assert.IsFalse(behaviourContext.IsAdpcmLoopContextBugFixed()); - Assert.IsFalse(behaviourContext.IsSplitterSupported()); - Assert.IsFalse(behaviourContext.IsLongSizePreDelaySupported()); - Assert.IsFalse(behaviourContext.IsAudioUsbDeviceOutputSupported()); - Assert.IsFalse(behaviourContext.IsFlushVoiceWaveBuffersSupported()); - Assert.IsFalse(behaviourContext.IsSplitterBugFixed()); - Assert.IsFalse(behaviourContext.IsElapsedFrameCountSupported()); - Assert.IsFalse(behaviourContext.IsDecodingBehaviourFlagSupported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterEffectStateClearBugFixed()); - Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); - Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); - Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - 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()); - Assert.AreEqual(1, behaviourContext.GetPerformanceMetricsDataFormat()); - } - - [Test] - public void TestRevision2() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision2); - - Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed()); - Assert.IsTrue(behaviourContext.IsSplitterSupported()); - Assert.IsFalse(behaviourContext.IsLongSizePreDelaySupported()); - Assert.IsFalse(behaviourContext.IsAudioUsbDeviceOutputSupported()); - Assert.IsFalse(behaviourContext.IsFlushVoiceWaveBuffersSupported()); - Assert.IsFalse(behaviourContext.IsSplitterBugFixed()); - Assert.IsFalse(behaviourContext.IsElapsedFrameCountSupported()); - Assert.IsFalse(behaviourContext.IsDecodingBehaviourFlagSupported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterEffectStateClearBugFixed()); - Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); - Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); - Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - 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()); - Assert.AreEqual(1, behaviourContext.GetPerformanceMetricsDataFormat()); - } - - [Test] - public void TestRevision3() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision3); - - Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed()); - Assert.IsTrue(behaviourContext.IsSplitterSupported()); - Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported()); - Assert.IsFalse(behaviourContext.IsAudioUsbDeviceOutputSupported()); - Assert.IsFalse(behaviourContext.IsFlushVoiceWaveBuffersSupported()); - Assert.IsFalse(behaviourContext.IsSplitterBugFixed()); - Assert.IsFalse(behaviourContext.IsElapsedFrameCountSupported()); - Assert.IsFalse(behaviourContext.IsDecodingBehaviourFlagSupported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterEffectStateClearBugFixed()); - Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); - Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); - Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - 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()); - Assert.AreEqual(1, behaviourContext.GetPerformanceMetricsDataFormat()); - } - - [Test] - public void TestRevision4() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision4); - - Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed()); - Assert.IsTrue(behaviourContext.IsSplitterSupported()); - Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported()); - Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported()); - Assert.IsFalse(behaviourContext.IsFlushVoiceWaveBuffersSupported()); - Assert.IsFalse(behaviourContext.IsSplitterBugFixed()); - Assert.IsFalse(behaviourContext.IsElapsedFrameCountSupported()); - Assert.IsFalse(behaviourContext.IsDecodingBehaviourFlagSupported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterEffectStateClearBugFixed()); - Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); - Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); - Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - 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()); - Assert.AreEqual(1, behaviourContext.GetPerformanceMetricsDataFormat()); - } - - [Test] - public void TestRevision5() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision5); - - 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.IsFalse(behaviourContext.IsBiquadFilterEffectStateClearBugFixed()); - Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); - Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); - Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - 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()); - Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat()); - } - - [Test] - public void TestRevision6() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision6); - - 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.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()); - Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); - Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - 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()); - Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat()); - } - - [Test] - public void TestRevision7() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision7); - - 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.IsFalse(behaviourContext.IsWaveBufferVersion2Supported()); - Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - 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()); - Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat()); - } - - [Test] - public void TestRevision8() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision8); - - 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.IsFalse(behaviourContext.IsEffectInfoVersion2Supported()); - 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()); - Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat()); - } - - [Test] - public void TestRevision9() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision9); - - 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.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()); - Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat()); - } - - [Test] - public void TestRevision10() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision10); - - 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.IsFalse(behaviourContext.IsNewEffectChannelMappingSupported()); - Assert.IsFalse(behaviourContext.IsBiquadFilterParameterForSplitterEnabled()); - Assert.IsFalse(behaviourContext.IsSplitterPrevVolumeResetSupported()); - - Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit()); - Assert.AreEqual(4, behaviourContext.GetCommandProcessingTimeEstimatorVersion()); - Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat()); - } - - [Test] - public void TestRevision11() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision11); - - 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.IsFalse(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 TestRevision12() - { - BehaviourContext behaviourContext = new(); - - behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision12); - - 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.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()); - Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat()); - } - } -} diff --git a/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourInfoTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourInfoTests.cs new file mode 100644 index 000000000..ac85e44b4 --- /dev/null +++ b/src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourInfoTests.cs @@ -0,0 +1,413 @@ +using NUnit.Framework; +using Ryujinx.Audio.Renderer.Server; + +namespace Ryujinx.Tests.Audio.Renderer.Server +{ + public class BehaviourInfoTests + { + [Test] + public void TestCheckFeature() + { + int latestRevision = BehaviourInfo.BaseRevisionMagic + BehaviourInfo.LastRevision; + int previousRevision = BehaviourInfo.BaseRevisionMagic + (BehaviourInfo.LastRevision - 1); + int invalidRevision = BehaviourInfo.BaseRevisionMagic + (BehaviourInfo.LastRevision + 1); + + Assert.IsTrue(BehaviourInfo.CheckFeatureSupported(latestRevision, latestRevision)); + Assert.IsFalse(BehaviourInfo.CheckFeatureSupported(previousRevision, latestRevision)); + Assert.IsTrue(BehaviourInfo.CheckFeatureSupported(latestRevision, previousRevision)); + // In case we get an invalid revision, this is supposed to auto default to REV1 internally.. idk what the hell Nintendo was thinking here.. + Assert.IsTrue(BehaviourInfo.CheckFeatureSupported(invalidRevision, latestRevision)); + } + + [Test] + public void TestsMemoryPoolForceMappingEnabled() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision1); + + Assert.IsFalse(behaviourInfo.IsMemoryPoolForceMappingEnabled()); + + behaviourInfo.UpdateFlags(0x1); + + Assert.IsTrue(behaviourInfo.IsMemoryPoolForceMappingEnabled()); + } + + [Test] + public void TestRevision1() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision1); + + Assert.IsFalse(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsFalse(behaviourInfo.IsSplitterSupported()); + Assert.IsFalse(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsFalse(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsFalse(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsFalse(behaviourInfo.IsSplitterBugFixed()); + Assert.IsFalse(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsFalse(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsFalse(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsFalse(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsFalse(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsFalse(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.70f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(1, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(1, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision2() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision2); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsFalse(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsFalse(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsFalse(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsFalse(behaviourInfo.IsSplitterBugFixed()); + Assert.IsFalse(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsFalse(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsFalse(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsFalse(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsFalse(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsFalse(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.70f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(1, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(1, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision3() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision3); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsTrue(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsFalse(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsFalse(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsFalse(behaviourInfo.IsSplitterBugFixed()); + Assert.IsFalse(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsFalse(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsFalse(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsFalse(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsFalse(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsFalse(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.70f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(1, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(1, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision4() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision4); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsTrue(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsFalse(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsFalse(behaviourInfo.IsSplitterBugFixed()); + Assert.IsFalse(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsFalse(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsFalse(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsFalse(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsFalse(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsFalse(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.75f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(1, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(1, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision5() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision5); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsTrue(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourInfo.IsSplitterBugFixed()); + Assert.IsTrue(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsFalse(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsFalse(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsFalse(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsFalse(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(2, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision6() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision6); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsTrue(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourInfo.IsSplitterBugFixed()); + Assert.IsTrue(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsTrue(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsFalse(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsFalse(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsFalse(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsFalse(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(2, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision7() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision7); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsTrue(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourInfo.IsSplitterBugFixed()); + Assert.IsTrue(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsTrue(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsTrue(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsFalse(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsFalse(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsFalse(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(2, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision8() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision8); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsTrue(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourInfo.IsSplitterBugFixed()); + Assert.IsTrue(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsTrue(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsTrue(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsTrue(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsFalse(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsFalse(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(3, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision9() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision9); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsTrue(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourInfo.IsSplitterBugFixed()); + Assert.IsTrue(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsTrue(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsTrue(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsTrue(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsTrue(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsFalse(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(3, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision10() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision10); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsTrue(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourInfo.IsSplitterBugFixed()); + Assert.IsTrue(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsTrue(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsTrue(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsTrue(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsTrue(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsTrue(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsFalse(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(4, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision11() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision11); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsTrue(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourInfo.IsSplitterBugFixed()); + Assert.IsTrue(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsTrue(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsTrue(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsTrue(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsTrue(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsTrue(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsTrue(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsFalse(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(5, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision12() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision12); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsTrue(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourInfo.IsSplitterBugFixed()); + Assert.IsTrue(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsTrue(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsTrue(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsTrue(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsTrue(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsTrue(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsTrue(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsTrue(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsFalse(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(5, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + + [Test] + public void TestRevision13() + { + BehaviourInfo behaviourInfo = new(); + + behaviourInfo.SetUserRevision(BehaviourInfo.BaseRevisionMagic + BehaviourInfo.Revision13); + + Assert.IsTrue(behaviourInfo.IsAdpcmLoopContextBugFixed()); + Assert.IsTrue(behaviourInfo.IsSplitterSupported()); + Assert.IsTrue(behaviourInfo.IsLongSizePreDelaySupported()); + Assert.IsTrue(behaviourInfo.IsAudioUsbDeviceOutputSupported()); + Assert.IsTrue(behaviourInfo.IsFlushVoiceWaveBuffersSupported()); + Assert.IsTrue(behaviourInfo.IsSplitterBugFixed()); + Assert.IsTrue(behaviourInfo.IsElapsedFrameCountSupported()); + Assert.IsTrue(behaviourInfo.IsDecodingBehaviourFlagSupported()); + Assert.IsTrue(behaviourInfo.IsBiquadFilterEffectStateClearBugFixed()); + Assert.IsTrue(behaviourInfo.IsMixInParameterDirtyOnlyUpdateSupported()); + Assert.IsTrue(behaviourInfo.IsWaveBufferVersion2Supported()); + Assert.IsTrue(behaviourInfo.IsEffectInfoVersion2Supported()); + Assert.IsTrue(behaviourInfo.UseMultiTapBiquadFilterProcessing()); + Assert.IsTrue(behaviourInfo.IsNewEffectChannelMappingSupported()); + Assert.IsTrue(behaviourInfo.IsBiquadFilterParameterForSplitterEnabled()); + Assert.IsTrue(behaviourInfo.IsSplitterPrevVolumeResetSupported()); + + Assert.AreEqual(0.80f, behaviourInfo.GetAudioRendererProcessingTimeLimit()); + Assert.AreEqual(5, behaviourInfo.GetCommandProcessingTimeEstimatorVersion()); + Assert.AreEqual(2, behaviourInfo.GetPerformanceMetricsDataFormat()); + } + } +} diff --git a/src/Ryujinx.Tests/Audio/Renderer/Server/MemoryPoolStateTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Server/MemoryPoolInfoTests.cs similarity index 80% rename from src/Ryujinx.Tests/Audio/Renderer/Server/MemoryPoolStateTests.cs rename to src/Ryujinx.Tests/Audio/Renderer/Server/MemoryPoolInfoTests.cs index c6a2e473e..612df4dc1 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/Server/MemoryPoolStateTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/Server/MemoryPoolInfoTests.cs @@ -4,18 +4,18 @@ using System.Runtime.CompilerServices; namespace Ryujinx.Tests.Audio.Renderer.Server { - class MemoryPoolStateTests + class MemoryPoolInfoTests { [Test] public void EnsureTypeSize() { - Assert.AreEqual(Unsafe.SizeOf(), 0x20); + Assert.AreEqual(Unsafe.SizeOf(), 0x20); } [Test] public void TestContains() { - MemoryPoolState memoryPool = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); + MemoryPoolInfo memoryPool = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Cpu); memoryPool.SetCpuAddress(0x1000000, 0x1000); @@ -32,7 +32,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server [Test] public void TestTranslate() { - MemoryPoolState memoryPool = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); + MemoryPoolInfo memoryPool = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Cpu); memoryPool.SetCpuAddress(0x1000000, 0x1000); @@ -48,7 +48,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server [Test] public void TestIsMapped() { - MemoryPoolState memoryPool = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); + MemoryPoolInfo memoryPool = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Cpu); memoryPool.SetCpuAddress(0x1000000, 0x1000); diff --git a/src/Ryujinx.Tests/Audio/Renderer/Server/MixStateTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Server/MixInfoTests.cs similarity index 73% rename from src/Ryujinx.Tests/Audio/Renderer/Server/MixStateTests.cs rename to src/Ryujinx.Tests/Audio/Renderer/Server/MixInfoTests.cs index 6262913b4..dbdc5c343 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/Server/MixStateTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/Server/MixInfoTests.cs @@ -4,12 +4,12 @@ using System.Runtime.CompilerServices; namespace Ryujinx.Tests.Audio.Renderer.Server { - class MixStateTests + class MixInfoTests { [Test] public void EnsureTypeSize() { - Assert.AreEqual(0x940, Unsafe.SizeOf()); + Assert.AreEqual(0x940, Unsafe.SizeOf()); } } } diff --git a/src/Ryujinx.Tests/Audio/Renderer/Server/PoolMapperTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Server/PoolMapperTests.cs index 941afae6f..5a1256937 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/Server/PoolMapperTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/Server/PoolMapperTests.cs @@ -16,8 +16,8 @@ namespace Ryujinx.Tests.Audio.Renderer.Server public void TestInitializeSystemPool() { PoolMapper poolMapper = new(DummyProcessHandle, true); - MemoryPoolState memoryPoolDsp = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp); - MemoryPoolState memoryPoolCpu = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); + MemoryPoolInfo memoryPoolDsp = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Dsp); + MemoryPoolInfo memoryPoolCpu = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Cpu); const CpuAddress CpuAddress = 0x20000; const DspAddress DspAddress = CpuAddress; // TODO: DSP LLE @@ -35,8 +35,8 @@ namespace Ryujinx.Tests.Audio.Renderer.Server public void TestGetProcessHandle() { PoolMapper poolMapper = new(DummyProcessHandle, true); - MemoryPoolState memoryPoolDsp = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp); - MemoryPoolState memoryPoolCpu = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); + MemoryPoolInfo memoryPoolDsp = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Dsp); + MemoryPoolInfo memoryPoolCpu = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Cpu); Assert.AreEqual(0xFFFF8001, poolMapper.GetProcessHandle(ref memoryPoolCpu)); Assert.AreEqual(DummyProcessHandle, poolMapper.GetProcessHandle(ref memoryPoolDsp)); @@ -46,8 +46,8 @@ namespace Ryujinx.Tests.Audio.Renderer.Server public void TestMappings() { PoolMapper poolMapper = new(DummyProcessHandle, true); - MemoryPoolState memoryPoolDsp = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp); - MemoryPoolState memoryPoolCpu = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); + MemoryPoolInfo memoryPoolDsp = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Dsp); + MemoryPoolInfo memoryPoolCpu = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Cpu); const CpuAddress CpuAddress = 0x20000; const DspAddress DspAddress = CpuAddress; // TODO: DSP LLE @@ -77,11 +77,11 @@ namespace Ryujinx.Tests.Audio.Renderer.Server const int MemoryPoolStateArraySize = 0x10; const CpuAddress CpuAddressRegionEnding = CpuAddress * MemoryPoolStateArraySize; - MemoryPoolState[] memoryPoolStateArray = new MemoryPoolState[MemoryPoolStateArraySize]; + MemoryPoolInfo[] memoryPoolStateArray = new MemoryPoolInfo[MemoryPoolStateArraySize]; for (int i = 0; i < memoryPoolStateArray.Length; i++) { - memoryPoolStateArray[i] = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); + memoryPoolStateArray[i] = MemoryPoolInfo.Create(MemoryPoolInfo.LocationType.Cpu); memoryPoolStateArray[i].SetCpuAddress(CpuAddress + (ulong)i * CpuSize, CpuSize); } diff --git a/src/Ryujinx.Tests/Audio/Renderer/Server/SplitterDestinationTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Server/SplitterDestinationTests.cs index 80b801336..e85111c9f 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/Server/SplitterDestinationTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/Server/SplitterDestinationTests.cs @@ -10,7 +10,7 @@ namespace Ryujinx.Tests.Audio.Renderer.Server public void EnsureTypeSize() { Assert.AreEqual(0xE0, Unsafe.SizeOf()); - Assert.AreEqual(0x110, Unsafe.SizeOf()); + Assert.AreEqual(0x128, Unsafe.SizeOf()); } } } diff --git a/src/Ryujinx.Tests/Audio/Renderer/Server/VoiceStateTests.cs b/src/Ryujinx.Tests/Audio/Renderer/Server/VoiceInfoTests.cs similarity index 71% rename from src/Ryujinx.Tests/Audio/Renderer/Server/VoiceStateTests.cs rename to src/Ryujinx.Tests/Audio/Renderer/Server/VoiceInfoTests.cs index dbd6eff8f..1382d693c 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/Server/VoiceStateTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/Server/VoiceInfoTests.cs @@ -4,12 +4,12 @@ using System.Runtime.CompilerServices; namespace Ryujinx.Tests.Audio.Renderer.Server { - class VoiceStateTests + class VoiceInfoTests { [Test] public void EnsureTypeSize() { - Assert.LessOrEqual(Unsafe.SizeOf(), 0x220); + Assert.LessOrEqual(Unsafe.SizeOf(), 0x238); } } } diff --git a/src/Ryujinx.Tests/Audio/Renderer/VoiceInParameterTests.cs b/src/Ryujinx.Tests/Audio/Renderer/VoiceInParameterTests.cs index 239da195a..e91675563 100644 --- a/src/Ryujinx.Tests/Audio/Renderer/VoiceInParameterTests.cs +++ b/src/Ryujinx.Tests/Audio/Renderer/VoiceInParameterTests.cs @@ -9,7 +9,8 @@ namespace Ryujinx.Tests.Audio.Renderer [Test] public void EnsureTypeSize() { - Assert.AreEqual(0x170, Unsafe.SizeOf()); + Assert.AreEqual(0x170, Unsafe.SizeOf()); + Assert.AreEqual(0x188, Unsafe.SizeOf()); } } } diff --git a/src/Ryujinx.Tests/Memory/PartialUnmaps.cs b/src/Ryujinx.Tests/Memory/PartialUnmaps.cs index 92b994279..1a01a36bc 100644 --- a/src/Ryujinx.Tests/Memory/PartialUnmaps.cs +++ b/src/Ryujinx.Tests/Memory/PartialUnmaps.cs @@ -226,7 +226,7 @@ namespace Ryujinx.Tests.Memory ref PartialUnmapState state = ref PartialUnmapState.GetRef(); - // Create some state to be used for managing the native writing loop. + // Create some info to be used for managing the native writing loop. int stateSize = Unsafe.SizeOf(); IntPtr statePtr = Marshal.AllocHGlobal(stateSize); Unsafe.InitBlockUnaligned((void*)statePtr, 0, (uint)stateSize);