aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Audio/Renderer/Parameter
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.Audio/Renderer/Parameter
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff)
Move solution and projects to src
Diffstat (limited to 'src/Ryujinx.Audio/Renderer/Parameter')
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/AudioRendererConfiguration.cs99
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/BehaviourErrorInfoOutStatus.cs30
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter.cs34
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Effect/AuxiliaryBufferParameter.cs84
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter.cs44
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Effect/BufferMixerParameter.cs32
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs115
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Effect/DelayParameter.cs101
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Effect/LimiterParameter.cs138
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Effect/LimiterStatistics.cs31
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Effect/Reverb3dParameter.cs127
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Effect/ReverbParameter.cs119
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion1.cs97
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion2.cs97
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/EffectOutStatusVersion1.cs23
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/EffectOutStatusVersion2.cs28
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/EffectResultState.cs26
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/EffectState.cs18
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/IEffectInParameter.cs53
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/IEffectOutStatus.cs13
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/MemoryPoolInParameter.cs33
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/MemoryPoolOutStatus.cs22
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/MixInParameterDirtyOnlyUpdate.cs27
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/MixParameter.cs95
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Performance/PerformanceInParameter.cs21
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Performance/PerformanceOutStatus.cs21
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/RendererInfoOutStatus.cs21
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Sink/CircularBufferParameter.cs62
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/Sink/DeviceParameter.cs58
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/SinkInParameter.cs53
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/SinkOutStatus.cs26
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameter.cs67
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/SplitterInParameter.cs46
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/SplitterInParameterHeader.cs45
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/VoiceChannelResourceInParameter.cs28
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter.cs344
-rw-r--r--src/Ryujinx.Audio/Renderer/Parameter/VoiceOutStatus.cs35
37 files changed, 2313 insertions, 0 deletions
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/AudioRendererConfiguration.cs b/src/Ryujinx.Audio/Renderer/Parameter/AudioRendererConfiguration.cs
new file mode 100644
index 00000000..359cd4c0
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/AudioRendererConfiguration.cs
@@ -0,0 +1,99 @@
+using Ryujinx.Audio.Renderer.Server.Types;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Audio Renderer user configuration.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct AudioRendererConfiguration
+ {
+ /// <summary>
+ /// The target sample rate of the user.
+ /// </summary>
+ /// <remarks>Only 32000Hz and 48000Hz are considered valid, other sample rates will cause undefined behaviour.</remarks>
+ public uint SampleRate;
+
+ /// <summary>
+ /// The target sample count per <see cref="Dsp.AudioProcessor"/> updates.
+ /// </summary>
+ public uint SampleCount;
+
+ /// <summary>
+ /// The maximum mix buffer count.
+ /// </summary>
+ public uint MixBufferCount;
+
+ /// <summary>
+ /// The maximum amount of sub mixes that could be used by the user.
+ /// </summary>
+ public uint SubMixBufferCount;
+
+ /// <summary>
+ /// The maximum amount of voices that could be used by the user.
+ /// </summary>
+ public uint VoiceCount;
+
+ /// <summary>
+ /// The maximum amount of sinks that could be used by the user.
+ /// </summary>
+ public uint SinkCount;
+
+ /// <summary>
+ /// The maximum amount of effects that could be used by the user.
+ /// </summary>
+ public uint EffectCount;
+
+ /// <summary>
+ /// The maximum amount of performance metric frames that could be used by the user.
+ /// </summary>
+ public uint PerformanceMetricFramesCount;
+
+ /// <summary>
+ /// Set to true if the user allows the <see cref="Server.AudioRenderSystem"/> to drop voices.
+ /// </summary>
+ /// <seealso cref="Server.AudioRenderSystem.ComputeVoiceDrop(Server.CommandBuffer, long, long)"/>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool VoiceDropEnabled;
+
+ /// <summary>
+ /// Reserved/unused
+ /// </summary>
+ private byte _reserved;
+
+ /// <summary>
+ /// The target rendering device.
+ /// </summary>
+ /// <remarks>Must be <see cref="AudioRendererRenderingDevice.Dsp"/></remarks>
+ public AudioRendererRenderingDevice RenderingDevice;
+
+ /// <summary>
+ /// The target execution mode.
+ /// </summary>
+ /// <remarks>Must be <see cref="AudioRendererExecutionMode.Auto"/></remarks>
+ public AudioRendererExecutionMode ExecutionMode;
+
+ /// <summary>
+ /// The maximum amount of splitters that could be used by the user.
+ /// </summary>
+ public uint SplitterCount;
+
+ /// <summary>
+ /// The maximum amount of splitters destinations that could be used by the user.
+ /// </summary>
+ public uint SplitterDestinationCount;
+
+ /// <summary>
+ /// The size of the external context.
+ /// </summary>
+ /// <remarks>This is a leftover of the old "codec" interface system that was present between 1.0.0 and 3.0.0. This was entirely removed from the server side with REV8.</remarks>
+ public uint ExternalContextSize;
+
+ /// <summary>
+ /// The user audio revision
+ /// </summary>
+ /// <seealso cref="Server.BehaviourContext"/>
+ public int Revision;
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/BehaviourErrorInfoOutStatus.cs b/src/Ryujinx.Audio/Renderer/Parameter/BehaviourErrorInfoOutStatus.cs
new file mode 100644
index 00000000..aba7dcd6
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/BehaviourErrorInfoOutStatus.cs
@@ -0,0 +1,30 @@
+using Ryujinx.Common.Memory;
+using System;
+using System.Runtime.InteropServices;
+using static Ryujinx.Audio.Renderer.Common.BehaviourParameter;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Output information for behaviour.
+ /// </summary>
+ /// <remarks>This is used to report errors to the user during <see cref="Server.AudioRenderSystem.Update(Memory{byte}, Memory{byte}, ReadOnlyMemory{byte})"/> processing.</remarks>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct BehaviourErrorInfoOutStatus
+ {
+ /// <summary>
+ /// The reported errors.
+ /// </summary>
+ public Array10<ErrorInfo> ErrorInfos;
+
+ /// <summary>
+ /// The amount of error that got reported.
+ /// </summary>
+ public uint ErrorInfosCount;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private unsafe fixed uint _reserved[3];
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter.cs
new file mode 100644
index 00000000..ef86015f
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/BiquadFilterParameter.cs
@@ -0,0 +1,34 @@
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Biquad filter parameters.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 1)]
+ public struct BiquadFilterParameter
+ {
+ /// <summary>
+ /// Set to true if the biquad filter is active.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool Enable;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private byte _reserved;
+
+ /// <summary>
+ /// Biquad filter numerator (b0, b1, b2).
+ /// </summary>
+ public Array3<short> Numerator;
+
+ /// <summary>
+ /// Biquad filter denominator (a1, a2).
+ /// </summary>
+ /// <remarks>a0 = 1</remarks>
+ public Array2<short> Denominator;
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/AuxiliaryBufferParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/AuxiliaryBufferParameter.cs
new file mode 100644
index 00000000..36f28677
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/AuxiliaryBufferParameter.cs
@@ -0,0 +1,84 @@
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Effect
+{
+ /// <summary>
+ /// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.AuxiliaryBuffer"/> and <see cref="Common.EffectType.CaptureBuffer"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct AuxiliaryBufferParameter
+ {
+ /// <summary>
+ /// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/> to write data to <see cref="SendBufferInfoAddress"/>.
+ /// </summary>
+ public Array24<byte> Input;
+
+ /// <summary>
+ /// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/> to read data from <see cref="ReturnBufferInfoAddress"/>.
+ /// </summary>
+ public Array24<byte> Output;
+
+ /// <summary>
+ /// The total channel count used.
+ /// </summary>
+ public uint ChannelCount;
+
+ /// <summary>
+ /// The target sample rate.
+ /// </summary>
+ public uint SampleRate;
+
+ /// <summary>
+ /// The buffer storage total size.
+ /// </summary>
+ public uint BufferStorageSize;
+
+ /// <summary>
+ /// The maximum number of channels supported.
+ /// </summary>
+ /// <remarks>This is unused.</remarks>
+ public uint ChannelCountMax;
+
+ /// <summary>
+ /// The address of the start of the region containing two <see cref="Dsp.State.AuxiliaryBufferHeader"/> followed by the data that will be written by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public ulong SendBufferInfoAddress;
+
+ /// <summary>
+ /// The address of the start of the region containling data that will be written by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ /// <remarks>This is unused.</remarks>
+ public ulong SendBufferStorageAddress;
+
+ /// <summary>
+ /// The address of the start of the region containing two <see cref="Dsp.State.AuxiliaryBufferHeader"/> followed by the data that will be read by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ /// <remarks>Unused with <see cref="Common.EffectType.CaptureBuffer"/>.</remarks>
+ public ulong ReturnBufferInfoAddress;
+
+ /// <summary>
+ /// The address of the start of the region containling data that will be read by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ /// <remarks>This is unused.</remarks>
+ public ulong ReturnBufferStorageAddress;
+
+ /// <summary>
+ /// Size of a sample of the mix buffer.
+ /// </summary>
+ /// <remarks>This is unused.</remarks>
+ public uint MixBufferSampleSize;
+
+ /// <summary>
+ /// The total count of sample that can be stored.
+ /// </summary>
+ /// <remarks>This is unused.</remarks>
+ public uint TotalSampleCount;
+
+ /// <summary>
+ /// The count of sample of the mix buffer.
+ /// </summary>
+ /// <remarks>This is unused.</remarks>
+ public uint MixBufferSampleCount;
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter.cs
new file mode 100644
index 00000000..73e0e9bb
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/BiquadFilterEffectParameter.cs
@@ -0,0 +1,44 @@
+using Ryujinx.Audio.Renderer.Server.Effect;
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Effect
+{
+ /// <summary>
+ /// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.BiquadFilter"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct BiquadFilterEffectParameter
+ {
+ /// <summary>
+ /// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Input;
+
+ /// <summary>
+ /// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Output;
+
+ /// <summary>
+ /// Biquad filter numerator (b0, b1, b2).
+ /// </summary>
+ public Array3<short> Numerator;
+
+ /// <summary>
+ /// Biquad filter denominator (a1, a2).
+ /// </summary>
+ /// <remarks>a0 = 1</remarks>
+ public Array2<short> Denominator;
+
+ /// <summary>
+ /// The total channel count used.
+ /// </summary>
+ public byte ChannelCount;
+
+ /// <summary>
+ /// The current usage status of the effect on the client side.
+ /// </summary>
+ public UsageState Status;
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/BufferMixerParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/BufferMixerParameter.cs
new file mode 100644
index 00000000..b03559eb
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/BufferMixerParameter.cs
@@ -0,0 +1,32 @@
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Effect
+{
+ /// <summary>
+ /// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.BufferMix"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct BufferMixParameter
+ {
+ /// <summary>
+ /// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array24<byte> Input;
+
+ /// <summary>
+ /// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array24<byte> Output;
+
+ /// <summary>
+ /// The output volumes of the mixes.
+ /// </summary>
+ public Array24<float> Volumes;
+
+ /// <summary>
+ /// The total count of mixes used.
+ /// </summary>
+ public uint MixesCount;
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs
new file mode 100644
index 00000000..0be37608
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs
@@ -0,0 +1,115 @@
+using Ryujinx.Audio.Renderer.Server.Effect;
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Effect
+{
+ /// <summary>
+ /// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.Compressor"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct CompressorParameter
+ {
+ /// <summary>
+ /// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Input;
+
+ /// <summary>
+ /// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Output;
+
+ /// <summary>
+ /// The maximum number of channels supported.
+ /// </summary>
+ public ushort ChannelCountMax;
+
+ /// <summary>
+ /// The total channel count used.
+ /// </summary>
+ public ushort ChannelCount;
+
+ /// <summary>
+ /// The target sample rate.
+ /// </summary>
+ /// <remarks>This is in kHz.</remarks>
+ public int SampleRate;
+
+ /// <summary>
+ /// The threshold.
+ /// </summary>
+ public float Threshold;
+
+ /// <summary>
+ /// The compressor ratio.
+ /// </summary>
+ public float Ratio;
+
+ /// <summary>
+ /// The attack time.
+ /// <remarks>This is in microseconds.</remarks>
+ /// </summary>
+ public int AttackTime;
+
+ /// <summary>
+ /// The release time.
+ /// <remarks>This is in microseconds.</remarks>
+ /// </summary>
+ public int ReleaseTime;
+
+ /// <summary>
+ /// The input gain.
+ /// </summary>
+ public float InputGain;
+
+ /// <summary>
+ /// The attack coefficient.
+ /// </summary>
+ public float AttackCoefficient;
+
+ /// <summary>
+ /// The release coefficient.
+ /// </summary>
+ public float ReleaseCoefficient;
+
+ /// <summary>
+ /// The output gain.
+ /// </summary>
+ public float OutputGain;
+
+ /// <summary>
+ /// The current usage status of the effect on the client side.
+ /// </summary>
+ public UsageState Status;
+
+ /// <summary>
+ /// Indicate if the makeup gain should be used.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool MakeupGainEnabled;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private Array2<byte> _reserved;
+
+ /// <summary>
+ /// Check if the <see cref="ChannelCount"/> is valid.
+ /// </summary>
+ /// <returns>Returns true if the <see cref="ChannelCount"/> is valid.</returns>
+ public bool IsChannelCountValid()
+ {
+ return EffectInParameterVersion1.IsChannelCountValid(ChannelCount);
+ }
+
+ /// <summary>
+ /// Check if the <see cref="ChannelCountMax"/> is valid.
+ /// </summary>
+ /// <returns>Returns true if the <see cref="ChannelCountMax"/> is valid.</returns>
+ public bool IsChannelCountMaxValid()
+ {
+ return EffectInParameterVersion1.IsChannelCountValid(ChannelCountMax);
+ }
+ }
+}
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/DelayParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/DelayParameter.cs
new file mode 100644
index 00000000..72332c17
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/DelayParameter.cs
@@ -0,0 +1,101 @@
+using Ryujinx.Audio.Renderer.Server.Effect;
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Effect
+{
+ /// <summary>
+ /// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.Delay"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct DelayParameter
+ {
+ /// <summary>
+ /// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Input;
+
+ /// <summary>
+ /// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Output;
+
+ /// <summary>
+ /// The maximum number of channels supported.
+ /// </summary>
+ public ushort ChannelCountMax;
+
+ /// <summary>
+ /// The total channel count used.
+ /// </summary>
+ public ushort ChannelCount;
+
+ /// <summary>
+ /// The maximum delay time in milliseconds.
+ /// </summary>
+ public uint DelayTimeMax;
+
+ /// <summary>
+ /// The delay time in milliseconds.
+ /// </summary>
+ public uint DelayTime;
+
+ /// <summary>
+ /// The target sample rate. (Q15)
+ /// </summary>
+ public uint SampleRate;
+
+ /// <summary>
+ /// The input gain. (Q15)
+ /// </summary>
+ public uint InGain;
+
+ /// <summary>
+ /// The feedback gain. (Q15)
+ /// </summary>
+ public uint FeedbackGain;
+
+ /// <summary>
+ /// The output gain. (Q15)
+ /// </summary>
+ public uint OutGain;
+
+ /// <summary>
+ /// The dry gain. (Q15)
+ /// </summary>
+ public uint DryGain;
+
+ /// <summary>
+ /// The channel spread of the <see cref="FeedbackGain"/>. (Q15)
+ /// </summary>
+ public uint ChannelSpread;
+
+ /// <summary>
+ /// The low pass amount. (Q15)
+ /// </summary>
+ public uint LowPassAmount;
+
+ /// <summary>
+ /// The current usage status of the effect on the client side.
+ /// </summary>
+ public UsageState Status;
+
+ /// <summary>
+ /// Check if the <see cref="ChannelCount"/> is valid.
+ /// </summary>
+ /// <returns>Returns true if the <see cref="ChannelCount"/> is valid.</returns>
+ public bool IsChannelCountValid()
+ {
+ return EffectInParameterVersion1.IsChannelCountValid(ChannelCount);
+ }
+
+ /// <summary>
+ /// Check if the <see cref="ChannelCountMax"/> is valid.
+ /// </summary>
+ /// <returns>Returns true if the <see cref="ChannelCountMax"/> is valid.</returns>
+ public bool IsChannelCountMaxValid()
+ {
+ return EffectInParameterVersion1.IsChannelCountValid(ChannelCountMax);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/LimiterParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/LimiterParameter.cs
new file mode 100644
index 00000000..0bce94a2
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/LimiterParameter.cs
@@ -0,0 +1,138 @@
+using Ryujinx.Audio.Renderer.Server.Effect;
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Effect
+{
+ /// <summary>
+ /// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.Limiter"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct LimiterParameter
+ {
+ /// <summary>
+ /// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Input;
+
+ /// <summary>
+ /// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Output;
+
+ /// <summary>
+ /// The maximum number of channels supported.
+ /// </summary>
+ public ushort ChannelCountMax;
+
+ /// <summary>
+ /// The total channel count used.
+ /// </summary>
+ public ushort ChannelCount;
+
+ /// <summary>
+ /// The target sample rate.
+ /// </summary>
+ /// <remarks>This is in kHz.</remarks>
+ public int SampleRate;
+
+ /// <summary>
+ /// The look ahead max time.
+ /// <remarks>This is in microseconds.</remarks>
+ /// </summary>
+ public int LookAheadTimeMax;
+
+ /// <summary>
+ /// The attack time.
+ /// <remarks>This is in microseconds.</remarks>
+ /// </summary>
+ public int AttackTime;
+
+ /// <summary>
+ /// The release time.
+ /// <remarks>This is in microseconds.</remarks>
+ /// </summary>
+ public int ReleaseTime;
+
+ /// <summary>
+ /// The look ahead time.
+ /// <remarks>This is in microseconds.</remarks>
+ /// </summary>
+ public int LookAheadTime;
+
+ /// <summary>
+ /// The attack coefficient.
+ /// </summary>
+ public float AttackCoefficient;
+
+ /// <summary>
+ /// The release coefficient.
+ /// </summary>
+ public float ReleaseCoefficient;
+
+ /// <summary>
+ /// The threshold.
+ /// </summary>
+ public float Threshold;
+
+ /// <summary>
+ /// The input gain.
+ /// </summary>
+ public float InputGain;
+
+ /// <summary>
+ /// The output gain.
+ /// </summary>
+ public float OutputGain;
+
+ /// <summary>
+ /// The minimum samples stored in the delay buffer.
+ /// </summary>
+ public int DelayBufferSampleCountMin;
+
+ /// <summary>
+ /// The maximum samples stored in the delay buffer.
+ /// </summary>
+ public int DelayBufferSampleCountMax;
+
+ /// <summary>
+ /// The current usage status of the effect on the client side.
+ /// </summary>
+ public UsageState Status;
+
+ /// <summary>
+ /// Indicate if the limiter effect should output statistics.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool StatisticsEnabled;
+
+ /// <summary>
+ /// Indicate to the DSP that the user did a statistics reset.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool StatisticsReset;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private byte _reserved;
+
+ /// <summary>
+ /// Check if the <see cref="ChannelCount"/> is valid.
+ /// </summary>
+ /// <returns>Returns true if the <see cref="ChannelCount"/> is valid.</returns>
+ public bool IsChannelCountValid()
+ {
+ return EffectInParameterVersion1.IsChannelCountValid(ChannelCount);
+ }
+
+ /// <summary>
+ /// Check if the <see cref="ChannelCountMax"/> is valid.
+ /// </summary>
+ /// <returns>Returns true if the <see cref="ChannelCountMax"/> is valid.</returns>
+ public bool IsChannelCountMaxValid()
+ {
+ return EffectInParameterVersion1.IsChannelCountValid(ChannelCountMax);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/LimiterStatistics.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/LimiterStatistics.cs
new file mode 100644
index 00000000..f353f18d
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/LimiterStatistics.cs
@@ -0,0 +1,31 @@
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Effect
+{
+ /// <summary>
+ /// Effect result state for <seealso cref="Common.EffectType.Limiter"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct LimiterStatistics
+ {
+ /// <summary>
+ /// The max input sample value recorded by the limiter.
+ /// </summary>
+ public Array6<float> InputMax;
+
+ /// <summary>
+ /// Compression gain min value.
+ /// </summary>
+ public Array6<float> CompressionGainMin;
+
+ /// <summary>
+ /// Reset the statistics.
+ /// </summary>
+ public void Reset()
+ {
+ InputMax.AsSpan().Fill(0.0f);
+ CompressionGainMin.AsSpan().Fill(1.0f);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/Reverb3dParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/Reverb3dParameter.cs
new file mode 100644
index 00000000..c78ce595
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/Reverb3dParameter.cs
@@ -0,0 +1,127 @@
+using Ryujinx.Audio.Renderer.Server.Effect;
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Effect
+{
+ /// <summary>
+ /// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.Reverb3d"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct Reverb3dParameter
+ {
+ /// <summary>
+ /// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Input;
+
+ /// <summary>
+ /// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Output;
+
+ /// <summary>
+ /// The maximum number of channels supported.
+ /// </summary>
+ public ushort ChannelCountMax;
+
+ /// <summary>
+ /// The total channel count used.
+ /// </summary>
+ public ushort ChannelCount;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private uint _reserved;
+
+ /// <summary>
+ /// The target sample rate.
+ /// </summary>
+ /// <remarks>This is in kHz.</remarks>
+ public uint SampleRate;
+
+ /// <summary>
+ /// Gain of the room high-frequency effect.
+ /// </summary>
+ public float RoomHf;
+
+ /// <summary>
+ /// Reference high frequency.
+ /// </summary>
+ public float HfReference;
+
+ /// <summary>
+ /// Reverberation decay time at low frequencies.
+ /// </summary>
+ public float DecayTime;
+
+ /// <summary>
+ /// Ratio of the decay time at high frequencies to the decay time at low frequencies.
+ /// </summary>
+ public float HfDecayRatio;
+
+ /// <summary>
+ /// Gain of the room effect.
+ /// </summary>
+ public float RoomGain;
+
+ /// <summary>
+ /// Gain of the early reflections relative to <see cref="RoomGain"/>.
+ /// </summary>
+ public float ReflectionsGain;
+
+ /// <summary>
+ /// Gain of the late reverberation relative to <see cref="RoomGain"/>.
+ /// </summary>
+ public float ReverbGain;
+
+ /// <summary>
+ /// Echo density in the late reverberation decay.
+ /// </summary>
+ public float Diffusion;
+
+ /// <summary>
+ /// Modal density in the late reverberation decay.
+ /// </summary>
+ public float ReflectionDelay;
+
+ /// <summary>
+ /// Time limit between the early reflections and the late reverberation relative to the time of the first reflection.
+ /// </summary>
+ public float ReverbDelayTime;
+
+ /// <summary>
+ /// Modal density in the late reverberation decay.
+ /// </summary>
+ public float Density;
+
+ /// <summary>
+ /// The dry gain.
+ /// </summary>
+ public float DryGain;
+
+ /// <summary>
+ /// The current usage status of the effect on the client side.
+ /// </summary>
+ public UsageState ParameterStatus;
+
+ /// <summary>
+ /// Check if the <see cref="ChannelCount"/> is valid.
+ /// </summary>
+ /// <returns>Returns true if the <see cref="ChannelCount"/> is valid.</returns>
+ public bool IsChannelCountValid()
+ {
+ return EffectInParameterVersion1.IsChannelCountValid(ChannelCount);
+ }
+
+ /// <summary>
+ /// Check if the <see cref="ChannelCountMax"/> is valid.
+ /// </summary>
+ /// <returns>Returns true if the <see cref="ChannelCountMax"/> is valid.</returns>
+ public bool IsChannelCountMaxValid()
+ {
+ return EffectInParameterVersion1.IsChannelCountValid(ChannelCountMax);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Effect/ReverbParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Effect/ReverbParameter.cs
new file mode 100644
index 00000000..baf049fb
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Effect/ReverbParameter.cs
@@ -0,0 +1,119 @@
+using Ryujinx.Audio.Renderer.Common;
+using Ryujinx.Audio.Renderer.Server.Effect;
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Effect
+{
+ /// <summary>
+ /// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.Reverb"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ReverbParameter
+ {
+ /// <summary>
+ /// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Input;
+
+ /// <summary>
+ /// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public Array6<byte> Output;
+
+ /// <summary>
+ /// The maximum number of channels supported.
+ /// </summary>
+ public ushort ChannelCountMax;
+
+ /// <summary>
+ /// The total channel count used.
+ /// </summary>
+ public ushort ChannelCount;
+
+ /// <summary>
+ /// The target sample rate. (Q15)
+ /// </summary>
+ /// <remarks>This is in kHz.</remarks>
+ public int SampleRate;
+
+ /// <summary>
+ /// The early mode to use.
+ /// </summary>
+ public ReverbEarlyMode EarlyMode;
+
+ /// <summary>
+ /// The gain to apply to the result of the early reflection. (Q15)
+ /// </summary>
+ public int EarlyGain;
+
+ /// <summary>
+ /// The pre-delay time in milliseconds. (Q15)
+ /// </summary>
+ public int PreDelayTime;
+
+ /// <summary>
+ /// The late mode to use.
+ /// </summary>
+ public ReverbLateMode LateMode;
+
+ /// <summary>
+ /// The gain to apply to the result of the late reflection. (Q15)
+ /// </summary>
+ public int LateGain;
+
+ /// <summary>
+ /// The decay time. (Q15)
+ /// </summary>
+ public int DecayTime;
+
+ /// <summary>
+ /// The high frequency decay ratio. (Q15)
+ /// </summary>
+ /// <remarks>If <see cref="HighFrequencyDecayRatio"/> >= 0.995f, it is considered disabled.</remarks>
+ public int HighFrequencyDecayRatio;
+
+ /// <summary>
+ /// The coloration of the decay. (Q15)
+ /// </summary>
+ public int Coloration;
+
+ /// <summary>
+ /// The reverb gain. (Q15)
+ /// </summary>
+ public int ReverbGain;
+
+ /// <summary>
+ /// The output gain. (Q15)
+ /// </summary>
+ public int OutGain;
+
+ /// <summary>
+ /// The dry gain. (Q15)
+ /// </summary>
+ public int DryGain;
+
+ /// <summary>
+ /// The current usage status of the effect on the client side.
+ /// </summary>
+ public UsageState Status;
+
+ /// <summary>
+ /// Check if the <see cref="ChannelCount"/> is valid.
+ /// </summary>
+ /// <returns>Returns true if the <see cref="ChannelCount"/> is valid.</returns>
+ public bool IsChannelCountValid()
+ {
+ return EffectInParameterVersion1.IsChannelCountValid(ChannelCount);
+ }
+
+ /// <summary>
+ /// Check if the <see cref="ChannelCountMax"/> is valid.
+ /// </summary>
+ /// <returns>Returns true if the <see cref="ChannelCountMax"/> is valid.</returns>
+ public bool IsChannelCountMaxValid()
+ {
+ return EffectInParameterVersion1.IsChannelCountValid(ChannelCountMax);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion1.cs b/src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion1.cs
new file mode 100644
index 00000000..e5419f70
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion1.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
+{
+ /// <summary>
+ /// Input information for an effect version 1.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct EffectInParameterVersion1 : IEffectInParameter
+ {
+ /// <summary>
+ /// Type of the effect.
+ /// </summary>
+ public EffectType Type;
+
+ /// <summary>
+ /// Set to true if the effect is new.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsNew;
+
+ /// <summary>
+ /// Set to true if the effect must be active.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsEnabled;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private byte _reserved1;
+
+ /// <summary>
+ /// The target mix id of the effect.
+ /// </summary>
+ public int MixId;
+
+ /// <summary>
+ /// Address of the processing workbuffer.
+ /// </summary>
+ /// <remarks>This is additional data that could be required by the effect processing.</remarks>
+ public ulong BufferBase;
+
+ /// <summary>
+ /// Size of the processing workbuffer.
+ /// </summary>
+ /// <remarks>This is additional data that could be required by the effect processing.</remarks>
+ public ulong BufferSize;
+
+ /// <summary>
+ /// Position of the effect while processing effects.
+ /// </summary>
+ public uint ProcessingOrder;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private uint _reserved2;
+
+ /// <summary>
+ /// Specific data storage.
+ /// </summary>
+ private SpecificDataStruct _specificDataStart;
+
+ [StructLayout(LayoutKind.Sequential, Size = 0xA0, Pack = 1)]
+ private struct SpecificDataStruct { }
+
+ public Span<byte> SpecificData => SpanHelpers.AsSpan<SpecificDataStruct, byte>(ref _specificDataStart);
+
+ EffectType IEffectInParameter.Type => Type;
+
+ bool IEffectInParameter.IsNew => IsNew;
+
+ bool IEffectInParameter.IsEnabled => IsEnabled;
+
+ int IEffectInParameter.MixId => MixId;
+
+ ulong IEffectInParameter.BufferBase => BufferBase;
+
+ ulong IEffectInParameter.BufferSize => BufferSize;
+
+ uint IEffectInParameter.ProcessingOrder => ProcessingOrder;
+
+ /// <summary>
+ /// Check if the given channel count is valid.
+ /// </summary>
+ /// <param name="channelCount">The channel count to check</param>
+ /// <returns>Returns true if the channel count is valid.</returns>
+ public static bool IsChannelCountValid(int channelCount)
+ {
+ return channelCount == 1 || channelCount == 2 || channelCount == 4 || channelCount == 6;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion2.cs b/src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion2.cs
new file mode 100644
index 00000000..250012d1
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/EffectInParameterVersion2.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
+{
+ /// <summary>
+ /// Input information for an effect version 2. (added with REV9)
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct EffectInParameterVersion2 : IEffectInParameter
+ {
+ /// <summary>
+ /// Type of the effect.
+ /// </summary>
+ public EffectType Type;
+
+ /// <summary>
+ /// Set to true if the effect is new.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsNew;
+
+ /// <summary>
+ /// Set to true if the effect must be active.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsEnabled;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private byte _reserved1;
+
+ /// <summary>
+ /// The target mix id of the effect.
+ /// </summary>
+ public int MixId;
+
+ /// <summary>
+ /// Address of the processing workbuffer.
+ /// </summary>
+ /// <remarks>This is additional data that could be required by the effect processing.</remarks>
+ public ulong BufferBase;
+
+ /// <summary>
+ /// Size of the processing workbuffer.
+ /// </summary>
+ /// <remarks>This is additional data that could be required by the effect processing.</remarks>
+ public ulong BufferSize;
+
+ /// <summary>
+ /// Position of the effect while processing effects.
+ /// </summary>
+ public uint ProcessingOrder;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private uint _reserved2;
+
+ /// <summary>
+ /// Specific data storage.
+ /// </summary>
+ private SpecificDataStruct _specificDataStart;
+
+ [StructLayout(LayoutKind.Sequential, Size = 0xA0, Pack = 1)]
+ private struct SpecificDataStruct { }
+
+ public Span<byte> SpecificData => SpanHelpers.AsSpan<SpecificDataStruct, byte>(ref _specificDataStart);
+
+ EffectType IEffectInParameter.Type => Type;
+
+ bool IEffectInParameter.IsNew => IsNew;
+
+ bool IEffectInParameter.IsEnabled => IsEnabled;
+
+ int IEffectInParameter.MixId => MixId;
+
+ ulong IEffectInParameter.BufferBase => BufferBase;
+
+ ulong IEffectInParameter.BufferSize => BufferSize;
+
+ uint IEffectInParameter.ProcessingOrder => ProcessingOrder;
+
+ /// <summary>
+ /// Check if the given channel count is valid.
+ /// </summary>
+ /// <param name="channelCount">The channel count to check</param>
+ /// <returns>Returns true if the channel count is valid.</returns>
+ public static bool IsChannelCountValid(int channelCount)
+ {
+ return channelCount == 1 || channelCount == 2 || channelCount == 4 || channelCount == 6;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/EffectOutStatusVersion1.cs b/src/Ryujinx.Audio/Renderer/Parameter/EffectOutStatusVersion1.cs
new file mode 100644
index 00000000..5e6a33ac
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/EffectOutStatusVersion1.cs
@@ -0,0 +1,23 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Output information for an effect version 1.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct EffectOutStatusVersion1 : IEffectOutStatus
+ {
+ /// <summary>
+ /// Current effect state.
+ /// </summary>
+ public EffectState State;
+
+ /// <summary>
+ /// Unused/Reserved.
+ /// </summary>
+ private unsafe fixed byte _reserved[15];
+
+ EffectState IEffectOutStatus.State { get => State; set => State = value; }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/EffectOutStatusVersion2.cs b/src/Ryujinx.Audio/Renderer/Parameter/EffectOutStatusVersion2.cs
new file mode 100644
index 00000000..f2c9768b
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/EffectOutStatusVersion2.cs
@@ -0,0 +1,28 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Output information for an effect version 2. (added with REV9)
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct EffectOutStatusVersion2 : IEffectOutStatus
+ {
+ /// <summary>
+ /// Current effect state.
+ /// </summary>
+ public EffectState State;
+
+ /// <summary>
+ /// Unused/Reserved.
+ /// </summary>
+ private unsafe fixed byte _reserved[15];
+
+ /// <summary>
+ /// Current result state.
+ /// </summary>
+ public EffectResultState ResultState;
+
+ EffectState IEffectOutStatus.State { get => State; set => State = value; }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/EffectResultState.cs b/src/Ryujinx.Audio/Renderer/Parameter/EffectResultState.cs
new file mode 100644
index 00000000..bd96c22b
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/EffectResultState.cs
@@ -0,0 +1,26 @@
+using Ryujinx.Common.Utilities;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Effect result state (added in REV9).
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct EffectResultState
+ {
+ /// <summary>
+ /// Specific data storage.
+ /// </summary>
+ private SpecificDataStruct _specificDataStart;
+
+ [StructLayout(LayoutKind.Sequential, Size = 0x80, Pack = 1)]
+ private struct SpecificDataStruct { }
+
+ /// <summary>
+ /// Specific data changing depending of the type of effect. See also the <see cref="Effect"/> namespace.
+ /// </summary>
+ public Span<byte> SpecificData => SpanHelpers.AsSpan<SpecificDataStruct, byte>(ref _specificDataStart);
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/EffectState.cs b/src/Ryujinx.Audio/Renderer/Parameter/EffectState.cs
new file mode 100644
index 00000000..911ba6d8
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/EffectState.cs
@@ -0,0 +1,18 @@
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// The state of an effect.
+ /// </summary>
+ public enum EffectState : byte
+ {
+ /// <summary>
+ /// The effect is enabled.
+ /// </summary>
+ Enabled = 3,
+
+ /// <summary>
+ /// The effect is disabled.
+ /// </summary>
+ Disabled = 4
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/IEffectInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/IEffectInParameter.cs
new file mode 100644
index 00000000..bdd1ca45
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/IEffectInParameter.cs
@@ -0,0 +1,53 @@
+using Ryujinx.Audio.Renderer.Common;
+using System;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Generic interface to represent input information for an effect.
+ /// </summary>
+ public interface IEffectInParameter
+ {
+ /// <summary>
+ /// Type of the effect.
+ /// </summary>
+ EffectType Type { get; }
+
+ /// <summary>
+ /// Set to true if the effect is new.
+ /// </summary>
+ bool IsNew { get; }
+
+ /// <summary>
+ /// Set to true if the effect must be active.
+ /// </summary>
+ bool IsEnabled { get; }
+
+ /// <summary>
+ /// The target mix id of the effect.
+ /// </summary>
+ int MixId { get; }
+
+ /// <summary>
+ /// Address of the processing workbuffer.
+ /// </summary>
+ /// <remarks>This is additional data that could be required by the effect processing.</remarks>
+ ulong BufferBase { get; }
+
+ /// <summary>
+ /// Size of the processing workbuffer.
+ /// </summary>
+ /// <remarks>This is additional data that could be required by the effect processing.</remarks>
+ ulong BufferSize { get; }
+
+ /// <summary>
+ /// Position of the effect while processing effects.
+ /// </summary>
+ uint ProcessingOrder { get; }
+
+ /// <summary>
+ /// Specific data changing depending of the <see cref="Type"/>. See also the <see cref="Effect"/> namespace.
+ /// </summary>
+ Span<byte> SpecificData { get; }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/IEffectOutStatus.cs b/src/Ryujinx.Audio/Renderer/Parameter/IEffectOutStatus.cs
new file mode 100644
index 00000000..a5addbcb
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/IEffectOutStatus.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Generic interface to represent output information for an effect.
+ /// </summary>
+ public interface IEffectOutStatus
+ {
+ /// <summary>
+ /// Current effect state.
+ /// </summary>
+ EffectState State { get; set; }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/MemoryPoolInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/MemoryPoolInParameter.cs
new file mode 100644
index 00000000..242e3843
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/MemoryPoolInParameter.cs
@@ -0,0 +1,33 @@
+using Ryujinx.Audio.Renderer.Common;
+using System.Runtime.InteropServices;
+using CpuAddress = System.UInt64;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Input information for a memory pool.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct MemoryPoolInParameter
+ {
+ /// <summary>
+ /// The CPU address used by the memory pool.
+ /// </summary>
+ public CpuAddress CpuAddress;
+
+ /// <summary>
+ /// The size used by the memory pool.
+ /// </summary>
+ public ulong Size;
+
+ /// <summary>
+ /// The target state the user wants.
+ /// </summary>
+ public MemoryPoolUserState State;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private unsafe fixed uint _reserved[3];
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/MemoryPoolOutStatus.cs b/src/Ryujinx.Audio/Renderer/Parameter/MemoryPoolOutStatus.cs
new file mode 100644
index 00000000..29a6e261
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/MemoryPoolOutStatus.cs
@@ -0,0 +1,22 @@
+using Ryujinx.Audio.Renderer.Common;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Output information for a memory pool.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct MemoryPoolOutStatus
+ {
+ /// <summary>
+ /// The current server memory pool state.
+ /// </summary>
+ public MemoryPoolUserState State;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private unsafe fixed uint _reserved[3];
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/MixInParameterDirtyOnlyUpdate.cs b/src/Ryujinx.Audio/Renderer/Parameter/MixInParameterDirtyOnlyUpdate.cs
new file mode 100644
index 00000000..c0954cda
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/MixInParameterDirtyOnlyUpdate.cs
@@ -0,0 +1,27 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Input information header for mix updates on REV7 and later
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct MixInParameterDirtyOnlyUpdate
+ {
+ /// <summary>
+ /// Magic of the header
+ /// </summary>
+ /// <remarks>Never checked on hardware.</remarks>
+ public uint Magic;
+
+ /// <summary>
+ /// The count of <see cref="MixParameter"/> following this header.
+ /// </summary>
+ public uint MixCount;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private unsafe fixed byte _reserved[24];
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/MixParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/MixParameter.cs
new file mode 100644
index 00000000..5b9a969a
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/MixParameter.cs
@@ -0,0 +1,95 @@
+using Ryujinx.Common.Utilities;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Input information for a mix.
+ /// </summary>
+ /// <remarks>Also used on the client side for mix tracking.</remarks>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct MixParameter
+ {
+ /// <summary>
+ /// Base volume of the mix.
+ /// </summary>
+ public float Volume;
+
+ /// <summary>
+ /// Target sample rate of the mix.
+ /// </summary>
+ public uint SampleRate;
+
+ /// <summary>
+ /// Target buffer count.
+ /// </summary>
+ public uint BufferCount;
+
+ /// <summary>
+ /// Set to true if in use.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsUsed;
+
+ /// <summary>
+ /// Set to true if it was changed.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsDirty;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private ushort _reserved1;
+
+ /// <summary>
+ /// The id of the mix.
+ /// </summary>
+ public int MixId;
+
+ /// <summary>
+ /// The effect count. (client side)
+ /// </summary>
+ public uint EffectCount;
+
+ /// <summary>
+ /// The mix node id.
+ /// </summary>
+ public int NodeId;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private ulong _reserved2;
+
+ /// <summary>
+ /// Mix buffer volumes storage.
+ /// </summary>
+ private MixVolumeArray _mixBufferVolumeArray;
+
+ /// <summary>
+ /// The mix to output the result of this mix.
+ /// </summary>
+ public int DestinationMixId;
+
+ /// <summary>
+ /// The splitter to output the result of this mix.
+ /// </summary>
+ public uint DestinationSplitterId;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private uint _reserved3;
+
+ [StructLayout(LayoutKind.Sequential, Size = 4 * Constants.MixBufferCountMax * Constants.MixBufferCountMax, Pack = 1)]
+ private struct MixVolumeArray { }
+
+ /// <summary>
+ /// Mix buffer volumes.
+ /// </summary>
+ /// <remarks>Used when no splitter id is specified.</remarks>
+ public Span<float> MixBufferVolume => SpanHelpers.AsSpan<MixVolumeArray, float>(ref _mixBufferVolumeArray);
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Performance/PerformanceInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Performance/PerformanceInParameter.cs
new file mode 100644
index 00000000..0f9a3aa3
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Performance/PerformanceInParameter.cs
@@ -0,0 +1,21 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Performance
+{
+ /// <summary>
+ /// Input information for performance monitoring.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct PerformanceInParameter
+ {
+ /// <summary>
+ /// The target node id to monitor performance on.
+ /// </summary>
+ public int TargetNodeId;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private unsafe fixed uint _reserved[3];
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Performance/PerformanceOutStatus.cs b/src/Ryujinx.Audio/Renderer/Parameter/Performance/PerformanceOutStatus.cs
new file mode 100644
index 00000000..64bbe080
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Performance/PerformanceOutStatus.cs
@@ -0,0 +1,21 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Performance
+{
+ /// <summary>
+ /// Output information for performance monitoring.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct PerformanceOutStatus
+ {
+ /// <summary>
+ /// Indicates the total size output to the performance buffer.
+ /// </summary>
+ public uint HistorySize;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private unsafe fixed uint _reserved[3];
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/RendererInfoOutStatus.cs b/src/Ryujinx.Audio/Renderer/Parameter/RendererInfoOutStatus.cs
new file mode 100644
index 00000000..a42ea833
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/RendererInfoOutStatus.cs
@@ -0,0 +1,21 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Renderer output information on REV5 and later.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct RendererInfoOutStatus
+ {
+ /// <summary>
+ /// The count of updates sent to the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ public ulong ElapsedFrameCount;
+
+ /// <summary>
+ /// Reserved/Unused.
+ /// </summary>
+ private ulong _reserved;
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Sink/CircularBufferParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Sink/CircularBufferParameter.cs
new file mode 100644
index 00000000..7c02d65f
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Sink/CircularBufferParameter.cs
@@ -0,0 +1,62 @@
+using Ryujinx.Audio.Common;
+using Ryujinx.Audio.Renderer.Common;
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+using CpuAddress = System.UInt64;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Sink
+{
+ /// <summary>
+ /// <see cref="SinkInParameter.SpecificData"/> for <see cref="SinkType.CircularBuffer"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct CircularBufferParameter
+ {
+ /// <summary>
+ /// The CPU address of the user circular buffer.
+ /// </summary>
+ public CpuAddress BufferAddress;
+
+ /// <summary>
+ /// The size of the user circular buffer.
+ /// </summary>
+ public uint BufferSize;
+
+ /// <summary>
+ /// The total count of channels to output to the circular buffer.
+ /// </summary>
+ public uint InputCount;
+
+ /// <summary>
+ /// The target sample count to output per update in the circular buffer.
+ /// </summary>
+ public uint SampleCount;
+
+ /// <summary>
+ /// Last read offset on the CPU side.
+ /// </summary>
+ public uint LastReadOffset;
+
+ /// <summary>
+ /// The target <see cref="SampleFormat"/>.
+ /// </summary>
+ /// <remarks>Only <see cref="SampleFormat.PcmInt16"/> is supported.</remarks>
+ public SampleFormat SampleFormat;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private unsafe fixed byte _reserved1[3];
+
+ /// <summary>
+ /// The input channels index that will be used.
+ /// </summary>
+ public Array6<byte> Input;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private ushort _reserved2;
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/Sink/DeviceParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/Sink/DeviceParameter.cs
new file mode 100644
index 00000000..abeadacc
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/Sink/DeviceParameter.cs
@@ -0,0 +1,58 @@
+using Ryujinx.Common.Memory;
+using Ryujinx.Common.Utilities;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter.Sink
+{
+ /// <summary>
+ /// <see cref="SinkInParameter.SpecificData"/> for <see cref="Common.SinkType.Device"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct DeviceParameter
+ {
+ /// <summary>
+ /// Device name storage.
+ /// </summary>
+ private DeviceNameStruct _deviceName;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private byte _padding;
+
+ /// <summary>
+ /// The total count of channels to output to the device.
+ /// </summary>
+ public uint InputCount;
+
+ /// <summary>
+ /// The input channels index that will be used.
+ /// </summary>
+ public Array6<byte> Input;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private byte _reserved;
+
+ /// <summary>
+ /// Set to true if the user controls Surround to Stereo downmixing coefficients.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool DownMixParameterEnabled;
+
+ /// <summary>
+ /// The user Surround to Stereo downmixing coefficients.
+ /// </summary>
+ public Array4<float> DownMixParameter;
+
+ [StructLayout(LayoutKind.Sequential, Size = 0xFF, Pack = 1)]
+ private struct DeviceNameStruct { }
+
+ /// <summary>
+ /// The output device name.
+ /// </summary>
+ public Span<byte> DeviceName => SpanHelpers.AsSpan<DeviceNameStruct, byte>(ref _deviceName);
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SinkInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/SinkInParameter.cs
new file mode 100644
index 00000000..1ee4eb53
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/SinkInParameter.cs
@@ -0,0 +1,53 @@
+using Ryujinx.Audio.Renderer.Common;
+using Ryujinx.Common.Utilities;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Input information for a sink.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct SinkInParameter
+ {
+ /// <summary>
+ /// Type of the sink.
+ /// </summary>
+ public SinkType Type;
+
+ /// <summary>
+ /// Set to true if the sink is used.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsUsed;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private ushort _reserved1;
+
+ /// <summary>
+ /// The node id of the sink.
+ /// </summary>
+ public int NodeId;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private unsafe fixed ulong _reserved2[3];
+
+ /// <summary>
+ /// Specific data storage.
+ /// </summary>
+ private SpecificDataStruct _specificDataStart;
+
+ [StructLayout(LayoutKind.Sequential, Size = 0x120, Pack = 1)]
+ private struct SpecificDataStruct { }
+
+ /// <summary>
+ /// Specific data changing depending of the <see cref="Type"/>. See also the <see cref="Sink"/> namespace.
+ /// </summary>
+ public Span<byte> SpecificData => SpanHelpers.AsSpan<SpecificDataStruct, byte>(ref _specificDataStart);
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SinkOutStatus.cs b/src/Ryujinx.Audio/Renderer/Parameter/SinkOutStatus.cs
new file mode 100644
index 00000000..426b861c
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/SinkOutStatus.cs
@@ -0,0 +1,26 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Output information for a sink.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct SinkOutStatus
+ {
+ /// <summary>
+ /// Last written offset if the sink type is <see cref="Common.SinkType.CircularBuffer"/>.
+ /// </summary>
+ public uint LastWrittenOffset;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private uint _padding;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private unsafe fixed ulong _reserved[3];
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameter.cs
new file mode 100644
index 00000000..96c43092
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/SplitterDestinationInParameter.cs
@@ -0,0 +1,67 @@
+using Ryujinx.Common.Utilities;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Input header for a splitter destination update.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct SplitterDestinationInParameter
+ {
+ /// <summary>
+ /// Magic of the input header.
+ /// </summary>
+ public uint Magic;
+
+ /// <summary>
+ /// Target splitter destination data id.
+ /// </summary>
+ public int Id;
+
+ /// <summary>
+ /// Mix buffer volumes storage.
+ /// </summary>
+ private MixArray _mixBufferVolume;
+
+ /// <summary>
+ /// The mix to output the result of the splitter.
+ /// </summary>
+ public int DestinationId;
+
+ /// <summary>
+ /// Set to true if in use.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsUsed;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private unsafe fixed byte _reserved[3];
+
+ [StructLayout(LayoutKind.Sequential, Size = 4 * Constants.MixBufferCountMax, Pack = 1)]
+ private struct MixArray { }
+
+ /// <summary>
+ /// Mix buffer volumes.
+ /// </summary>
+ /// <remarks>Used when a splitter id is specified in the mix.</remarks>
+ public Span<float> MixBufferVolume => SpanHelpers.AsSpan<MixArray, float>(ref _mixBufferVolume);
+
+ /// <summary>
+ /// The expected constant of any input header.
+ /// </summary>
+ private const uint ValidMagic = 0x44444E53;
+
+ /// <summary>
+ /// Check if the magic is valid.
+ /// </summary>
+ /// <returns>Returns true if the magic is valid.</returns>
+ public bool IsMagicValid()
+ {
+ return Magic == ValidMagic;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SplitterInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/SplitterInParameter.cs
new file mode 100644
index 00000000..0220497d
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/SplitterInParameter.cs
@@ -0,0 +1,46 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Input header for a splitter state update.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct SplitterInParameter
+ {
+ /// <summary>
+ /// Magic of the input header.
+ /// </summary>
+ public uint Magic;
+
+ /// <summary>
+ /// Target splitter id.
+ /// </summary>
+ public int Id;
+
+ /// <summary>
+ /// Target sample rate to use on the splitter.
+ /// </summary>
+ public uint SampleRate;
+
+ /// <summary>
+ /// Count of splitter destinations.
+ /// </summary>
+ /// <remarks>Splitter destination ids are defined right after this header.</remarks>
+ public int DestinationCount;
+
+ /// <summary>
+ /// The expected constant of any input header.
+ /// </summary>
+ private const uint ValidMagic = 0x49444E53;
+
+ /// <summary>
+ /// Check if the magic is valid.
+ /// </summary>
+ /// <returns>Returns true if the magic is valid.</returns>
+ public bool IsMagicValid()
+ {
+ return Magic == ValidMagic;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/SplitterInParameterHeader.cs b/src/Ryujinx.Audio/Renderer/Parameter/SplitterInParameterHeader.cs
new file mode 100644
index 00000000..dbae17a9
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/SplitterInParameterHeader.cs
@@ -0,0 +1,45 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Input header for splitter update.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct SplitterInParameterHeader
+ {
+ /// <summary>
+ /// Magic of the input header.
+ /// </summary>
+ public uint Magic;
+
+ /// <summary>
+ /// The count of <see cref="SplitterInParameter"/> after the header.
+ /// </summary>
+ public uint SplitterCount;
+
+ /// <summary>
+ /// The count of splitter destinations after the header and splitter info.
+ /// </summary>
+ public uint SplitterDestinationCount;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private unsafe fixed uint _reserved[5];
+
+ /// <summary>
+ /// The expected constant of any input splitter header.
+ /// </summary>
+ private const uint ValidMagic = 0x48444E53;
+
+ /// <summary>
+ /// Check if the magic is valid.
+ /// </summary>
+ /// <returns>Returns true if the magic is valid.</returns>
+ public bool IsMagicValid()
+ {
+ return Magic == ValidMagic;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/VoiceChannelResourceInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/VoiceChannelResourceInParameter.cs
new file mode 100644
index 00000000..6a863237
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/VoiceChannelResourceInParameter.cs
@@ -0,0 +1,28 @@
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Input information for a voice channel resources.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Size = 0x70, Pack = 1)]
+ public struct VoiceChannelResourceInParameter
+ {
+ /// <summary>
+ /// The id of the voice channel resource.
+ /// </summary>
+ public uint Id;
+
+ /// <summary>
+ /// Mix volumes for the voice channel resource.
+ /// </summary>
+ public Array24<float> Mix;
+
+ /// <summary>
+ /// Indicate if the voice channel resource is used.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsUsed;
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter.cs b/src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter.cs
new file mode 100644
index 00000000..c4b4ba31
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/VoiceInParameter.cs
@@ -0,0 +1,344 @@
+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
+{
+ /// <summary>
+ /// Input information for a voice.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Size = 0x170, Pack = 1)]
+ public struct VoiceInParameter
+ {
+ /// <summary>
+ /// Id of the voice.
+ /// </summary>
+ public int Id;
+
+ /// <summary>
+ /// Node id of the voice.
+ /// </summary>
+ public int NodeId;
+
+ /// <summary>
+ /// Set to true if the voice is new.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsNew;
+
+ /// <summary>
+ /// Set to true if the voice is used.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool InUse;
+
+ /// <summary>
+ /// The voice <see cref="PlayState"/> wanted by the user.
+ /// </summary>
+ public PlayState PlayState;
+
+ /// <summary>
+ /// The <see cref="SampleFormat"/> of the voice.
+ /// </summary>
+ public SampleFormat SampleFormat;
+
+ /// <summary>
+ /// The sample rate of the voice.
+ /// </summary>
+ public uint SampleRate;
+
+ /// <summary>
+ /// The priority of the voice.
+ /// </summary>
+ public uint Priority;
+
+ /// <summary>
+ /// Target sorting position of the voice. (Used to sort voices with the same <see cref="Priority"/>)
+ /// </summary>
+ public uint SortingOrder;
+
+ /// <summary>
+ /// The total channel count used.
+ /// </summary>
+ public uint ChannelCount;
+
+ /// <summary>
+ /// The pitch used on the voice.
+ /// </summary>
+ public float Pitch;
+
+ /// <summary>
+ /// The output volume of the voice.
+ /// </summary>
+ public float Volume;
+
+ /// <summary>
+ /// Biquad filters to apply to the output of the voice.
+ /// </summary>
+ public Array2<BiquadFilterParameter> BiquadFilters;
+
+ /// <summary>
+ /// Total count of <see cref="WaveBufferInternal"/> of the voice.
+ /// </summary>
+ public uint WaveBuffersCount;
+
+ /// <summary>
+ /// Current playing <see cref="WaveBufferInternal"/> of the voice.
+ /// </summary>
+ public uint WaveBuffersIndex;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private uint _reserved1;
+
+ /// <summary>
+ /// User state address required by the data source.
+ /// </summary>
+ /// <remarks>Only used for <see cref="SampleFormat.Adpcm"/> as the address of the GC-ADPCM coefficients.</remarks>
+ public ulong DataSourceStateAddress;
+
+ /// <summary>
+ /// User state size required by the data source.
+ /// </summary>
+ /// <remarks>Only used for <see cref="SampleFormat.Adpcm"/> as the size of the GC-ADPCM coefficients.</remarks>
+ public ulong DataSourceStateSize;
+
+ /// <summary>
+ /// The target mix id of the voice.
+ /// </summary>
+ public int MixId;
+
+ /// <summary>
+ /// The target splitter id of the voice.
+ /// </summary>
+ public uint SplitterId;
+
+ /// <summary>
+ /// The wavebuffer parameters of this voice.
+ /// </summary>
+ public Array4<WaveBufferInternal> WaveBuffers;
+
+ /// <summary>
+ /// The channel resource ids associated to the voice.
+ /// </summary>
+ public Array6<int> ChannelResourceIds;
+
+ /// <summary>
+ /// Reset the voice drop flag during voice server update.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool ResetVoiceDropFlag;
+
+ /// <summary>
+ /// Flush the amount of wavebuffer specified. This will result in the wavebuffer being skipped and marked played.
+ /// </summary>
+ /// <remarks>This was added on REV5.</remarks>
+ public byte FlushWaveBufferCount;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private ushort _reserved2;
+
+ /// <summary>
+ /// Change the behaviour of the voice.
+ /// </summary>
+ /// <remarks>This was added on REV5.</remarks>
+ public DecodingBehaviour DecodingBehaviourFlags;
+
+ /// <summary>
+ /// Change the Sample Rate Conversion (SRC) quality of the voice.
+ /// </summary>
+ /// <remarks>This was added on REV8.</remarks>
+ public SampleRateConversionQuality SrcQuality;
+
+ /// <summary>
+ /// This was previously used for opus codec support on the Audio Renderer and was removed on REV3.
+ /// </summary>
+ public uint ExternalContext;
+
+ /// <summary>
+ /// This was previously used for opus codec support on the Audio Renderer and was removed on REV3.
+ /// </summary>
+ public uint ExternalContextSize;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private unsafe fixed uint _reserved3[2];
+
+ /// <summary>
+ /// Input information for a voice wavebuffer.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Size = 0x38, Pack = 1)]
+ public struct WaveBufferInternal
+ {
+ /// <summary>
+ /// Address of the wavebuffer data.
+ /// </summary>
+ public ulong Address;
+
+ /// <summary>
+ /// Size of the wavebuffer data.
+ /// </summary>
+ public ulong Size;
+
+ /// <summary>
+ /// Offset of the first sample to play.
+ /// </summary>
+ public uint StartSampleOffset;
+
+ /// <summary>
+ /// Offset of the last sample to play.
+ /// </summary>
+ public uint EndSampleOffset;
+
+ /// <summary>
+ /// If set to true, the wavebuffer will loop when reaching <see cref="EndSampleOffset"/>.
+ /// </summary>
+ /// <remarks>
+ /// Starting with REV8, you can specify how many times to loop the wavebuffer (<see cref="LoopCount"/>) and where it should start and end when looping (<see cref="LoopFirstSampleOffset"/> and <see cref="LoopLastSampleOffset"/>)
+ /// </remarks>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool ShouldLoop;
+
+ /// <summary>
+ /// Indicates that this is the last wavebuffer to play of the voice.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsEndOfStream;
+
+ /// <summary>
+ /// Indicates if the server should update its internal state.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool SentToServer;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private byte _reserved;
+
+ /// <summary>
+ /// If set to anything other than 0, specifies how many times to loop the wavebuffer.
+ /// </summary>
+ /// <remarks>This was added in REV8.</remarks>
+ public int LoopCount;
+
+ /// <summary>
+ /// Address of the context used by the sample decoder.
+ /// </summary>
+ /// <remarks>This is only currently used by <see cref="SampleFormat.Adpcm"/>.</remarks>
+ public ulong ContextAddress;
+
+ /// <summary>
+ /// Size of the context used by the sample decoder.
+ /// </summary>
+ /// <remarks>This is only currently used by <see cref="SampleFormat.Adpcm"/>.</remarks>
+ public ulong ContextSize;
+
+ /// <summary>
+ /// If set to anything other than 0, specifies the offset of the first sample to play when looping.
+ /// </summary>
+ /// <remarks>This was added in REV8.</remarks>
+ public uint LoopFirstSampleOffset;
+
+ /// <summary>
+ /// If set to anything other than 0, specifies the offset of the last sample to play when looping.
+ /// </summary>
+ /// <remarks>This was added in REV8.</remarks>
+ public uint LoopLastSampleOffset;
+
+ /// <summary>
+ /// Check if the sample offsets are in a valid range for generic PCM.
+ /// </summary>
+ /// <typeparam name="T">The PCM sample type</typeparam>
+ /// <returns>Returns true if the sample offset are in range of the size.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private bool IsSampleOffsetInRangeForPcm<T>() where T : unmanaged
+ {
+ uint dataTypeSize = (uint)Unsafe.SizeOf<T>();
+
+ return StartSampleOffset * dataTypeSize <= Size &&
+ EndSampleOffset * dataTypeSize <= Size;
+ }
+
+ /// <summary>
+ /// Check if the sample offsets are in a valid range for the given <see cref="SampleFormat"/>.
+ /// </summary>
+ /// <param name="format">The target <see cref="SampleFormat"/></param>
+ /// <returns>Returns true if the sample offset are in range of the size.</returns>
+ public bool IsSampleOffsetValid(SampleFormat format)
+ {
+ bool result;
+
+ switch (format)
+ {
+ case SampleFormat.PcmInt16:
+ result = IsSampleOffsetInRangeForPcm<ushort>();
+ break;
+ case SampleFormat.PcmFloat:
+ result = IsSampleOffsetInRangeForPcm<float>();
+ break;
+ case SampleFormat.Adpcm:
+ result = AdpcmHelper.GetAdpcmDataSize((int)StartSampleOffset) <= Size &&
+ AdpcmHelper.GetAdpcmDataSize((int)EndSampleOffset) <= Size;
+ break;
+ default:
+ throw new NotImplementedException($"{format} not implemented!");
+ }
+
+ return result;
+ }
+ }
+
+ /// <summary>
+ /// Flag altering the behaviour of wavebuffer decoding.
+ /// </summary>
+ [Flags]
+ public enum DecodingBehaviour : ushort
+ {
+ /// <summary>
+ /// Default decoding behaviour.
+ /// </summary>
+ Default = 0,
+
+ /// <summary>
+ /// Reset the played samples accumulator when looping.
+ /// </summary>
+ PlayedSampleCountResetWhenLooping = 1,
+
+ /// <summary>
+ /// Skip pitch and Sample Rate Conversion (SRC).
+ /// </summary>
+ SkipPitchAndSampleRateConversion = 2
+ }
+
+ /// <summary>
+ /// Specify the quality to use during Sample Rate Conversion (SRC) and pitch handling.
+ /// </summary>
+ /// <remarks>This was added in REV8.</remarks>
+ public enum SampleRateConversionQuality : byte
+ {
+ /// <summary>
+ /// Resample interpolating 4 samples per output sample.
+ /// </summary>
+ Default,
+
+ /// <summary>
+ /// Resample interpolating 8 samples per output sample.
+ /// </summary>
+ High,
+
+ /// <summary>
+ /// Resample interpolating 1 samples per output sample.
+ /// </summary>
+ Low
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Parameter/VoiceOutStatus.cs b/src/Ryujinx.Audio/Renderer/Parameter/VoiceOutStatus.cs
new file mode 100644
index 00000000..be9d3584
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Parameter/VoiceOutStatus.cs
@@ -0,0 +1,35 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Parameter
+{
+ /// <summary>
+ /// Output information about a voice.
+ /// </summary>
+ /// <remarks>See <seealso cref="Server.StateUpdater.UpdateVoices(Server.Voice.VoiceContext, System.Memory{Server.MemoryPool.MemoryPoolState})"/></remarks>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct VoiceOutStatus
+ {
+ /// <summary>
+ /// The total amount of samples that was played.
+ /// </summary>
+ /// <remarks>This is reset to 0 when a <see cref="Common.WaveBuffer"/> finishes playing and <see cref="Common.WaveBuffer.IsEndOfStream"/> is set.</remarks>
+ /// <remarks>This is reset to 0 when looping while <see cref="Parameter.VoiceInParameter.DecodingBehaviour.PlayedSampleCountResetWhenLooping"/> is set.</remarks>
+ public ulong PlayedSampleCount;
+
+ /// <summary>
+ /// The total amount of <see cref="WaveBuffer"/> consumed.
+ /// </summary>
+ public uint PlayedWaveBuffersCount;
+
+ /// <summary>
+ /// If set to true, the voice was dropped.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool VoiceDropFlag;
+
+ /// <summary>
+ /// Reserved/unused.
+ /// </summary>
+ private unsafe fixed byte _reserved[3];
+ }
+} \ No newline at end of file