From cee712105850ac3385cd0091a923438167433f9f Mon Sep 17 00:00:00 2001
From: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
Date: Sat, 8 Apr 2023 01:22:00 +0200
Subject: Move solution and projects to src
---
.../Renderer/Common/AuxiliaryBufferAddresses.cs | 13 ++
.../Renderer/Common/BehaviourParameter.cs | 50 +++++
src/Ryujinx.Audio/Renderer/Common/EdgeMatrix.cs | 150 ++++++++++++++
src/Ryujinx.Audio/Renderer/Common/EffectType.cs | 58 ++++++
.../Renderer/Common/MemoryPoolUserState.cs | 43 ++++
src/Ryujinx.Audio/Renderer/Common/NodeIdHelper.cs | 28 +++
src/Ryujinx.Audio/Renderer/Common/NodeIdType.cs | 33 +++
src/Ryujinx.Audio/Renderer/Common/NodeStates.cs | 229 +++++++++++++++++++++
.../Renderer/Common/PerformanceDetailType.cs | 20 ++
.../Renderer/Common/PerformanceEntryType.cs | 11 +
src/Ryujinx.Audio/Renderer/Common/PlayState.cs | 23 +++
.../Renderer/Common/ReverbEarlyMode.cs | 33 +++
.../Renderer/Common/ReverbLateMode.cs | 38 ++++
src/Ryujinx.Audio/Renderer/Common/SinkType.cs | 23 +++
.../Renderer/Common/UpdateDataHeader.cs | 33 +++
.../Renderer/Common/VoiceUpdateState.cs | 104 ++++++++++
src/Ryujinx.Audio/Renderer/Common/WaveBuffer.cs | 82 ++++++++
.../Renderer/Common/WorkBufferAllocator.cs | 61 ++++++
18 files changed, 1032 insertions(+)
create mode 100644 src/Ryujinx.Audio/Renderer/Common/AuxiliaryBufferAddresses.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/EdgeMatrix.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/EffectType.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/MemoryPoolUserState.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/NodeIdHelper.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/NodeIdType.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/NodeStates.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/PerformanceDetailType.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/PerformanceEntryType.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/PlayState.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/ReverbEarlyMode.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/ReverbLateMode.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/SinkType.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/WaveBuffer.cs
create mode 100644 src/Ryujinx.Audio/Renderer/Common/WorkBufferAllocator.cs
(limited to 'src/Ryujinx.Audio/Renderer/Common')
diff --git a/src/Ryujinx.Audio/Renderer/Common/AuxiliaryBufferAddresses.cs b/src/Ryujinx.Audio/Renderer/Common/AuxiliaryBufferAddresses.cs
new file mode 100644
index 00000000..96647405
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/AuxiliaryBufferAddresses.cs
@@ -0,0 +1,13 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct AuxiliaryBufferAddresses
+ {
+ public ulong SendBufferInfo;
+ public ulong SendBufferInfoBase;
+ public ulong ReturnBufferInfo;
+ public ulong ReturnBufferInfoBase;
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs b/src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs
new file mode 100644
index 00000000..270f84d5
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs
@@ -0,0 +1,50 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// Represents the input parameter for .
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct BehaviourParameter
+ {
+ ///
+ /// The current audio renderer revision in use.
+ ///
+ public int UserRevision;
+
+ ///
+ /// Reserved/padding.
+ ///
+ private uint _padding;
+
+ ///
+ /// The flags given controlling behaviour of the audio renderer
+ ///
+ /// See and .
+ public ulong Flags;
+
+ ///
+ /// Represents an error during .
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ErrorInfo
+ {
+ ///
+ /// The error code to report.
+ ///
+ public ResultCode ErrorCode;
+
+ ///
+ /// Reserved/padding.
+ ///
+ private uint _padding;
+
+ ///
+ /// Extra information given with the
+ ///
+ /// This is usually used to report a faulting cpu address when a mapping fail.
+ public ulong ExtraErrorInfo;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/EdgeMatrix.cs b/src/Ryujinx.Audio/Renderer/Common/EdgeMatrix.cs
new file mode 100644
index 00000000..24a9350f
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/EdgeMatrix.cs
@@ -0,0 +1,150 @@
+using Ryujinx.Audio.Renderer.Utils;
+using Ryujinx.Common;
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// Represents a adjacent matrix.
+ ///
+ /// This is used for splitter routing.
+ public class EdgeMatrix
+ {
+ ///
+ /// Backing used for node connections.
+ ///
+ private BitArray _storage;
+
+ ///
+ /// The count of nodes of the current instance.
+ ///
+ private int _nodeCount;
+
+ ///
+ /// Get the required work buffer size memory needed for the .
+ ///
+ /// The count of nodes.
+ /// The size required for the given .
+ public static int GetWorkBufferSize(int nodeCount)
+ {
+ int size = BitUtils.AlignUp(nodeCount * nodeCount, Constants.BufferAlignment);
+
+ return size / Unsafe.SizeOf();
+ }
+
+ ///
+ /// Initializes the instance with backing memory.
+ ///
+ /// The backing memory.
+ /// The count of nodes.
+ public void Initialize(Memory edgeMatrixWorkBuffer, int nodeCount)
+ {
+ Debug.Assert(edgeMatrixWorkBuffer.Length >= GetWorkBufferSize(nodeCount));
+
+ _storage = new BitArray(edgeMatrixWorkBuffer);
+
+ _nodeCount = nodeCount;
+
+ _storage.Reset();
+ }
+
+ ///
+ /// Test if the bit at the given index is set.
+ ///
+ /// A bit index.
+ /// Returns true if the bit at the given index is set
+ public bool Test(int index)
+ {
+ return _storage.Test(index);
+ }
+
+ ///
+ /// Reset all bits in the storage.
+ ///
+ public void Reset()
+ {
+ _storage.Reset();
+ }
+
+ ///
+ /// Reset the bit at the given index.
+ ///
+ /// A bit index.
+ public void Reset(int index)
+ {
+ _storage.Reset(index);
+ }
+
+ ///
+ /// Set the bit at the given index.
+ ///
+ /// A bit index.
+ public void Set(int index)
+ {
+ _storage.Set(index);
+ }
+
+ ///
+ /// Connect a given source to a given destination.
+ ///
+ /// The source index.
+ /// The destination index.
+ public void Connect(int source, int destination)
+ {
+ Debug.Assert(source < _nodeCount);
+ Debug.Assert(destination < _nodeCount);
+
+ _storage.Set(_nodeCount * source + destination);
+ }
+
+ ///
+ /// Check if the given source is connected to the given destination.
+ ///
+ /// The source index.
+ /// The destination index.
+ /// Returns true if the given source is connected to the given destination.
+ public bool Connected(int source, int destination)
+ {
+ Debug.Assert(source < _nodeCount);
+ Debug.Assert(destination < _nodeCount);
+
+ return _storage.Test(_nodeCount * source + destination);
+ }
+
+ ///
+ /// Disconnect a given source from a given destination.
+ ///
+ /// The source index.
+ /// The destination index.
+ public void Disconnect(int source, int destination)
+ {
+ Debug.Assert(source < _nodeCount);
+ Debug.Assert(destination < _nodeCount);
+
+ _storage.Reset(_nodeCount * source + destination);
+ }
+
+ ///
+ /// Remove all edges from a given source.
+ ///
+ /// The source index.
+ public void RemoveEdges(int source)
+ {
+ for (int i = 0; i < _nodeCount; i++)
+ {
+ Disconnect(source, i);
+ }
+ }
+
+ ///
+ /// Get the total node count.
+ ///
+ /// The total node count.
+ public int GetNodeCount()
+ {
+ return _nodeCount;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/EffectType.cs b/src/Ryujinx.Audio/Renderer/Common/EffectType.cs
new file mode 100644
index 00000000..7128db4c
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/EffectType.cs
@@ -0,0 +1,58 @@
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// The type of an effect.
+ ///
+ public enum EffectType : byte
+ {
+ ///
+ /// Invalid effect.
+ ///
+ Invalid,
+
+ ///
+ /// Effect applying additional mixing capability.
+ ///
+ BufferMix,
+
+ ///
+ /// Effect applying custom user effect (via auxiliary buffers).
+ ///
+ AuxiliaryBuffer,
+
+ ///
+ /// Effect applying a delay.
+ ///
+ Delay,
+
+ ///
+ /// Effect applying a reverberation effect via a given preset.
+ ///
+ Reverb,
+
+ ///
+ /// Effect applying a 3D reverberation effect via a given preset.
+ ///
+ Reverb3d,
+
+ ///
+ /// Effect applying a biquad filter.
+ ///
+ BiquadFilter,
+
+ ///
+ /// Effect applying a limiter (DRC).
+ ///
+ Limiter,
+
+ ///
+ /// Effect to capture mixes (via auxiliary buffers).
+ ///
+ CaptureBuffer,
+
+ ///
+ /// Effect applying a compressor filter (DRC).
+ ///
+ Compressor,
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/MemoryPoolUserState.cs b/src/Ryujinx.Audio/Renderer/Common/MemoryPoolUserState.cs
new file mode 100644
index 00000000..590731c3
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/MemoryPoolUserState.cs
@@ -0,0 +1,43 @@
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// Represents the state of a memory pool.
+ ///
+ public enum MemoryPoolUserState : uint
+ {
+ ///
+ /// Invalid state.
+ ///
+ Invalid = 0,
+
+ ///
+ /// The memory pool is new. (client side only)
+ ///
+ New = 1,
+
+ ///
+ /// The user asked to detach the memory pool from the .
+ ///
+ RequestDetach = 2,
+
+ ///
+ /// The memory pool is detached from the .
+ ///
+ Detached = 3,
+
+ ///
+ /// The user asked to attach the memory pool to the .
+ ///
+ RequestAttach = 4,
+
+ ///
+ /// The memory pool is attached to the .
+ ///
+ Attached = 5,
+
+ ///
+ /// The memory pool is released. (client side only)
+ ///
+ Released = 6
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/NodeIdHelper.cs b/src/Ryujinx.Audio/Renderer/Common/NodeIdHelper.cs
new file mode 100644
index 00000000..a999e3ad
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/NodeIdHelper.cs
@@ -0,0 +1,28 @@
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// Helper for manipulating node ids.
+ ///
+ public static class NodeIdHelper
+ {
+ ///
+ /// Get the type of a node from a given node id.
+ ///
+ /// Id of the node.
+ /// The type of the node.
+ public static NodeIdType GetType(int nodeId)
+ {
+ return (NodeIdType)(nodeId >> 28);
+ }
+
+ ///
+ /// Get the base of a node from a given node id.
+ ///
+ /// Id of the node.
+ /// The base of the node.
+ public static int GetBase(int nodeId)
+ {
+ return (nodeId >> 16) & 0xFFF;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/NodeIdType.cs b/src/Ryujinx.Audio/Renderer/Common/NodeIdType.cs
new file mode 100644
index 00000000..69b58f6b
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/NodeIdType.cs
@@ -0,0 +1,33 @@
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// The type of a node.
+ ///
+ public enum NodeIdType : byte
+ {
+ ///
+ /// Invalid node id.
+ ///
+ Invalid = 0,
+
+ ///
+ /// Voice related node id. (data source, biquad filter, ...)
+ ///
+ Voice = 1,
+
+ ///
+ /// Mix related node id. (mix, effects, splitters, ...)
+ ///
+ Mix = 2,
+
+ ///
+ /// Sink related node id. (device & circular buffer sink)
+ ///
+ Sink = 3,
+
+ ///
+ /// Performance monitoring related node id (performance commands)
+ ///
+ Performance = 15
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/NodeStates.cs b/src/Ryujinx.Audio/Renderer/Common/NodeStates.cs
new file mode 100644
index 00000000..45748d60
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/NodeStates.cs
@@ -0,0 +1,229 @@
+using Ryujinx.Audio.Renderer.Utils;
+using System;
+using System.Diagnostics;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ public class NodeStates
+ {
+ private class Stack
+ {
+ private Memory _storage;
+ private int _index;
+
+ private int _nodeCount;
+
+ public void Reset(Memory storage, int nodeCount)
+ {
+ Debug.Assert(storage.Length * sizeof(int) >= CalcBufferSize(nodeCount));
+
+ _storage = storage;
+ _index = 0;
+ _nodeCount = nodeCount;
+ }
+
+ public int GetCurrentCount()
+ {
+ return _index;
+ }
+
+ public void Push(int data)
+ {
+ Debug.Assert(_index + 1 <= _nodeCount);
+
+ _storage.Span[_index++] = data;
+ }
+
+ public int Pop()
+ {
+ Debug.Assert(_index > 0);
+
+ return _storage.Span[--_index];
+ }
+
+ public int Top()
+ {
+ return _storage.Span[_index - 1];
+ }
+
+ public static int CalcBufferSize(int nodeCount)
+ {
+ return nodeCount * sizeof(int);
+ }
+ }
+
+ private int _nodeCount;
+ private EdgeMatrix _discovered;
+ private EdgeMatrix _finished;
+ private Memory _resultArray;
+ private Stack _stack;
+ private int _tsortResultIndex;
+
+ private enum NodeState : byte
+ {
+ Unknown,
+ Discovered,
+ Finished
+ }
+
+ public NodeStates()
+ {
+ _stack = new Stack();
+ _discovered = new EdgeMatrix();
+ _finished = new EdgeMatrix();
+ }
+
+ public static int GetWorkBufferSize(int nodeCount)
+ {
+ return Stack.CalcBufferSize(nodeCount * nodeCount) + 0xC * nodeCount + 2 * EdgeMatrix.GetWorkBufferSize(nodeCount);
+ }
+
+ public void Initialize(Memory nodeStatesWorkBuffer, int nodeCount)
+ {
+ int workBufferSize = GetWorkBufferSize(nodeCount);
+
+ Debug.Assert(nodeStatesWorkBuffer.Length >= workBufferSize);
+
+ _nodeCount = nodeCount;
+
+ int edgeMatrixWorkBufferSize = EdgeMatrix.GetWorkBufferSize(nodeCount);
+
+ _discovered.Initialize(nodeStatesWorkBuffer.Slice(0, edgeMatrixWorkBufferSize), nodeCount);
+ _finished.Initialize(nodeStatesWorkBuffer.Slice(edgeMatrixWorkBufferSize, edgeMatrixWorkBufferSize), nodeCount);
+
+ nodeStatesWorkBuffer = nodeStatesWorkBuffer.Slice(edgeMatrixWorkBufferSize * 2);
+
+ _resultArray = SpanMemoryManager.Cast(nodeStatesWorkBuffer.Slice(0, sizeof(int) * nodeCount));
+
+ nodeStatesWorkBuffer = nodeStatesWorkBuffer.Slice(sizeof(int) * nodeCount);
+
+ Memory stackWorkBuffer = SpanMemoryManager.Cast(nodeStatesWorkBuffer.Slice(0, Stack.CalcBufferSize(nodeCount * nodeCount)));
+
+ _stack.Reset(stackWorkBuffer, nodeCount * nodeCount);
+ }
+
+ private void Reset()
+ {
+ _discovered.Reset();
+ _finished.Reset();
+ _tsortResultIndex = 0;
+ _resultArray.Span.Fill(-1);
+ }
+
+ private NodeState GetState(int index)
+ {
+ Debug.Assert(index < _nodeCount);
+
+ if (_discovered.Test(index))
+ {
+ Debug.Assert(!_finished.Test(index));
+
+ return NodeState.Discovered;
+ }
+ else if (_finished.Test(index))
+ {
+ Debug.Assert(!_discovered.Test(index));
+
+ return NodeState.Finished;
+ }
+
+ return NodeState.Unknown;
+ }
+
+ private void SetState(int index, NodeState state)
+ {
+ switch (state)
+ {
+ case NodeState.Unknown:
+ _discovered.Reset(index);
+ _finished.Reset(index);
+ break;
+ case NodeState.Discovered:
+ _discovered.Set(index);
+ _finished.Reset(index);
+ break;
+ case NodeState.Finished:
+ _finished.Set(index);
+ _discovered.Reset(index);
+ break;
+ }
+ }
+
+ private void PushTsortResult(int index)
+ {
+ Debug.Assert(index < _nodeCount);
+
+ _resultArray.Span[_tsortResultIndex++] = index;
+ }
+
+ public ReadOnlySpan GetTsortResult()
+ {
+ return _resultArray.Span.Slice(0, _tsortResultIndex);
+ }
+
+ public bool Sort(EdgeMatrix edgeMatrix)
+ {
+ Reset();
+
+ if (_nodeCount <= 0)
+ {
+ return true;
+ }
+
+ for (int i = 0; i < _nodeCount; i++)
+ {
+ if (GetState(i) == NodeState.Unknown)
+ {
+ _stack.Push(i);
+ }
+
+ while (_stack.GetCurrentCount() > 0)
+ {
+ int topIndex = _stack.Top();
+
+ NodeState topState = GetState(topIndex);
+
+ if (topState == NodeState.Discovered)
+ {
+ SetState(topIndex, NodeState.Finished);
+ PushTsortResult(topIndex);
+ _stack.Pop();
+ }
+ else if (topState == NodeState.Finished)
+ {
+ _stack.Pop();
+ }
+ else
+ {
+ if (topState == NodeState.Unknown)
+ {
+ SetState(topIndex, NodeState.Discovered);
+ }
+
+ for (int j = 0; j < edgeMatrix.GetNodeCount(); j++)
+ {
+ if (edgeMatrix.Connected(topIndex, j))
+ {
+ NodeState jState = GetState(j);
+
+ if (jState == NodeState.Unknown)
+ {
+ _stack.Push(j);
+ }
+ // Found a loop, reset and propagate rejection.
+ else if (jState == NodeState.Discovered)
+ {
+ Reset();
+
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/PerformanceDetailType.cs b/src/Ryujinx.Audio/Renderer/Common/PerformanceDetailType.cs
new file mode 100644
index 00000000..805d5518
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/PerformanceDetailType.cs
@@ -0,0 +1,20 @@
+namespace Ryujinx.Audio.Renderer.Common
+{
+ public enum PerformanceDetailType : byte
+ {
+ Unknown,
+ PcmInt16,
+ Adpcm,
+ VolumeRamp,
+ BiquadFilter,
+ Mix,
+ Delay,
+ Aux,
+ Reverb,
+ Reverb3d,
+ PcmFloat,
+ Limiter,
+ CaptureBuffer,
+ Compressor
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/PerformanceEntryType.cs b/src/Ryujinx.Audio/Renderer/Common/PerformanceEntryType.cs
new file mode 100644
index 00000000..bde72aae
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/PerformanceEntryType.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Audio.Renderer.Common
+{
+ public enum PerformanceEntryType : byte
+ {
+ Invalid,
+ Voice,
+ SubMix,
+ FinalMix,
+ Sink
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/PlayState.cs b/src/Ryujinx.Audio/Renderer/Common/PlayState.cs
new file mode 100644
index 00000000..4a6929e0
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/PlayState.cs
@@ -0,0 +1,23 @@
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// Common play state.
+ ///
+ public enum PlayState : byte
+ {
+ ///
+ /// The user request the voice to be started.
+ ///
+ Start,
+
+ ///
+ /// The user request the voice to be stopped.
+ ///
+ Stop,
+
+ ///
+ /// The user request the voice to be paused.
+ ///
+ Pause
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/ReverbEarlyMode.cs b/src/Ryujinx.Audio/Renderer/Common/ReverbEarlyMode.cs
new file mode 100644
index 00000000..aa768562
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/ReverbEarlyMode.cs
@@ -0,0 +1,33 @@
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// Early reverb reflection.
+ ///
+ public enum ReverbEarlyMode : uint
+ {
+ ///
+ /// Room early reflection. (small acoustic space, fast reflection)
+ ///
+ Room,
+
+ ///
+ /// Chamber early reflection. (bigger than 's acoustic space, short reflection)
+ ///
+ Chamber,
+
+ ///
+ /// Hall early reflection. (large acoustic space, warm reflection)
+ ///
+ Hall,
+
+ ///
+ /// Cathedral early reflection. (very large acoustic space, pronounced bright reflection)
+ ///
+ Cathedral,
+
+ ///
+ /// No early reflection.
+ ///
+ Disabled
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/ReverbLateMode.cs b/src/Ryujinx.Audio/Renderer/Common/ReverbLateMode.cs
new file mode 100644
index 00000000..8aa88165
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/ReverbLateMode.cs
@@ -0,0 +1,38 @@
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// Late reverb reflection.
+ ///
+ public enum ReverbLateMode : uint
+ {
+ ///
+ /// Room late reflection. (small acoustic space, fast reflection)
+ ///
+ Room,
+
+ ///
+ /// Hall late reflection. (large acoustic space, warm reflection)
+ ///
+ Hall,
+
+ ///
+ /// Classic plate late reflection. (clean distinctive reverb)
+ ///
+ Plate,
+
+ ///
+ /// Cathedral late reflection. (very large acoustic space, pronounced bright reflection)
+ ///
+ Cathedral,
+
+ ///
+ /// Do not apply any delay. (max delay)
+ ///
+ NoDelay,
+
+ ///
+ /// Max delay. (used for delay line limits)
+ ///
+ Limit = NoDelay
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/SinkType.cs b/src/Ryujinx.Audio/Renderer/Common/SinkType.cs
new file mode 100644
index 00000000..2e17201e
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/SinkType.cs
@@ -0,0 +1,23 @@
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// The type of a sink.
+ ///
+ public enum SinkType : byte
+ {
+ ///
+ /// The sink is in an invalid state.
+ ///
+ Invalid,
+
+ ///
+ /// The sink is a device.
+ ///
+ Device,
+
+ ///
+ /// The sink is a circular buffer.
+ ///
+ CircularBuffer
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs b/src/Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs
new file mode 100644
index 00000000..70dbfa94
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs
@@ -0,0 +1,33 @@
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// Update data header used for input and output of .
+ ///
+ public struct UpdateDataHeader
+ {
+ public int Revision;
+ public uint BehaviourSize;
+ public uint MemoryPoolsSize;
+ public uint VoicesSize;
+ public uint VoiceResourcesSize;
+ public uint EffectsSize;
+ public uint MixesSize;
+ public uint SinksSize;
+ public uint PerformanceBufferSize;
+ public uint Unknown24;
+ public uint RenderInfoSize;
+
+ private unsafe fixed int _reserved[4];
+
+ public uint TotalSize;
+
+ public void Initialize(int revision)
+ {
+ Revision = revision;
+
+ TotalSize = (uint)Unsafe.SizeOf();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs b/src/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs
new file mode 100644
index 00000000..f52c2f4c
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs
@@ -0,0 +1,104 @@
+using Ryujinx.Audio.Renderer.Dsp.State;
+using Ryujinx.Common.Memory;
+using Ryujinx.Common.Utilities;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// Represent the update state of a voice.
+ ///
+ /// This is shared between the server and audio processor.
+ [StructLayout(LayoutKind.Sequential, Pack = Align)]
+ public struct VoiceUpdateState
+ {
+ public const int Align = 0x10;
+ public const int BiquadStateOffset = 0x0;
+ public const int BiquadStateSize = 0x10;
+
+ ///
+ /// The state of the biquad filters of this voice.
+ ///
+ public Array2 BiquadFilterState;
+
+ ///
+ /// The total amount of samples that was played.
+ ///
+ /// This is reset to 0 when a finishes playing and is set.
+ /// This is reset to 0 when looping while is set.
+ public ulong PlayedSampleCount;
+
+ ///
+ /// The current sample offset in the pointed by .
+ ///
+ public int Offset;
+
+ ///
+ /// The current index of the in use.
+ ///
+ public uint WaveBufferIndex;
+
+ private WaveBufferValidArray _isWaveBufferValid;
+
+ ///
+ /// The total amount of consumed.
+ ///
+ public uint WaveBufferConsumed;
+
+ ///
+ /// Pitch used for Sample Rate Conversion.
+ ///
+ public Array8 Pitch;
+
+ public float Fraction;
+
+ ///
+ /// The ADPCM loop context when is in use.
+ ///
+ public AdpcmLoopContext LoopContext;
+
+ ///
+ /// The last samples after a mix ramp.
+ ///
+ /// This is used for depop (to perform voice drop).
+ public Array24 LastSamples;
+
+ ///
+ /// The current count of loop performed.
+ ///
+ public int LoopCount;
+
+ [StructLayout(LayoutKind.Sequential, Size = 1 * Constants.VoiceWaveBufferCount, Pack = 1)]
+ private struct WaveBufferValidArray { }
+
+ ///
+ /// Contains information of validity.
+ ///
+ public Span IsWaveBufferValid => SpanHelpers.AsSpan(ref _isWaveBufferValid);
+
+ ///
+ /// Mark the current as played and switch to the next one.
+ ///
+ /// The current
+ /// The wavebuffer index.
+ /// The amount of wavebuffers consumed.
+ /// The total count of sample played.
+ public void MarkEndOfBufferWaveBufferProcessing(ref WaveBuffer waveBuffer, ref int waveBufferIndex, ref uint waveBufferConsumed, ref ulong playedSampleCount)
+ {
+ IsWaveBufferValid[waveBufferIndex++] = false;
+ LoopCount = 0;
+ waveBufferConsumed++;
+
+ if (waveBufferIndex >= Constants.VoiceWaveBufferCount)
+ {
+ waveBufferIndex = 0;
+ }
+
+ if (waveBuffer.IsEndOfStream)
+ {
+ playedSampleCount = 0;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/WaveBuffer.cs b/src/Ryujinx.Audio/Renderer/Common/WaveBuffer.cs
new file mode 100644
index 00000000..0d00e838
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/WaveBuffer.cs
@@ -0,0 +1,82 @@
+using System.Runtime.InteropServices;
+
+using DspAddr = System.UInt64;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ ///
+ /// A wavebuffer used for data source commands.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct WaveBuffer
+ {
+ ///
+ /// The DSP address of the sample data of the wavebuffer.
+ ///
+ public DspAddr Buffer;
+
+ ///
+ /// The DSP address of the context of the wavebuffer.
+ ///
+ /// Only used by .
+ public DspAddr Context;
+
+ ///
+ /// The size of the sample buffer data.
+ ///
+ public uint BufferSize;
+
+ ///
+ /// The size of the context buffer.
+ ///
+ public uint ContextSize;
+
+ ///
+ /// First sample to play on the wavebuffer.
+ ///
+ public uint StartSampleOffset;
+
+ ///
+ /// Last sample to play on the wavebuffer.
+ ///
+ public uint EndSampleOffset;
+
+ ///
+ /// First sample to play when looping the wavebuffer.
+ ///
+ ///
+ /// If or is equal to zero,, it will default to and .
+ ///
+ public uint LoopStartSampleOffset;
+
+ ///
+ /// Last sample to play when looping the wavebuffer.
+ ///
+ ///
+ /// If or is equal to zero, it will default to and .
+ ///
+ public uint LoopEndSampleOffset;
+
+ ///
+ /// The max loop count.
+ ///
+ public int LoopCount;
+
+ ///
+ /// Set to true if the wavebuffer is looping.
+ ///
+ [MarshalAs(UnmanagedType.I1)]
+ public bool Looping;
+
+ ///
+ /// Set to true if the wavebuffer is the end of stream.
+ ///
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsEndOfStream;
+
+ ///
+ /// Padding/Reserved.
+ ///
+ private ushort _padding;
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Audio/Renderer/Common/WorkBufferAllocator.cs b/src/Ryujinx.Audio/Renderer/Common/WorkBufferAllocator.cs
new file mode 100644
index 00000000..f35dbec7
--- /dev/null
+++ b/src/Ryujinx.Audio/Renderer/Common/WorkBufferAllocator.cs
@@ -0,0 +1,61 @@
+using Ryujinx.Audio.Renderer.Utils;
+using Ryujinx.Common;
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ public class WorkBufferAllocator
+ {
+ public Memory BackingMemory { get; }
+
+ public ulong Offset { get; private set; }
+
+ public WorkBufferAllocator(Memory backingMemory)
+ {
+ BackingMemory = backingMemory;
+ }
+
+ public Memory Allocate(ulong size, int align)
+ {
+ Debug.Assert(align != 0);
+
+ if (size != 0)
+ {
+ ulong alignedOffset = BitUtils.AlignUp(Offset, (ulong)align);
+
+ if (alignedOffset + size <= (ulong)BackingMemory.Length)
+ {
+ Memory result = BackingMemory.Slice((int)alignedOffset, (int)size);
+
+ Offset = alignedOffset + size;
+
+ // Clear the memory to be sure that is does not contain any garbage.
+ result.Span.Fill(0);
+
+ return result;
+ }
+ }
+
+ return Memory.Empty;
+ }
+
+ public Memory Allocate(ulong count, int align) where T : unmanaged
+ {
+ Memory allocatedMemory = Allocate((ulong)Unsafe.SizeOf() * count, align);
+
+ if (allocatedMemory.IsEmpty)
+ {
+ return Memory.Empty;
+ }
+
+ return SpanMemoryManager.Cast(allocatedMemory);
+ }
+
+ public static ulong GetTargetSize(ulong currentSize, ulong count, int align) where T : unmanaged
+ {
+ return BitUtils.AlignUp(currentSize, (ulong)align) + (ulong)Unsafe.SizeOf() * count;
+ }
+ }
+}
\ No newline at end of file
--
cgit v1.2.3