aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs')
-rw-r--r--src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs339
1 files changed, 257 insertions, 82 deletions
diff --git a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs
index 1faf7921..36dfa5e4 100644
--- a/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs
+++ b/src/Ryujinx.Audio/Renderer/Server/Splitter/SplitterDestination.cs
@@ -1,115 +1,198 @@
using Ryujinx.Audio.Renderer.Parameter;
-using Ryujinx.Common.Utilities;
using System;
using System.Diagnostics;
-using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
namespace Ryujinx.Audio.Renderer.Server.Splitter
{
/// <summary>
/// Server state for a splitter destination.
/// </summary>
- [StructLayout(LayoutKind.Sequential, Size = 0xE0, Pack = Alignment)]
- public struct SplitterDestination
+ public ref struct SplitterDestination
{
- public const int Alignment = 0x10;
+ private ref SplitterDestinationVersion1 _v1;
+ private ref SplitterDestinationVersion2 _v2;
/// <summary>
- /// The unique id of this <see cref="SplitterDestination"/>.
+ /// Checks if the splitter destination data reference is null.
/// </summary>
- public int Id;
+ public bool IsNull => Unsafe.IsNullRef(ref _v1) && Unsafe.IsNullRef(ref _v2);
/// <summary>
- /// The mix to output the result of the splitter.
- /// </summary>
- public int DestinationId;
-
- /// <summary>
- /// Mix buffer volumes storage.
- /// </summary>
- private MixArray _mix;
- private MixArray _previousMix;
-
- /// <summary>
- /// Pointer to the next linked element.
- /// </summary>
- private unsafe SplitterDestination* _next;
-
- /// <summary>
- /// Set to true if in use.
+ /// The splitter unique id.
/// </summary>
- [MarshalAs(UnmanagedType.I1)]
- public bool IsUsed;
+ public int Id
+ {
+ get
+ {
+ if (Unsafe.IsNullRef(ref _v2))
+ {
+ if (Unsafe.IsNullRef(ref _v1))
+ {
+ return 0;
+ }
+ else
+ {
+ return _v1.Id;
+ }
+ }
+ else
+ {
+ return _v2.Id;
+ }
+ }
+ }
/// <summary>
- /// Set to true if the internal state need to be updated.
+ /// The mix to output the result of the splitter.
/// </summary>
- [MarshalAs(UnmanagedType.I1)]
- public bool NeedToUpdateInternalState;
-
- [StructLayout(LayoutKind.Sequential, Size = 4 * Constants.MixBufferCountMax, Pack = 1)]
- private struct MixArray { }
+ public int DestinationId
+ {
+ get
+ {
+ if (Unsafe.IsNullRef(ref _v2))
+ {
+ if (Unsafe.IsNullRef(ref _v1))
+ {
+ return 0;
+ }
+ else
+ {
+ return _v1.DestinationId;
+ }
+ }
+ else
+ {
+ return _v2.DestinationId;
+ }
+ }
+ }
/// <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 _mix);
+ public Span<float> MixBufferVolume
+ {
+ get
+ {
+ if (Unsafe.IsNullRef(ref _v2))
+ {
+ if (Unsafe.IsNullRef(ref _v1))
+ {
+ return Span<float>.Empty;
+ }
+ else
+ {
+ return _v1.MixBufferVolume;
+ }
+ }
+ else
+ {
+ return _v2.MixBufferVolume;
+ }
+ }
+ }
/// <summary>
/// Previous mix buffer volumes.
/// </summary>
/// <remarks>Used when a splitter id is specified in the mix.</remarks>
- public Span<float> PreviousMixBufferVolume => SpanHelpers.AsSpan<MixArray, float>(ref _previousMix);
+ public Span<float> PreviousMixBufferVolume
+ {
+ get
+ {
+ if (Unsafe.IsNullRef(ref _v2))
+ {
+ if (Unsafe.IsNullRef(ref _v1))
+ {
+ return Span<float>.Empty;
+ }
+ else
+ {
+ return _v1.PreviousMixBufferVolume;
+ }
+ }
+ else
+ {
+ return _v2.PreviousMixBufferVolume;
+ }
+ }
+ }
/// <summary>
- /// Get the <see cref="Span{SplitterDestination}"/> of the next element or <see cref="Span{SplitterDestination}.Empty"/> if not present.
+ /// Get the <see cref="SplitterDestination"/> of the next element or null if not present.
/// </summary>
- public readonly Span<SplitterDestination> Next
+ public readonly SplitterDestination Next
{
get
{
unsafe
{
- return _next != null ? new Span<SplitterDestination>(_next, 1) : Span<SplitterDestination>.Empty;
+ if (Unsafe.IsNullRef(ref _v2))
+ {
+ if (Unsafe.IsNullRef(ref _v1))
+ {
+ return new SplitterDestination();
+ }
+ else
+ {
+ return new SplitterDestination(ref _v1.Next);
+ }
+ }
+ else
+ {
+ return new SplitterDestination(ref _v2.Next);
+ }
}
}
}
/// <summary>
- /// Create a new <see cref="SplitterDestination"/>.
+ /// Creates a new splitter destination wrapper for the version 1 splitter destination data.
/// </summary>
- /// <param name="id">The unique id of this <see cref="SplitterDestination"/>.</param>
- public SplitterDestination(int id) : this()
+ /// <param name="v1">Version 1 splitter destination data</param>
+ public SplitterDestination(ref SplitterDestinationVersion1 v1)
{
- Id = id;
- DestinationId = Constants.UnusedMixId;
-
- ClearVolumes();
+ _v1 = ref v1;
+ _v2 = ref Unsafe.NullRef<SplitterDestinationVersion2>();
}
/// <summary>
- /// Update the <see cref="SplitterDestination"/> from user parameter.
+ /// Creates a new splitter destination wrapper for the version 2 splitter destination data.
/// </summary>
- /// <param name="parameter">The user parameter.</param>
- public void Update(SplitterDestinationInParameter parameter)
+ /// <param name="v2">Version 2 splitter destination data</param>
+ public SplitterDestination(ref SplitterDestinationVersion2 v2)
{
- Debug.Assert(Id == parameter.Id);
-
- if (parameter.IsMagicValid() && Id == parameter.Id)
- {
- DestinationId = parameter.DestinationId;
- parameter.MixBufferVolume.CopyTo(MixBufferVolume);
-
- if (!IsUsed && parameter.IsUsed)
- {
- MixBufferVolume.CopyTo(PreviousMixBufferVolume);
+ _v1 = ref Unsafe.NullRef<SplitterDestinationVersion1>();
+ _v2 = ref v2;
+ }
- NeedToUpdateInternalState = false;
- }
+ /// <summary>
+ /// Creates a new splitter destination wrapper for the splitter destination data.
+ /// </summary>
+ /// <param name="v1">Version 1 splitter destination data</param>
+ /// <param name="v2">Version 2 splitter destination data</param>
+ public unsafe SplitterDestination(SplitterDestinationVersion1* v1, SplitterDestinationVersion2* v2)
+ {
+ _v1 = ref Unsafe.AsRef<SplitterDestinationVersion1>(v1);
+ _v2 = ref Unsafe.AsRef<SplitterDestinationVersion2>(v2);
+ }
- IsUsed = parameter.IsUsed;
+ /// <summary>
+ /// Update the splitter destination data from user parameter.
+ /// </summary>
+ /// <param name="parameter">The user parameter.</param>
+ public void Update<T>(in T parameter) where T : ISplitterDestinationInParameter
+ {
+ if (Unsafe.IsNullRef(ref _v2))
+ {
+ _v1.Update(parameter);
+ }
+ else
+ {
+ _v2.Update(parameter);
}
}
@@ -118,12 +201,14 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// </summary>
public void UpdateInternalState()
{
- if (IsUsed && NeedToUpdateInternalState)
+ if (Unsafe.IsNullRef(ref _v2))
{
- MixBufferVolume.CopyTo(PreviousMixBufferVolume);
+ _v1.UpdateInternalState();
+ }
+ else
+ {
+ _v2.UpdateInternalState();
}
-
- NeedToUpdateInternalState = false;
}
/// <summary>
@@ -131,16 +216,23 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// </summary>
public void MarkAsNeedToUpdateInternalState()
{
- NeedToUpdateInternalState = true;
+ if (Unsafe.IsNullRef(ref _v2))
+ {
+ _v1.MarkAsNeedToUpdateInternalState();
+ }
+ else
+ {
+ _v2.MarkAsNeedToUpdateInternalState();
+ }
}
/// <summary>
- /// Return true if the <see cref="SplitterDestination"/> is used and has a destination.
+ /// Return true if the splitter destination is used and has a destination.
/// </summary>
- /// <returns>True if the <see cref="SplitterDestination"/> is used and has a destination.</returns>
+ /// <returns>True if the splitter destination is used and has a destination.</returns>
public readonly bool IsConfigured()
{
- return IsUsed && DestinationId != Constants.UnusedMixId;
+ return Unsafe.IsNullRef(ref _v2) ? _v1.IsConfigured() : _v2.IsConfigured();
}
/// <summary>
@@ -150,9 +242,17 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// <returns>The volume for the given destination.</returns>
public float GetMixVolume(int destinationIndex)
{
- Debug.Assert(destinationIndex >= 0 && destinationIndex < Constants.MixBufferCountMax);
+ return Unsafe.IsNullRef(ref _v2) ? _v1.GetMixVolume(destinationIndex) : _v2.GetMixVolume(destinationIndex);
+ }
- return MixBufferVolume[destinationIndex];
+ /// <summary>
+ /// Get the previous volume for a given destination.
+ /// </summary>
+ /// <param name="destinationIndex">The destination index to use.</param>
+ /// <returns>The volume for the given destination.</returns>
+ public float GetMixVolumePrev(int destinationIndex)
+ {
+ return Unsafe.IsNullRef(ref _v2) ? _v1.GetMixVolumePrev(destinationIndex) : _v2.GetMixVolumePrev(destinationIndex);
}
/// <summary>
@@ -160,22 +260,33 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// </summary>
public void ClearVolumes()
{
- MixBufferVolume.Clear();
- PreviousMixBufferVolume.Clear();
+ if (Unsafe.IsNullRef(ref _v2))
+ {
+ _v1.ClearVolumes();
+ }
+ else
+ {
+ _v2.ClearVolumes();
+ }
}
/// <summary>
- /// Link the next element to the given <see cref="SplitterDestination"/>.
+ /// Link the next element to the given splitter destination.
/// </summary>
- /// <param name="next">The given <see cref="SplitterDestination"/> to link.</param>
- public void Link(ref SplitterDestination next)
+ /// <param name="next">The given splitter destination to link.</param>
+ public void Link(SplitterDestination next)
{
- unsafe
+ if (Unsafe.IsNullRef(ref _v2))
{
- fixed (SplitterDestination* nextPtr = &next)
- {
- _next = nextPtr;
- }
+ Debug.Assert(!Unsafe.IsNullRef(ref next._v1));
+
+ _v1.Link(ref next._v1);
+ }
+ else
+ {
+ Debug.Assert(!Unsafe.IsNullRef(ref next._v2));
+
+ _v2.Link(ref next._v2);
}
}
@@ -184,10 +295,74 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// </summary>
public void Unlink()
{
- unsafe
+ if (Unsafe.IsNullRef(ref _v2))
+ {
+ _v1.Unlink();
+ }
+ else
+ {
+ _v2.Unlink();
+ }
+ }
+
+ /// <summary>
+ /// Checks if any biquad filter is enabled.
+ /// </summary>
+ /// <returns>True if any biquad filter is enabled.</returns>
+ public bool IsBiquadFilterEnabled()
+ {
+ return !Unsafe.IsNullRef(ref _v2) && _v2.IsBiquadFilterEnabled();
+ }
+
+ /// <summary>
+ /// Checks if any biquad filter was previously enabled.
+ /// </summary>
+ /// <returns>True if any biquad filter was previously enabled.</returns>
+ public bool IsBiquadFilterEnabledPrev()
+ {
+ return !Unsafe.IsNullRef(ref _v2) && _v2.IsBiquadFilterEnabledPrev();
+ }
+
+ /// <summary>
+ /// Gets the biquad filter parameters.
+ /// </summary>
+ /// <param name="index">Biquad filter index (0 or 1).</param>
+ /// <returns>Biquad filter parameters.</returns>
+ public ref BiquadFilterParameter GetBiquadFilterParameter(int index)
+ {
+ Debug.Assert(!Unsafe.IsNullRef(ref _v2));
+
+ return ref _v2.GetBiquadFilterParameter(index);
+ }
+
+ /// <summary>
+ /// Checks if any biquad filter was previously enabled.
+ /// </summary>
+ /// <param name="index">Biquad filter index (0 or 1).</param>
+ public void UpdateBiquadFilterEnabledPrev(int index)
+ {
+ if (!Unsafe.IsNullRef(ref _v2))
{
- _next = null;
+ _v2.UpdateBiquadFilterEnabledPrev(index);
}
}
+
+ /// <summary>
+ /// Get the reference for the version 1 splitter destination data, or null if version 2 is being used or the destination is null.
+ /// </summary>
+ /// <returns>Reference for the version 1 splitter destination data.</returns>
+ public ref SplitterDestinationVersion1 GetV1RefOrNull()
+ {
+ return ref _v1;
+ }
+
+ /// <summary>
+ /// Get the reference for the version 2 splitter destination data, or null if version 1 is being used or the destination is null.
+ /// </summary>
+ /// <returns>Reference for the version 2 splitter destination data.</returns>
+ public ref SplitterDestinationVersion2 GetV2RefOrNull()
+ {
+ return ref _v2;
+ }
}
}