diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.Audio/Renderer/Parameter | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'src/Ryujinx.Audio/Renderer/Parameter')
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 |
