diff options
Diffstat (limited to 'Ryujinx.Audio.Renderer')
159 files changed, 0 insertions, 21652 deletions
diff --git a/Ryujinx.Audio.Renderer/Common/AuxiliaryBufferAddresses.cs b/Ryujinx.Audio.Renderer/Common/AuxiliaryBufferAddresses.cs deleted file mode 100644 index 5d826569..00000000 --- a/Ryujinx.Audio.Renderer/Common/AuxiliaryBufferAddresses.cs +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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; - } -} diff --git a/Ryujinx.Audio.Renderer/Common/BehaviourParameter.cs b/Ryujinx.Audio.Renderer/Common/BehaviourParameter.cs deleted file mode 100644 index 0de3d571..00000000 --- a/Ryujinx.Audio.Renderer/Common/BehaviourParameter.cs +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// Represents the input parameter for <see cref="Server.BehaviourContext"/>. - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct BehaviourParameter - { - /// <summary> - /// The current audio renderer revision in use. - /// </summary> - public int UserRevision; - - /// <summary> - /// Reserved/padding. - /// </summary> - private uint _padding; - - /// <summary> - /// The flags given controlling behaviour of the audio renderer - /// </summary> - /// <remarks>See <see cref="Server.BehaviourContext.UpdateFlags(ulong)"/> and <see cref="Server.BehaviourContext.IsMemoryPoolForceMappingEnabled"/>.</remarks> - public ulong Flags; - - /// <summary> - /// Represents an error during <see cref="Server.AudioRenderSystem.Update(System.Memory{byte}, System.Memory{byte}, System.ReadOnlyMemory{byte})"/>. - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct ErrorInfo - { - /// <summary> - /// The error code to report. - /// </summary> - public ResultCode ErrorCode; - - /// <summary> - /// Reserved/padding. - /// </summary> - private uint _padding; - - /// <summary> - /// Extra information given with the <see cref="ResultCode"/> - /// </summary> - /// <remarks>This is usually used to report a faulting cpu address when a <see cref="Server.MemoryPool.MemoryPoolState"/> mapping fail.</remarks> - public ulong ExtraErrorInfo; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Common/EdgeMatrix.cs b/Ryujinx.Audio.Renderer/Common/EdgeMatrix.cs deleted file mode 100644 index 33b61780..00000000 --- a/Ryujinx.Audio.Renderer/Common/EdgeMatrix.cs +++ /dev/null @@ -1,167 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Utils; -using Ryujinx.Common; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// Represents a adjacent matrix. - /// </summary> - /// <remarks>This is used for splitter routing.</remarks> - public class EdgeMatrix - { - /// <summary> - /// Backing <see cref="BitArray"/> used for node connections. - /// </summary> - private BitArray _storage; - - /// <summary> - /// The count of nodes of the current instance. - /// </summary> - private int _nodeCount; - - /// <summary> - /// Get the required work buffer size memory needed for the <see cref="EdgeMatrix"/>. - /// </summary> - /// <param name="nodeCount">The count of nodes.</param> - /// <returns>The size required for the given <paramref name="nodeCount"/>.</returns> - public static int GetWorkBufferSize(int nodeCount) - { - int size = BitUtils.AlignUp(nodeCount * nodeCount, RendererConstants.BufferAlignment); - - return size / Unsafe.SizeOf<byte>(); - } - - /// <summary> - /// Initializes the <see cref="EdgeMatrix"/> instance with backing memory. - /// </summary> - /// <param name="edgeMatrixWorkBuffer">The backing memory.</param> - /// <param name="nodeCount">The count of nodes.</param> - public void Initialize(Memory<byte> edgeMatrixWorkBuffer, int nodeCount) - { - Debug.Assert(edgeMatrixWorkBuffer.Length >= GetWorkBufferSize(nodeCount)); - - _storage = new BitArray(edgeMatrixWorkBuffer); - - _nodeCount = nodeCount; - - _storage.Reset(); - } - - /// <summary> - /// Test if the bit at the given index is set. - /// </summary> - /// <param name="index">A bit index.</param> - /// <returns>Returns true if the bit at the given index is set</returns> - public bool Test(int index) - { - return _storage.Test(index); - } - - /// <summary> - /// Reset all bits in the storage. - /// </summary> - public void Reset() - { - _storage.Reset(); - } - - /// <summary> - /// Reset the bit at the given index. - /// </summary> - /// <param name="index">A bit index.</param> - public void Reset(int index) - { - _storage.Reset(index); - } - - /// <summary> - /// Set the bit at the given index. - /// </summary> - /// <param name="index">A bit index.</param> - public void Set(int index) - { - _storage.Set(index); - } - - /// <summary> - /// Connect a given source to a given destination. - /// </summary> - /// <param name="source">The source index.</param> - /// <param name="destination">The destination index.</param> - public void Connect(int source, int destination) - { - Debug.Assert(source < _nodeCount); - Debug.Assert(destination < _nodeCount); - - _storage.Set(_nodeCount * source + destination); - } - - /// <summary> - /// Check if the given source is connected to the given destination. - /// </summary> - /// <param name="source">The source index.</param> - /// <param name="destination">The destination index.</param> - /// <returns>Returns true if the given source is connected to the given destination.</returns> - public bool Connected(int source, int destination) - { - Debug.Assert(source < _nodeCount); - Debug.Assert(destination < _nodeCount); - - return _storage.Test(_nodeCount * source + destination); - } - - /// <summary> - /// Disconnect a given source from a given destination. - /// </summary> - /// <param name="source">The source index.</param> - /// <param name="destination">The destination index.</param> - public void Disconnect(int source, int destination) - { - Debug.Assert(source < _nodeCount); - Debug.Assert(destination < _nodeCount); - - _storage.Reset(_nodeCount * source + destination); - } - - /// <summary> - /// Remove all edges from a given source. - /// </summary> - /// <param name="source">The source index.</param> - public void RemoveEdges(int source) - { - for (int i = 0; i < _nodeCount; i++) - { - Disconnect(source, i); - } - } - - /// <summary> - /// Get the total node count. - /// </summary> - /// <returns>The total node count.</returns> - public int GetNodeCount() - { - return _nodeCount; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Common/EffectType.cs b/Ryujinx.Audio.Renderer/Common/EffectType.cs deleted file mode 100644 index 082f94f8..00000000 --- a/Ryujinx.Audio.Renderer/Common/EffectType.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// The type of an effect. - /// </summary> - public enum EffectType : byte - { - /// <summary> - /// Invalid effect. - /// </summary> - Invalid, - - /// <summary> - /// Effect applying additional mixing capability. - /// </summary> - BufferMix, - - /// <summary> - /// Effect applying custom user effect (via auxiliary buffers). - /// </summary> - AuxiliaryBuffer, - - /// <summary> - /// Effect applying a delay. - /// </summary> - Delay, - - /// <summary> - /// Effect applying a reverberation effect via a given preset. - /// </summary> - Reverb, - - /// <summary> - /// Effect applying a 3D reverberation effect via a given preset. - /// </summary> - Reverb3d, - - /// <summary> - /// Effect applying a biquad filter. - /// </summary> - BiquadFilter - } -} diff --git a/Ryujinx.Audio.Renderer/Common/MemoryPoolUserState.cs b/Ryujinx.Audio.Renderer/Common/MemoryPoolUserState.cs deleted file mode 100644 index 7f9765d9..00000000 --- a/Ryujinx.Audio.Renderer/Common/MemoryPoolUserState.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// Represents the state of a memory pool. - /// </summary> - public enum MemoryPoolUserState : uint - { - /// <summary> - /// Invalid state. - /// </summary> - Invalid = 0, - - /// <summary> - /// The memory pool is new. (client side only) - /// </summary> - New = 1, - - /// <summary> - /// The user asked to detach the memory pool from the <see cref="Dsp.AudioProcessor"/>. - /// </summary> - RequestDetach = 2, - - /// <summary> - /// The memory pool is detached from the <see cref="Dsp.AudioProcessor"/>. - /// </summary> - Detached = 3, - - /// <summary> - /// The user asked to attach the memory pool to the <see cref="Dsp.AudioProcessor"/>. - /// </summary> - RequestAttach = 4, - - /// <summary> - /// The memory pool is attached to the <see cref="Dsp.AudioProcessor"/>. - /// </summary> - Attached = 5, - - /// <summary> - /// The memory pool is released. (client side only) - /// </summary> - Released = 6 - } -} diff --git a/Ryujinx.Audio.Renderer/Common/NodeIdHelper.cs b/Ryujinx.Audio.Renderer/Common/NodeIdHelper.cs deleted file mode 100644 index 9bf1f2d0..00000000 --- a/Ryujinx.Audio.Renderer/Common/NodeIdHelper.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// Helper for manipulating node ids. - /// </summary> - public static class NodeIdHelper - { - /// <summary> - /// Get the type of a node from a given node id. - /// </summary> - /// <param name="nodeId">Id of the node.</param> - /// <returns>The type of the node.</returns> - public static NodeIdType GetType(int nodeId) - { - return (NodeIdType)(nodeId >> 28); - } - - /// <summary> - /// Get the base of a node from a given node id. - /// </summary> - /// <param name="nodeId">Id of the node.</param> - /// <returns>The base of the node.</returns> - public static int GetBase(int nodeId) - { - return (nodeId >> 16) & 0xFFF; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Common/NodeIdType.cs b/Ryujinx.Audio.Renderer/Common/NodeIdType.cs deleted file mode 100644 index 4a4796a9..00000000 --- a/Ryujinx.Audio.Renderer/Common/NodeIdType.cs +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// The type of a node. - /// </summary> - public enum NodeIdType : byte - { - /// <summary> - /// Invalid node id. - /// </summary> - Invalid = 0, - - /// <summary> - /// Voice related node id. (data source, biquad filter, ...) - /// </summary> - Voice = 1, - - /// <summary> - /// Mix related node id. (mix, effects, splitters, ...) - /// </summary> - Mix = 2, - - /// <summary> - /// Sink related node id. (device & circular buffer sink) - /// </summary> - Sink = 3, - - /// <summary> - /// Performance monitoring related node id (performance commands) - /// </summary> - Performance = 15 - } -} diff --git a/Ryujinx.Audio.Renderer/Common/NodeStates.cs b/Ryujinx.Audio.Renderer/Common/NodeStates.cs deleted file mode 100644 index 5efd7767..00000000 --- a/Ryujinx.Audio.Renderer/Common/NodeStates.cs +++ /dev/null @@ -1,246 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Utils; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Common -{ - public class NodeStates - { - private class Stack - { - private Memory<int> _storage; - private int _index; - - private int _nodeCount; - - public void Reset(Memory<int> 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<int> _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<byte> 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<int>.Cast(nodeStatesWorkBuffer.Slice(0, sizeof(int) * nodeCount)); - - nodeStatesWorkBuffer = nodeStatesWorkBuffer.Slice(sizeof(int) * nodeCount); - - Memory<int> stackWorkBuffer = SpanMemoryManager<int>.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<int> 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; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Common/PerformanceDetailType.cs b/Ryujinx.Audio.Renderer/Common/PerformanceDetailType.cs deleted file mode 100644 index a92bd0cc..00000000 --- a/Ryujinx.Audio.Renderer/Common/PerformanceDetailType.cs +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Common -{ - public enum PerformanceDetailType : byte - { - Unknown, - PcmInt16, - Adpcm, - VolumeRamp, - BiquadFilter, - Mix, - Delay, - Aux, - Reverb, - Reverb3d, - PcmFloat - } -} diff --git a/Ryujinx.Audio.Renderer/Common/PerformanceEntryType.cs b/Ryujinx.Audio.Renderer/Common/PerformanceEntryType.cs deleted file mode 100644 index 0d9a547d..00000000 --- a/Ryujinx.Audio.Renderer/Common/PerformanceEntryType.cs +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Common -{ - public enum PerformanceEntryType : byte - { - Invalid, - Voice, - SubMix, - FinalMix, - Sink - } -} diff --git a/Ryujinx.Audio.Renderer/Common/PlayState.cs b/Ryujinx.Audio.Renderer/Common/PlayState.cs deleted file mode 100644 index 7771c154..00000000 --- a/Ryujinx.Audio.Renderer/Common/PlayState.cs +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// Common play state. - /// </summary> - public enum PlayState : byte - { - /// <summary> - /// The user request the voice to be started. - /// </summary> - Start, - - /// <summary> - /// The user request the voice to be stopped. - /// </summary> - Stop, - - /// <summary> - /// The user request the voice to be paused. - /// </summary> - Pause - } -} diff --git a/Ryujinx.Audio.Renderer/Common/ReverbEarlyMode.cs b/Ryujinx.Audio.Renderer/Common/ReverbEarlyMode.cs deleted file mode 100644 index a0f65e5e..00000000 --- a/Ryujinx.Audio.Renderer/Common/ReverbEarlyMode.cs +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// Early reverb reflection. - /// </summary> - public enum ReverbEarlyMode : uint - { - /// <summary> - /// Room early reflection. (small acoustic space, fast reflection) - /// </summary> - Room, - - /// <summary> - /// Chamber early reflection. (bigger than <see cref="Room"/>'s acoustic space, short reflection) - /// </summary> - Chamber, - - /// <summary> - /// Hall early reflection. (large acoustic space, warm reflection) - /// </summary> - Hall, - - /// <summary> - /// Cathedral early reflection. (very large acoustic space, pronounced bright reflection) - /// </summary> - Cathedral, - - /// <summary> - /// No early reflection. - /// </summary> - Disabled - } -} diff --git a/Ryujinx.Audio.Renderer/Common/ReverbLateMode.cs b/Ryujinx.Audio.Renderer/Common/ReverbLateMode.cs deleted file mode 100644 index 57760821..00000000 --- a/Ryujinx.Audio.Renderer/Common/ReverbLateMode.cs +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// Late reverb reflection. - /// </summary> - public enum ReverbLateMode : uint - { - /// <summary> - /// Room late reflection. (small acoustic space, fast reflection) - /// </summary> - Room, - - /// <summary> - /// Hall late reflection. (large acoustic space, warm reflection) - /// </summary> - Hall, - - /// <summary> - /// Classic plate late reflection. (clean distinctive reverb) - /// </summary> - Plate, - - /// <summary> - /// Cathedral late reflection. (very large acoustic space, pronounced bright reflection) - /// </summary> - Cathedral, - - /// <summary> - /// Do not apply any delay. (max delay) - /// </summary> - NoDelay, - - /// <summary> - /// Max delay. (used for delay line limits) - /// </summary> - Limit = NoDelay - } -} diff --git a/Ryujinx.Audio.Renderer/Common/SampleFormat.cs b/Ryujinx.Audio.Renderer/Common/SampleFormat.cs deleted file mode 100644 index b5268408..00000000 --- a/Ryujinx.Audio.Renderer/Common/SampleFormat.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// Sample format definition. - /// </summary> - public enum SampleFormat : byte - { - /// <summary> - /// Invalid sample format. - /// </summary> - Invalid = 0, - - /// <summary> - /// PCM8 sample format. (unsupported) - /// </summary> - PcmInt8 = 1, - - /// <summary> - /// PCM16 sample format. - /// </summary> - PcmInt16 = 2, - - /// <summary> - /// PCM24 sample format. (unsupported) - /// </summary> - PcmInt24 = 3, - - /// <summary> - /// PCM32 sample format. - /// </summary> - PcmInt32 = 4, - - /// <summary> - /// PCM Float sample format. - /// </summary> - PcmFloat = 5, - - /// <summary> - /// ADPCM sample format. (Also known as GC-ADPCM) - /// </summary> - Adpcm = 6 - } -} diff --git a/Ryujinx.Audio.Renderer/Common/SinkType.cs b/Ryujinx.Audio.Renderer/Common/SinkType.cs deleted file mode 100644 index e1a35508..00000000 --- a/Ryujinx.Audio.Renderer/Common/SinkType.cs +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// The type of a sink. - /// </summary> - public enum SinkType : byte - { - /// <summary> - /// The sink is in an invalid state. - /// </summary> - Invalid, - - /// <summary> - /// The sink is a device. - /// </summary> - Device, - - /// <summary> - /// The sink is a circular buffer. - /// </summary> - CircularBuffer - } -} diff --git a/Ryujinx.Audio.Renderer/Common/UpdateDataHeader.cs b/Ryujinx.Audio.Renderer/Common/UpdateDataHeader.cs deleted file mode 100644 index ae516662..00000000 --- a/Ryujinx.Audio.Renderer/Common/UpdateDataHeader.cs +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// Update data header used for input and output of <see cref="Server.AudioRenderSystem.Update(System.Memory{byte}, System.Memory{byte}, System.ReadOnlyMemory{byte})"/>. - /// </summary> - 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<UpdateDataHeader>(); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Common/VoiceUpdateState.cs b/Ryujinx.Audio.Renderer/Common/VoiceUpdateState.cs deleted file mode 100644 index b455ff5c..00000000 --- a/Ryujinx.Audio.Renderer/Common/VoiceUpdateState.cs +++ /dev/null @@ -1,121 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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 -{ - /// <summary> - /// Represent the update state of a voice. - /// </summary> - /// <remarks>This is shared between the server and audio processor.</remarks> - [StructLayout(LayoutKind.Sequential, Pack = Align)] - public struct VoiceUpdateState - { - public const int Align = 0x10; - public const int BiquadStateOffset = 0x0; - public const int BiquadStateSize = 0x10; - - /// <summary> - /// The state of the biquad filters of this voice. - /// </summary> - public Array2<BiquadFilterState> BiquadFilterState; - - /// <summary> - /// The total amount of samples that was played. - /// </summary> - /// <remarks>This is reset to 0 when a <see cref="WaveBuffer"/> finishes playing and <see cref="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 current sample offset in the <see cref="WaveBuffer"/> pointed by <see cref="WaveBufferIndex"/>. - /// </summary> - public int Offset; - - /// <summary> - /// The current index of the <see cref="WaveBuffer"/> in use. - /// </summary> - public uint WaveBufferIndex; - - private WaveBufferValidArray _isWaveBufferValid; - - /// <summary> - /// The total amount of <see cref="WaveBuffer"/> consumed. - /// </summary> - public uint WaveBufferConsumed; - - /// <summary> - /// Pitch used for Sample Rate Conversion. - /// </summary> - public Array8<short> Pitch; - - public float Fraction; - - /// <summary> - /// The ADPCM loop context when <see cref="SampleFormat.Adpcm"/> is in use. - /// </summary> - public AdpcmLoopContext LoopContext; - - /// <summary> - /// The last samples after a mix ramp. - /// </summary> - /// <remarks>This is used for depop (to perform voice drop).</remarks> - public Array24<float> LastSamples; - - /// <summary> - /// The current count of loop performed. - /// </summary> - public int LoopCount; - - [StructLayout(LayoutKind.Sequential, Size = 1 * RendererConstants.VoiceWaveBufferCount, Pack = 1)] - private struct WaveBufferValidArray { } - - /// <summary> - /// Contains information of <see cref="WaveBuffer"/> validity. - /// </summary> - public Span<bool> IsWaveBufferValid => SpanHelpers.AsSpan<WaveBufferValidArray, bool>(ref _isWaveBufferValid); - - /// <summary> - /// Mark the current <see cref="WaveBuffer"/> as played and switch to the next one. - /// </summary> - /// <param name="waveBuffer">The current <see cref="WaveBuffer"/></param> - /// <param name="waveBufferIndex">The wavebuffer index.</param> - /// <param name="waveBufferConsumed">The amount of wavebuffers consumed.</param> - /// <param name="playedSampleCount">The total count of sample played.</param> - public void MarkEndOfBufferWaveBufferProcessing(ref WaveBuffer waveBuffer, ref int waveBufferIndex, ref uint waveBufferConsumed, ref ulong playedSampleCount) - { - IsWaveBufferValid[waveBufferIndex++] = false; - LoopCount = 0; - waveBufferConsumed++; - - if (waveBufferIndex >= RendererConstants.VoiceWaveBufferCount) - { - waveBufferIndex = 0; - } - - if (waveBuffer.IsEndOfStream) - { - playedSampleCount = 0; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Common/WaveBuffer.cs b/Ryujinx.Audio.Renderer/Common/WaveBuffer.cs deleted file mode 100644 index 53906c0c..00000000 --- a/Ryujinx.Audio.Renderer/Common/WaveBuffer.cs +++ /dev/null @@ -1,99 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Runtime.InteropServices; - -using DspAddr = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Common -{ - /// <summary> - /// A wavebuffer used for data source commands. - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct WaveBuffer - { - /// <summary> - /// The DSP address of the sample data of the wavebuffer. - /// </summary> - public DspAddr Buffer; - - /// <summary> - /// The DSP address of the context of the wavebuffer. - /// </summary> - /// <remarks>Only used by <see cref="SampleFormat.Adpcm"/>.</remarks> - public DspAddr Context; - - /// <summary> - /// The size of the sample buffer data. - /// </summary> - public uint BufferSize; - - /// <summary> - /// The size of the context buffer. - /// </summary> - public uint ContextSize; - - /// <summary> - /// First sample to play on the wavebuffer. - /// </summary> - public uint StartSampleOffset; - - /// <summary> - /// Last sample to play on the wavebuffer. - /// </summary> - public uint EndSampleOffset; - - /// <summary> - /// First sample to play when looping the wavebuffer. - /// </summary> - /// <remarks> - /// If <see cref="LoopStartSampleOffset"/> or <see cref="LoopEndSampleOffset"/> is equal to zero,, it will default to <see cref="StartSampleOffset"/> and <see cref="EndSampleOffset"/>. - /// </remarks> - public uint LoopStartSampleOffset; - - /// <summary> - /// Last sample to play when looping the wavebuffer. - /// </summary> - /// <remarks> - /// If <see cref="LoopStartSampleOffset"/> or <see cref="LoopEndSampleOffset"/> is equal to zero, it will default to <see cref="StartSampleOffset"/> and <see cref="EndSampleOffset"/>. - /// </remarks> - public uint LoopEndSampleOffset; - - /// <summary> - /// The max loop count. - /// </summary> - public int LoopCount; - - /// <summary> - /// Set to true if the wavebuffer is looping. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool Looping; - - /// <summary> - /// Set to true if the wavebuffer is the end of stream. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool IsEndOfStream; - - /// <summary> - /// Padding/Reserved. - /// </summary> - private ushort _padding; - } -} diff --git a/Ryujinx.Audio.Renderer/Common/WorkBufferAllocator.cs b/Ryujinx.Audio.Renderer/Common/WorkBufferAllocator.cs deleted file mode 100644 index 2aff4eb0..00000000 --- a/Ryujinx.Audio.Renderer/Common/WorkBufferAllocator.cs +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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<byte> BackingMemory { get; } - - public ulong Offset { get; private set; } - - public WorkBufferAllocator(Memory<byte> backingMemory) - { - BackingMemory = backingMemory; - } - - public Memory<byte> Allocate(ulong size, int align) - { - Debug.Assert(align != 0); - - if (size != 0) - { - ulong alignedOffset = BitUtils.AlignUp(Offset, align); - - if (alignedOffset + size <= (ulong)BackingMemory.Length) - { - Memory<byte> 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<byte>.Empty; - } - - public Memory<T> Allocate<T>(ulong count, int align) where T: unmanaged - { - Memory<byte> allocatedMemory = Allocate((ulong)Unsafe.SizeOf<T>() * count, align); - - if (allocatedMemory.IsEmpty) - { - return Memory<T>.Empty; - } - - return SpanMemoryManager<T>.Cast(allocatedMemory); - } - - public static ulong GetTargetSize<T>(ulong currentSize, ulong count, int align) where T: unmanaged - { - return BitUtils.AlignUp(currentSize, align) + (ulong)Unsafe.SizeOf<T>() * count; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Device/VirtualDevice.cs b/Ryujinx.Audio.Renderer/Device/VirtualDevice.cs deleted file mode 100644 index 29395e5c..00000000 --- a/Ryujinx.Audio.Renderer/Device/VirtualDevice.cs +++ /dev/null @@ -1,84 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Device -{ - /// <summary> - /// Represents a virtual device used by IAudioDevice. - /// </summary> - public class VirtualDevice - { - /// <summary> - /// All the defined virtual devices. - /// </summary> - public static readonly VirtualDevice[] Devices = new VirtualDevice[4] - { - new VirtualDevice("AudioStereoJackOutput", 2), - new VirtualDevice("AudioBuiltInSpeakerOutput", 2), - new VirtualDevice("AudioTvOutput", 6), - new VirtualDevice("AudioUsbDeviceOutput", 2), - }; - - /// <summary> - /// The name of the <see cref="VirtualDevice"/>. - /// </summary> - public string Name { get; } - - /// <summary> - /// The count of channels supported by the <see cref="VirtualDevice"/>. - /// </summary> - public uint ChannelCount { get; } - - /// <summary> - /// The system master volume of the <see cref="VirtualDevice"/>. - /// </summary> - public float MasterVolume { get; private set; } - - /// <summary> - /// Create a new <see cref="VirtualDevice"/> instance. - /// </summary> - /// <param name="name">The name of the <see cref="VirtualDevice"/>.</param> - /// <param name="channelCount">The count of channels supported by the <see cref="VirtualDevice"/>.</param> - private VirtualDevice(string name, uint channelCount) - { - Name = name; - ChannelCount = channelCount; - } - - /// <summary> - /// Update the master volume of the <see cref="VirtualDevice"/>. - /// </summary> - /// <param name="volume">The new master volume.</param> - public void UpdateMasterVolume(float volume) - { - Debug.Assert(volume >= 0.0f && volume <= 1.0f); - - MasterVolume = volume; - } - - /// <summary> - /// Check if the <see cref="VirtualDevice"/> is a usb device. - /// </summary> - /// <returns>Returns true if the <see cref="VirtualDevice"/> is a usb device.</returns> - public bool IsUsbDevice() - { - return Name.Equals("AudioUsbDeviceOutput"); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Device/VirtualDeviceSession.cs b/Ryujinx.Audio.Renderer/Device/VirtualDeviceSession.cs deleted file mode 100644 index b2669418..00000000 --- a/Ryujinx.Audio.Renderer/Device/VirtualDeviceSession.cs +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Device -{ - /// <summary> - /// Represents a virtual device session used by IAudioDevice. - /// </summary> - public class VirtualDeviceSession - { - /// <summary> - /// The <see cref="VirtualDevice"/> associated to this session. - /// </summary> - public VirtualDevice Device { get; } - - /// <summary> - /// The user volume of this session. - /// </summary> - public float Volume { get; set; } - - /// <summary> - /// Create a new <see cref="VirtualDeviceSession"/> instance. - /// </summary> - /// <param name="virtualDevice">The <see cref="VirtualDevice"/> associated to this session.</param> - public VirtualDeviceSession(VirtualDevice virtualDevice) - { - Device = virtualDevice; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Device/VirtualDeviceSessionRegistry.cs b/Ryujinx.Audio.Renderer/Device/VirtualDeviceSessionRegistry.cs deleted file mode 100644 index ed6806b2..00000000 --- a/Ryujinx.Audio.Renderer/Device/VirtualDeviceSessionRegistry.cs +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Collections.Generic; - -namespace Ryujinx.Audio.Renderer.Device -{ - /// <summary> - /// Represent an instance containing a registry of <see cref="VirtualDeviceSession"/>. - /// </summary> - public class VirtualDeviceSessionRegistry - { - /// <summary> - /// The session registry, used to store the sessions of a given AppletResourceId. - /// </summary> - private Dictionary<ulong, VirtualDeviceSession[]> _sessionsRegistry = new Dictionary<ulong, VirtualDeviceSession[]>(); - - /// <summary> - /// The default <see cref="VirtualDevice"/>. - /// </summary> - /// <remarks>This is used when the USB device is the default one on older revision.</remarks> - public VirtualDevice DefaultDevice => VirtualDevice.Devices[0]; - - /// <summary> - /// The current active <see cref="VirtualDevice"/>. - /// </summary> - // TODO: make this configurable - public VirtualDevice ActiveDevice = VirtualDevice.Devices[1]; - - /// <summary> - /// Get the associated <see cref="T:VirtualDeviceSession[]"/> from an AppletResourceId. - /// </summary> - /// <param name="resourceAppletId">The AppletResourceId used.</param> - /// <returns>The associated <see cref="T:VirtualDeviceSession[]"/> from an AppletResourceId.</returns> - public VirtualDeviceSession[] GetSessionByAppletResourceId(ulong resourceAppletId) - { - if (_sessionsRegistry.TryGetValue(resourceAppletId, out VirtualDeviceSession[] result)) - { - return result; - } - - result = CreateSessionsFromBehaviourContext(); - - _sessionsRegistry.Add(resourceAppletId, result); - - return result; - } - - /// <summary> - /// Create a new array of sessions for each <see cref="VirtualDevice"/>. - /// </summary> - /// <returns>A new array of sessions for each <see cref="VirtualDevice"/>.</returns> - private static VirtualDeviceSession[] CreateSessionsFromBehaviourContext() - { - VirtualDeviceSession[] virtualDeviceSession = new VirtualDeviceSession[VirtualDevice.Devices.Length]; - - for (int i = 0; i < virtualDeviceSession.Length; i++) - { - virtualDeviceSession[i] = new VirtualDeviceSession(VirtualDevice.Devices[i]); - } - - return virtualDeviceSession; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/AdpcmHelper.cs b/Ryujinx.Audio.Renderer/Dsp/AdpcmHelper.cs deleted file mode 100644 index f9f0811d..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/AdpcmHelper.cs +++ /dev/null @@ -1,219 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp.State; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Dsp -{ - public static class AdpcmHelper - { - private const int FixedPointPrecision = 11; - private const int SamplesPerFrame = 14; - private const int NibblesPerFrame = SamplesPerFrame + 2; - private const int BytesPerFrame = 8; - private const int BitsPerFrame = BytesPerFrame * 8; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint GetAdpcmDataSize(int sampleCount) - { - Debug.Assert(sampleCount >= 0); - - int frames = sampleCount / SamplesPerFrame; - int extraSize = 0; - - if ((sampleCount % SamplesPerFrame) != 0) - { - extraSize = (sampleCount % SamplesPerFrame) / 2 + 1 + (sampleCount % 2); - } - - return (uint)(BytesPerFrame * frames + extraSize); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetAdpcmOffsetFromSampleOffset(int sampleOffset) - { - Debug.Assert(sampleOffset >= 0); - - return GetNibblesFromSampleCount(sampleOffset) / 2; - } - - public static int NibbleToSample(int nibble) - { - int frames = nibble / NibblesPerFrame; - int extraNibbles = nibble % NibblesPerFrame; - int samples = SamplesPerFrame * frames; - - return samples + extraNibbles - 2; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetNibblesFromSampleCount(int sampleCount) - { - byte headerSize = 0; - - if ((sampleCount % SamplesPerFrame) != 0) - { - headerSize = 2; - } - - return sampleCount % SamplesPerFrame + NibblesPerFrame * (sampleCount / SamplesPerFrame) + headerSize; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static short Saturate(int value) - { - if (value > short.MaxValue) - value = short.MaxValue; - - if (value < short.MinValue) - value = short.MinValue; - - return (short)value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Decode(Span<short> output, ReadOnlySpan<byte> input, int startSampleOffset, int endSampleOffset, int offset, int count, ReadOnlySpan<short> coefficients, ref AdpcmLoopContext loopContext) - { - if (input.IsEmpty || endSampleOffset < startSampleOffset) - { - return 0; - } - - byte predScale = (byte)loopContext.PredScale; - byte scale = (byte)(predScale & 0xF); - byte coefficientIndex = (byte)((predScale >> 4) & 0xF); - short history0 = loopContext.History0; - short history1 = loopContext.History1; - short coefficient0 = coefficients[coefficientIndex * 2 + 0]; - short coefficient1 = coefficients[coefficientIndex * 2 + 1]; - - int decodedCount = Math.Min(count, endSampleOffset - startSampleOffset - offset); - int nibbles = GetNibblesFromSampleCount(offset + startSampleOffset); - int remaining = decodedCount; - int outputBufferIndex = 0; - int inputIndex = 0; - - ReadOnlySpan<byte> targetInput; - - targetInput = input.Slice(nibbles / 2); - - while (remaining > 0) - { - int samplesCount; - - if (((uint)nibbles % NibblesPerFrame) == 0) - { - predScale = targetInput[inputIndex++]; - - scale = (byte)(predScale & 0xF); - - coefficientIndex = (byte)((predScale >> 4) & 0xF); - - coefficient0 = coefficients[coefficientIndex * 2 + 0]; - coefficient1 = coefficients[coefficientIndex * 2 + 1]; - - nibbles += 2; - - samplesCount = Math.Min(remaining, SamplesPerFrame); - } - else - { - samplesCount = 1; - } - - int scaleFixedPoint = FixedPointHelper.ToFixed(1.0f, FixedPointPrecision) << scale; - - if (samplesCount < SamplesPerFrame) - { - for (int i = 0; i < samplesCount; i++) - { - int value = targetInput[inputIndex]; - - int sample; - - if ((nibbles & 1) != 0) - { - sample = (value << 28) >> 28; - - inputIndex++; - } - else - { - sample = (value << 24) >> 28; - } - - nibbles++; - - int prediction = coefficient0 * history0 + coefficient1 * history1; - - sample = FixedPointHelper.RoundUpAndToInt(sample * scaleFixedPoint + prediction, FixedPointPrecision); - - short saturatedSample = Saturate(sample); - - history1 = history0; - history0 = saturatedSample; - - output[outputBufferIndex++] = saturatedSample; - - remaining--; - } - } - else - { - for (int i = 0; i < SamplesPerFrame / 2; i++) - { - int value = targetInput[inputIndex]; - - int sample0; - int sample1; - - sample0 = (value << 24) >> 28; - sample1 = (value << 28) >> 28; - - inputIndex++; - - int prediction0 = coefficient0 * history0 + coefficient1 * history1; - sample0 = FixedPointHelper.RoundUpAndToInt(sample0 * scaleFixedPoint + prediction0, FixedPointPrecision); - short saturatedSample0 = Saturate(sample0); - - int prediction1 = coefficient0 * saturatedSample0 + coefficient1 * history0; - sample1 = FixedPointHelper.RoundUpAndToInt(sample1 * scaleFixedPoint + prediction1, FixedPointPrecision); - short saturatedSample1 = Saturate(sample1); - - history1 = saturatedSample0; - history0 = saturatedSample1; - - output[outputBufferIndex++] = saturatedSample0; - output[outputBufferIndex++] = saturatedSample1; - } - - nibbles += SamplesPerFrame; - remaining -= SamplesPerFrame; - } - } - - loopContext.PredScale = predScale; - loopContext.History0 = history0; - loopContext.History1 = history1; - - return decodedCount; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/AudioProcessor.cs b/Ryujinx.Audio.Renderer/Dsp/AudioProcessor.cs deleted file mode 100644 index d6cb497a..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/AudioProcessor.cs +++ /dev/null @@ -1,226 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp.Command; -using Ryujinx.Audio.Renderer.Integration; -using Ryujinx.Audio.Renderer.Utils; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using System; -using System.Threading; - -namespace Ryujinx.Audio.Renderer.Dsp -{ - public class AudioProcessor : IDisposable - { - private const int MaxBufferedFrames = 5; - private const int TargetBufferedFrames = 3; - - private enum MailboxMessage : uint - { - Start, - Stop, - RenderStart, - RenderEnd - } - - private class RendererSession - { - public CommandList CommandList; - public int RenderingLimit; - public ulong AppletResourceId; - } - - private Mailbox<MailboxMessage> _mailbox; - private RendererSession[] _sessionCommandList; - private Thread _workerThread; - private HardwareDevice[] _outputDevices; - - private long _lastTime; - private long _playbackEnds; - private ManualResetEvent _event; - - public AudioProcessor() - { - _event = new ManualResetEvent(false); - } - - public void SetOutputDevices(HardwareDevice[] outputDevices) - { - _outputDevices = outputDevices; - } - - public void Start() - { - _mailbox = new Mailbox<MailboxMessage>(); - _sessionCommandList = new RendererSession[RendererConstants.AudioRendererSessionCountMax]; - _event.Reset(); - _lastTime = PerformanceCounter.ElapsedNanoseconds; - - StartThread(); - - _mailbox.SendMessage(MailboxMessage.Start); - - if (_mailbox.ReceiveResponse() != MailboxMessage.Start) - { - throw new InvalidOperationException("Audio Processor Start response was invalid!"); - } - } - - public void Stop() - { - _mailbox.SendMessage(MailboxMessage.Stop); - - if (_mailbox.ReceiveResponse() != MailboxMessage.Stop) - { - throw new InvalidOperationException("Audio Processor Stop response was invalid!"); - } - } - - public void Send(int sessionId, CommandList commands, int renderingLimit, ulong appletResourceId) - { - _sessionCommandList[sessionId] = new RendererSession - { - CommandList = commands, - RenderingLimit = renderingLimit, - AppletResourceId = appletResourceId - }; - } - - public void Signal() - { - _mailbox.SendMessage(MailboxMessage.RenderStart); - } - - public void Wait() - { - if (_mailbox.ReceiveResponse() != MailboxMessage.RenderEnd) - { - throw new InvalidOperationException("Audio Processor Wait response was invalid!"); - } - - long increment = RendererConstants.AudioProcessorMaxUpdateTimeTarget; - - long timeNow = PerformanceCounter.ElapsedNanoseconds; - - if (timeNow > _playbackEnds) - { - // Playback has restarted. - _playbackEnds = timeNow; - } - - _playbackEnds += increment; - - // The number of frames we are behind where the timer says we should be. - long framesBehind = (timeNow - _lastTime) / increment; - - // The number of frames yet to play on the backend. - long bufferedFrames = (_playbackEnds - timeNow) / increment + framesBehind; - - // If we've entered a situation where a lot of buffers will be queued on the backend, - // Skip some audio frames so that playback can catch up. - if (bufferedFrames > MaxBufferedFrames) - { - // Skip a few frames so that we're not too far behind. (the target number of frames) - _lastTime += increment * (bufferedFrames - TargetBufferedFrames); - } - - while (timeNow < _lastTime + increment) - { - _event.WaitOne(1); - - timeNow = PerformanceCounter.ElapsedNanoseconds; - } - - _lastTime += increment; - } - - private void StartThread() - { - _workerThread = new Thread(Work) - { - Name = "AudioProcessor.Worker" - }; - - _workerThread.Start(); - } - - private void Work() - { - if (_mailbox.ReceiveMessage() != MailboxMessage.Start) - { - throw new InvalidOperationException("Audio Processor Start message was invalid!"); - } - - _mailbox.SendResponse(MailboxMessage.Start); - _mailbox.SendResponse(MailboxMessage.RenderEnd); - - Logger.Info?.Print(LogClass.AudioRenderer, "Starting audio processor"); - - while (true) - { - MailboxMessage message = _mailbox.ReceiveMessage(); - - if (message == MailboxMessage.Stop) - { - break; - } - - if (message == MailboxMessage.RenderStart) - { - long startTicks = PerformanceCounter.ElapsedNanoseconds; - - for (int i = 0; i < _sessionCommandList.Length; i++) - { - if (_sessionCommandList[i] != null) - { - _sessionCommandList[i].CommandList.Process(_outputDevices[i]); - _sessionCommandList[i] = null; - } - } - - long endTicks = PerformanceCounter.ElapsedNanoseconds; - - long elapsedTime = endTicks - startTicks; - - if (RendererConstants.AudioProcessorMaxUpdateTime < elapsedTime) - { - Logger.Debug?.Print(LogClass.AudioRenderer, $"DSP too slow (exceeded by {elapsedTime - RendererConstants.AudioProcessorMaxUpdateTime}ns)"); - } - - _mailbox.SendResponse(MailboxMessage.RenderEnd); - } - } - - Logger.Info?.Print(LogClass.AudioRenderer, "Stopping audio processor"); - _mailbox.SendResponse(MailboxMessage.Stop); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _event.Dispose(); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/AdpcmDataSourceCommandVersion1.cs b/Ryujinx.Audio.Renderer/Dsp/Command/AdpcmDataSourceCommandVersion1.cs deleted file mode 100644 index daf75208..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/AdpcmDataSourceCommandVersion1.cs +++ /dev/null @@ -1,93 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using System; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class AdpcmDataSourceCommandVersion1 : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.AdpcmDataSourceVersion1; - - public ulong EstimatedProcessingTime { get; set; } - - public ushort OutputBufferIndex { get; } - public uint SampleRate { get; } - - public float Pitch { get; } - - public WaveBuffer[] WaveBuffers { get; } - - public Memory<VoiceUpdateState> State { get; } - - public ulong AdpcmParameter { get; } - public ulong AdpcmParameterSize { get; } - - public DecodingBehaviour DecodingBehaviour { get; } - - public AdpcmDataSourceCommandVersion1(ref Server.Voice.VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, int nodeId) - { - Enabled = true; - NodeId = nodeId; - - OutputBufferIndex = outputBufferIndex; - SampleRate = serverState.SampleRate; - Pitch = serverState.Pitch; - - WaveBuffers = new WaveBuffer[RendererConstants.VoiceWaveBufferCount]; - - for (int i = 0; i < WaveBuffers.Length; i++) - { - ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i]; - - WaveBuffers[i] = voiceWaveBuffer.ToCommon(1); - } - - AdpcmParameter = serverState.DataSourceStateAddressInfo.GetReference(true); - AdpcmParameterSize = serverState.DataSourceStateAddressInfo.Size; - State = state; - DecodingBehaviour = serverState.DecodingBehaviour; - } - - public void Process(CommandList context) - { - Span<float> outputBuffer = context.GetBuffer(OutputBufferIndex); - - DataSourceHelper.WaveBufferInformation info = new DataSourceHelper.WaveBufferInformation() - { - State = State, - SourceSampleRate = SampleRate, - SampleFormat = SampleFormat.Adpcm, - Pitch = Pitch, - DecodingBehaviour = DecodingBehaviour, - WaveBuffers = WaveBuffers, - ExtraParameter = AdpcmParameter, - ExtraParameterSize = AdpcmParameterSize, - ChannelIndex = 0, - ChannelCount = 1, - }; - - DataSourceHelper.ProcessWaveBuffers(context.MemoryManager, outputBuffer, info, context.SampleRate, (int)context.SampleCount); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/AuxiliaryBufferCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/AuxiliaryBufferCommand.cs deleted file mode 100644 index 5ff3a6b4..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/AuxiliaryBufferCommand.cs +++ /dev/null @@ -1,205 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Memory; -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using static Ryujinx.Audio.Renderer.Dsp.State.AuxiliaryBufferHeader; -using CpuAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class AuxiliaryBufferCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.AuxiliaryBuffer; - - public ulong EstimatedProcessingTime { get; set; } - - public uint InputBufferIndex { get; } - public uint OutputBufferIndex { get; } - - public AuxiliaryBufferAddresses BufferInfo { get; } - - public CpuAddress InputBuffer { get; } - public CpuAddress OutputBuffer { get; } - public uint CountMax { get; } - public uint UpdateCount { get; } - public uint WriteOffset { get; } - - public bool IsEffectEnabled { get; } - - public AuxiliaryBufferCommand(uint bufferOffset, byte inputBufferOffset, byte outputBufferOffset, - ref AuxiliaryBufferAddresses sendBufferInfo, bool isEnabled, uint countMax, - CpuAddress outputBuffer, CpuAddress inputBuffer, uint updateCount, uint writeOffset, int nodeId) - { - Enabled = true; - NodeId = nodeId; - InputBufferIndex = bufferOffset + inputBufferOffset; - OutputBufferIndex = bufferOffset + outputBufferOffset; - BufferInfo = sendBufferInfo; - InputBuffer = inputBuffer; - OutputBuffer = outputBuffer; - CountMax = countMax; - UpdateCount = updateCount; - WriteOffset = writeOffset; - IsEffectEnabled = isEnabled; - } - - private uint Read(IVirtualMemoryManager memoryManager, ulong bufferAddress, uint countMax, Span<int> outBuffer, uint count, uint readOffset, uint updateCount) - { - if (countMax == 0 || bufferAddress == 0) - { - return 0; - } - - uint targetReadOffset = readOffset + AuxiliaryBufferInfo.GetReadOffset(memoryManager, BufferInfo.ReturnBufferInfo); - - if (targetReadOffset > countMax) - { - return 0; - } - - uint remaining = count; - - uint outBufferOffset = 0; - - while (remaining != 0) - { - uint countToWrite = Math.Min(countMax - targetReadOffset, remaining); - - memoryManager.Read(bufferAddress + targetReadOffset * sizeof(int), MemoryMarshal.Cast<int, byte>(outBuffer.Slice((int)outBufferOffset, (int)countToWrite))); - - targetReadOffset = (targetReadOffset + countToWrite) % countMax; - remaining -= countToWrite; - outBufferOffset += countToWrite; - } - - if (updateCount != 0) - { - uint newReadOffset = (AuxiliaryBufferInfo.GetReadOffset(memoryManager, BufferInfo.ReturnBufferInfo) + updateCount) % countMax; - - AuxiliaryBufferInfo.SetReadOffset(memoryManager, BufferInfo.ReturnBufferInfo, newReadOffset); - } - - return count; - } - - private uint Write(IVirtualMemoryManager memoryManager, ulong outBufferAddress, uint countMax, ReadOnlySpan<int> buffer, uint count, uint writeOffset, uint updateCount) - { - if (countMax == 0 || outBufferAddress == 0) - { - return 0; - } - - uint targetWriteOffset = writeOffset + AuxiliaryBufferInfo.GetWriteOffset(memoryManager, BufferInfo.SendBufferInfo); - - if (targetWriteOffset > countMax) - { - return 0; - } - - uint remaining = count; - - uint inBufferOffset = 0; - - while (remaining != 0) - { - uint countToWrite = Math.Min(countMax - targetWriteOffset, remaining); - - memoryManager.Write(outBufferAddress + targetWriteOffset * sizeof(int), MemoryMarshal.Cast<int, byte>(buffer.Slice((int)inBufferOffset, (int)countToWrite))); - - targetWriteOffset = (targetWriteOffset + countToWrite) % countMax; - remaining -= countToWrite; - inBufferOffset += countToWrite; - } - - if (updateCount != 0) - { - uint newWriteOffset = (AuxiliaryBufferInfo.GetWriteOffset(memoryManager, BufferInfo.SendBufferInfo) + updateCount) % countMax; - - AuxiliaryBufferInfo.SetWriteOffset(memoryManager, BufferInfo.SendBufferInfo, newWriteOffset); - } - - return count; - } - - public void Process(CommandList context) - { - Span<float> inputBuffer = context.GetBuffer((int)InputBufferIndex); - Span<float> outputBuffer = context.GetBuffer((int)OutputBufferIndex); - - if (IsEffectEnabled) - { - Span<int> inputBufferInt = MemoryMarshal.Cast<float, int>(inputBuffer); - Span<int> outputBufferInt = MemoryMarshal.Cast<float, int>(outputBuffer); - - // Convert input data to the target format for user (int) - DataSourceHelper.ToInt(inputBufferInt, inputBuffer, outputBuffer.Length); - - // Send the input to the user - Write(context.MemoryManager, OutputBuffer, CountMax, inputBufferInt, context.SampleCount, WriteOffset, UpdateCount); - - // Convert back to float just in case it's reused - DataSourceHelper.ToFloat(inputBuffer, inputBufferInt, inputBuffer.Length); - - // Retrieve the input from user - uint readResult = Read(context.MemoryManager, InputBuffer, CountMax, outputBufferInt, context.SampleCount, WriteOffset, UpdateCount); - - // Convert the outputBuffer back to the target format of the renderer (float) - DataSourceHelper.ToFloat(outputBuffer, outputBufferInt, outputBuffer.Length); - - if (readResult != context.SampleCount) - { - outputBuffer.Slice((int)readResult, (int)context.SampleCount - (int)readResult).Fill(0); - } - } - else - { - ZeroFill(context.MemoryManager, BufferInfo.SendBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>()); - ZeroFill(context.MemoryManager, BufferInfo.ReturnBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>()); - - if (InputBufferIndex != OutputBufferIndex) - { - inputBuffer.CopyTo(outputBuffer); - } - } - } - - private static void ZeroFill(IVirtualMemoryManager memoryManager, ulong address, int size) - { - ulong endAddress = address + (ulong)size; - - while (address + 7UL < endAddress) - { - memoryManager.Write(address, 0UL); - address += 8; - } - - while (address < endAddress) - { - memoryManager.Write(address, (byte)0); - address++; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/BiquadFilterCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/BiquadFilterCommand.cs deleted file mode 100644 index 580eb732..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/BiquadFilterCommand.cs +++ /dev/null @@ -1,89 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using System; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class BiquadFilterCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.BiquadFilter; - - public ulong EstimatedProcessingTime { get; set; } - - public BiquadFilterParameter Parameter { get; } - public Memory<BiquadFilterState> BiquadFilterState { get; } - public int InputBufferIndex { get; } - public int OutputBufferIndex { get; } - public bool NeedInitialization { get; } - - public BiquadFilterCommand(int baseIndex, ref BiquadFilterParameter filter, Memory<BiquadFilterState> biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, bool needInitialization, int nodeId) - { - Parameter = filter; - BiquadFilterState = biquadFilterStateMemory; - InputBufferIndex = baseIndex + inputBufferOffset; - OutputBufferIndex = baseIndex + outputBufferOffset; - NeedInitialization = needInitialization; - - Enabled = true; - NodeId = nodeId; - } - - private void ProcessBiquadFilter(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, uint sampleCount) - { - const int fixedPointPrecisionForParameter = 14; - - float a0 = FixedPointHelper.ToFloat(Parameter.Numerator[0], fixedPointPrecisionForParameter); - float a1 = FixedPointHelper.ToFloat(Parameter.Numerator[1], fixedPointPrecisionForParameter); - float a2 = FixedPointHelper.ToFloat(Parameter.Numerator[2], fixedPointPrecisionForParameter); - - float b1 = FixedPointHelper.ToFloat(Parameter.Denominator[0], fixedPointPrecisionForParameter); - float b2 = FixedPointHelper.ToFloat(Parameter.Denominator[1], fixedPointPrecisionForParameter); - - ref BiquadFilterState state = ref BiquadFilterState.Span[0]; - - for (int i = 0; i < sampleCount; i++) - { - float input = inputBuffer[i]; - float output = input * a0 + state.Z1; - - state.Z1 = input * a1 + output * b1 + state.Z2; - state.Z2 = input * a2 + output * b2; - - outputBuffer[i] = output; - } - } - - public void Process(CommandList context) - { - Span<float> outputBuffer = context.GetBuffer(InputBufferIndex); - - if (NeedInitialization) - { - BiquadFilterState.Span[0] = new BiquadFilterState(); - } - - ProcessBiquadFilter(outputBuffer, outputBuffer, context.SampleCount); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/CircularBufferSinkCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/CircularBufferSinkCommand.cs deleted file mode 100644 index 509aff27..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/CircularBufferSinkCommand.cs +++ /dev/null @@ -1,91 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Parameter.Sink; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class CircularBufferSinkCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.CircularBufferSink; - - public ulong EstimatedProcessingTime { get; set; } - - public ushort[] Input { get; } - public uint InputCount { get; } - - public ulong CircularBuffer { get; } - public ulong CircularBufferSize { get; } - public ulong CurrentOffset { get; } - - public CircularBufferSinkCommand(uint bufferOffset, ref CircularBufferParameter parameter, ref AddressInfo circularBufferAddressInfo, uint currentOffset, int nodeId) - { - Enabled = true; - NodeId = nodeId; - - Input = new ushort[RendererConstants.ChannelCountMax]; - InputCount = parameter.InputCount; - - for (int i = 0; i < InputCount; i++) - { - Input[i] = (ushort)(bufferOffset + parameter.Input[i]); - } - - CircularBuffer = circularBufferAddressInfo.GetReference(true); - CircularBufferSize = parameter.BufferSize; - CurrentOffset = currentOffset; - - Debug.Assert(CircularBuffer != 0); - } - - public void Process(CommandList context) - { - const int targetChannelCount = 2; - - ulong currentOffset = CurrentOffset; - - if (CircularBufferSize > 0) - { - for (int i = 0; i < InputCount; i++) - { - ReadOnlySpan<float> inputBuffer = context.GetBuffer(Input[i]); - - ulong targetOffset = CircularBuffer + currentOffset; - - for (int y = 0; y < context.SampleCount; y++) - { - context.MemoryManager.Write(targetOffset + (ulong)y * targetChannelCount, PcmHelper.Saturate(inputBuffer[y])); - } - - currentOffset += context.SampleCount * targetChannelCount; - - if (currentOffset >= CircularBufferSize) - { - currentOffset = 0; - } - } - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/ClearMixBufferCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/ClearMixBufferCommand.cs deleted file mode 100644 index ba9a0357..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/ClearMixBufferCommand.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class ClearMixBufferCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.ClearMixBuffer; - - public ulong EstimatedProcessingTime { get; set; } - - public ClearMixBufferCommand(int nodeId) - { - Enabled = true; - NodeId = nodeId; - } - - public void Process(CommandList context) - { - context.Buffers.Span.Fill(0); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/CommandList.cs b/Ryujinx.Audio.Renderer/Dsp/Command/CommandList.cs deleted file mode 100644 index bcc2cd11..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/CommandList.cs +++ /dev/null @@ -1,124 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Integration; -using Ryujinx.Audio.Renderer.Server; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Memory; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class CommandList - { - public ulong StartTime { get; private set; } - public ulong EndTime { get; private set; } - public uint SampleCount { get; } - public uint SampleRate { get; } - - public Memory<float> Buffers { get; } - public uint BufferCount { get; } - - public List<ICommand> Commands { get; } - - public IVirtualMemoryManager MemoryManager { get; } - - public HardwareDevice OutputDevice { get; private set; } - - public CommandList(AudioRenderSystem renderSystem) : this(renderSystem.MemoryManager, - renderSystem.GetMixBuffer(), - renderSystem.GetSampleCount(), - renderSystem.GetSampleRate(), - renderSystem.GetMixBufferCount(), - renderSystem.GetVoiceChannelCountMax()) - { - } - - public CommandList(IVirtualMemoryManager memoryManager, Memory<float> mixBuffer, uint sampleCount, uint sampleRate, uint mixBufferCount, uint voiceChannelCountMax) - { - SampleCount = sampleCount; - SampleRate = sampleRate; - BufferCount = mixBufferCount + voiceChannelCountMax; - Buffers = mixBuffer; - Commands = new List<ICommand>(); - MemoryManager = memoryManager; - } - - public void AddCommand(ICommand command) - { - Commands.Add(command); - } - - public void AddCommand<T>(T command) where T : unmanaged, ICommand - { - throw new NotImplementedException(); - } - - public Memory<float> GetBufferMemory(int index) - { - return Buffers.Slice(index * (int)SampleCount, (int)SampleCount); - } - - public Span<float> GetBuffer(int index) - { - return Buffers.Span.Slice(index * (int)SampleCount, (int)SampleCount); - } - - public ulong GetTimeElapsedSinceDspStartedProcessing() - { - return (ulong)PerformanceCounter.ElapsedNanoseconds - StartTime; - } - - public void Process(HardwareDevice outputDevice) - { - OutputDevice = outputDevice; - - StartTime = (ulong)PerformanceCounter.ElapsedNanoseconds; - - foreach (ICommand command in Commands) - { - if (command.Enabled) - { - bool shouldMeter = command.ShouldMeter(); - - long startTime = 0; - - if (shouldMeter) - { - startTime = PerformanceCounter.ElapsedNanoseconds; - } - - command.Process(this); - - if (shouldMeter) - { - ulong effectiveElapsedTime = (ulong)(PerformanceCounter.ElapsedNanoseconds - startTime); - - if (effectiveElapsedTime > command.EstimatedProcessingTime) - { - Logger.Warning?.Print(LogClass.AudioRenderer, $"Command {command.GetType().Name} took {effectiveElapsedTime}ns (expected {command.EstimatedProcessingTime}ns)"); - } - } - } - } - - EndTime = (ulong)PerformanceCounter.ElapsedNanoseconds; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/CommandType.cs b/Ryujinx.Audio.Renderer/Dsp/Command/CommandType.cs deleted file mode 100644 index 8ff1c581..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/CommandType.cs +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public enum CommandType : byte - { - Invalid, - PcmInt16DataSourceVersion1, - PcmInt16DataSourceVersion2, - PcmFloatDataSourceVersion1, - PcmFloatDataSourceVersion2, - AdpcmDataSourceVersion1, - AdpcmDataSourceVersion2, - Volume, - VolumeRamp, - BiquadFilter, - Mix, - MixRamp, - MixRampGrouped, - DepopPrepare, - DepopForMixBuffers, - Delay, - Upsample, - DownMixSurroundToStereo, - AuxiliaryBuffer, - DeviceSink, - CircularBufferSink, - Reverb, - Reverb3d, - Performance, - ClearMixBuffer, - CopyMixBuffer - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/CopyMixBufferCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/CopyMixBufferCommand.cs deleted file mode 100644 index 2dc6f04b..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/CopyMixBufferCommand.cs +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class CopyMixBufferCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.CopyMixBuffer; - - public ulong EstimatedProcessingTime { get; set; } - - public ushort InputBufferIndex { get; } - public ushort OutputBufferIndex { get; } - - public CopyMixBufferCommand(uint inputBufferIndex, uint outputBufferIndex, int nodeId) - { - Enabled = true; - NodeId = nodeId; - - InputBufferIndex = (ushort)inputBufferIndex; - OutputBufferIndex = (ushort)outputBufferIndex; - } - - public void Process(CommandList context) - { - ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndex); - Span<float> outputBuffer = context.GetBuffer(OutputBufferIndex); - - inputBuffer.CopyTo(outputBuffer); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/DataSourceVersion2Command.cs b/Ryujinx.Audio.Renderer/Dsp/Command/DataSourceVersion2Command.cs deleted file mode 100644 index 469f6ca5..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/DataSourceVersion2Command.cs +++ /dev/null @@ -1,126 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using System; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class DataSourceVersion2Command : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType { get; } - - public ulong EstimatedProcessingTime { get; set; } - - public ushort OutputBufferIndex { get; } - public uint SampleRate { get; } - - public float Pitch { get; } - - public WaveBuffer[] WaveBuffers { get; } - - public Memory<VoiceUpdateState> State { get; } - - public ulong ExtraParameter { get; } - public ulong ExtraParameterSize { get; } - - public uint ChannelIndex { get; } - - public uint ChannelCount { get; } - - public DecodingBehaviour DecodingBehaviour { get; } - - public SampleFormat SampleFormat { get; } - - public SampleRateConversionQuality SrcQuality { get; } - - public DataSourceVersion2Command(ref Server.Voice.VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId) - { - Enabled = true; - NodeId = nodeId; - ChannelIndex = channelIndex; - ChannelCount = serverState.ChannelsCount; - SampleFormat = serverState.SampleFormat; - SrcQuality = serverState.SrcQuality; - CommandType = GetCommandTypeBySampleFormat(SampleFormat); - - OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex); - SampleRate = serverState.SampleRate; - Pitch = serverState.Pitch; - - WaveBuffers = new WaveBuffer[RendererConstants.VoiceWaveBufferCount]; - - for (int i = 0; i < WaveBuffers.Length; i++) - { - ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i]; - - WaveBuffers[i] = voiceWaveBuffer.ToCommon(2); - } - - if (SampleFormat == SampleFormat.Adpcm) - { - ExtraParameter = serverState.DataSourceStateAddressInfo.GetReference(true); - ExtraParameterSize = serverState.DataSourceStateAddressInfo.Size; - } - - State = state; - DecodingBehaviour = serverState.DecodingBehaviour; - } - - private static CommandType GetCommandTypeBySampleFormat(SampleFormat sampleFormat) - { - switch (sampleFormat) - { - case SampleFormat.Adpcm: - return CommandType.AdpcmDataSourceVersion2; - case SampleFormat.PcmInt16: - return CommandType.PcmInt16DataSourceVersion2; - case SampleFormat.PcmFloat: - return CommandType.PcmFloatDataSourceVersion2; - default: - throw new NotImplementedException($"{sampleFormat}"); - } - } - - public void Process(CommandList context) - { - Span<float> outputBuffer = context.GetBuffer(OutputBufferIndex); - - DataSourceHelper.WaveBufferInformation info = new DataSourceHelper.WaveBufferInformation() - { - State = State, - SourceSampleRate = SampleRate, - SampleFormat = SampleFormat, - Pitch = Pitch, - DecodingBehaviour = DecodingBehaviour, - WaveBuffers = WaveBuffers, - ExtraParameter = ExtraParameter, - ExtraParameterSize = ExtraParameterSize, - ChannelIndex = (int)ChannelIndex, - ChannelCount = (int)ChannelCount, - SrcQuality = SrcQuality - }; - - DataSourceHelper.ProcessWaveBuffers(context.MemoryManager, outputBuffer, info, context.SampleRate, (int)context.SampleCount); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/DelayCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/DelayCommand.cs deleted file mode 100644 index 54234a93..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/DelayCommand.cs +++ /dev/null @@ -1,272 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.Effect; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class DelayCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.Delay; - - public ulong EstimatedProcessingTime { get; set; } - - public DelayParameter Parameter => _parameter; - public Memory<DelayState> State { get; } - public ulong WorkBuffer { get; } - public ushort[] OutputBufferIndices { get; } - public ushort[] InputBufferIndices { get; } - public bool IsEffectEnabled { get; } - - private DelayParameter _parameter; - - private const int FixedPointPrecision = 14; - - public DelayCommand(uint bufferOffset, DelayParameter parameter, Memory<DelayState> state, bool isEnabled, ulong workBuffer, int nodeId) - { - Enabled = true; - NodeId = nodeId; - _parameter = parameter; - State = state; - WorkBuffer = workBuffer; - - IsEffectEnabled = isEnabled; - - InputBufferIndices = new ushort[RendererConstants.VoiceChannelCountMax]; - OutputBufferIndices = new ushort[RendererConstants.VoiceChannelCountMax]; - - for (int i = 0; i < Parameter.ChannelCount; i++) - { - InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]); - OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]); - } - } - - private void ProcessDelayMono(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, uint sampleCount) - { - ref DelayState state = ref State.Span[0]; - - float feedbackGain = FixedPointHelper.ToFloat(Parameter.FeedbackGain, FixedPointPrecision); - float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision); - float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision); - float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); - - for (int i = 0; i < sampleCount; i++) - { - float input = inputBuffer[i] * 64; - float delayLineValue = state.DelayLines[0].Read(); - - float lowPassResult = input * inGain + delayLineValue * feedbackGain * state.LowPassBaseGain + state.LowPassZ[0] * state.LowPassFeedbackGain; - - state.LowPassZ[0] = lowPassResult; - - state.DelayLines[0].Update(lowPassResult); - - outputBuffer[i] = (input * dryGain + delayLineValue * outGain) / 64; - } - } - - private void ProcessDelayStereo(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount) - { - ref DelayState state = ref State.Span[0]; - - float[] channelInput = new float[Parameter.ChannelCount]; - float[] delayLineValues = new float[Parameter.ChannelCount]; - float[] temp = new float[Parameter.ChannelCount]; - - float delayFeedbackBaseGain = state.DelayFeedbackBaseGain; - float delayFeedbackCrossGain = state.DelayFeedbackCrossGain; - float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision); - float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision); - float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); - - for (int i = 0; i < sampleCount; i++) - { - for (int j = 0; j < Parameter.ChannelCount; j++) - { - channelInput[j] = inputBuffers[j].Span[i] * 64; - delayLineValues[j] = state.DelayLines[j].Read(); - } - - temp[0] = channelInput[0] * inGain + delayLineValues[1] * delayFeedbackCrossGain + delayLineValues[0] * delayFeedbackBaseGain; - temp[1] = channelInput[1] * inGain + delayLineValues[0] * delayFeedbackCrossGain + delayLineValues[1] * delayFeedbackBaseGain; - - for (int j = 0; j < Parameter.ChannelCount; j++) - { - float lowPassResult = state.LowPassFeedbackGain * state.LowPassZ[j] + temp[j] * state.LowPassBaseGain; - - state.LowPassZ[j] = lowPassResult; - state.DelayLines[j].Update(lowPassResult); - - outputBuffers[j].Span[i] = (channelInput[j] * dryGain + delayLineValues[j] * outGain) / 64; - } - } - } - - private void ProcessDelayQuadraphonic(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount) - { - ref DelayState state = ref State.Span[0]; - - float[] channelInput = new float[Parameter.ChannelCount]; - float[] delayLineValues = new float[Parameter.ChannelCount]; - float[] temp = new float[Parameter.ChannelCount]; - - float delayFeedbackBaseGain = state.DelayFeedbackBaseGain; - float delayFeedbackCrossGain = state.DelayFeedbackCrossGain; - float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision); - float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision); - float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); - - for (int i = 0; i < sampleCount; i++) - { - for (int j = 0; j < Parameter.ChannelCount; j++) - { - channelInput[j] = inputBuffers[j].Span[i] * 64; - delayLineValues[j] = state.DelayLines[j].Read(); - } - - temp[0] = channelInput[0] * inGain + (delayLineValues[2] + delayLineValues[1]) * delayFeedbackCrossGain + delayLineValues[0] * delayFeedbackBaseGain; - temp[1] = channelInput[1] * inGain + (delayLineValues[0] + delayLineValues[3]) * delayFeedbackCrossGain + delayLineValues[1] * delayFeedbackBaseGain; - temp[2] = channelInput[2] * inGain + (delayLineValues[3] + delayLineValues[0]) * delayFeedbackCrossGain + delayLineValues[2] * delayFeedbackBaseGain; - temp[3] = channelInput[3] * inGain + (delayLineValues[1] + delayLineValues[2]) * delayFeedbackCrossGain + delayLineValues[3] * delayFeedbackBaseGain; - - for (int j = 0; j < Parameter.ChannelCount; j++) - { - float lowPassResult = state.LowPassFeedbackGain * state.LowPassZ[j] + temp[j] * state.LowPassBaseGain; - - state.LowPassZ[j] = lowPassResult; - state.DelayLines[j].Update(lowPassResult); - - outputBuffers[j].Span[i] = (channelInput[j] * dryGain + delayLineValues[j] * outGain) / 64; - } - } - } - - private void ProcessDelaySurround(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount) - { - ref DelayState state = ref State.Span[0]; - - float[] channelInput = new float[Parameter.ChannelCount]; - float[] delayLineValues = new float[Parameter.ChannelCount]; - float[] temp = new float[Parameter.ChannelCount]; - - float delayFeedbackBaseGain = state.DelayFeedbackBaseGain; - float delayFeedbackCrossGain = state.DelayFeedbackCrossGain; - float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision); - float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision); - float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); - - for (int i = 0; i < sampleCount; i++) - { - for (int j = 0; j < Parameter.ChannelCount; j++) - { - channelInput[j] = inputBuffers[j].Span[i] * 64; - delayLineValues[j] = state.DelayLines[j].Read(); - } - - temp[0] = channelInput[0] * inGain + (delayLineValues[2] + delayLineValues[4]) * delayFeedbackCrossGain + delayLineValues[0] * delayFeedbackBaseGain; - temp[1] = channelInput[1] * inGain + (delayLineValues[4] + delayLineValues[3]) * delayFeedbackCrossGain + delayLineValues[1] * delayFeedbackBaseGain; - temp[2] = channelInput[2] * inGain + (delayLineValues[3] + delayLineValues[0]) * delayFeedbackCrossGain + delayLineValues[2] * delayFeedbackBaseGain; - temp[3] = channelInput[3] * inGain + (delayLineValues[1] + delayLineValues[2]) * delayFeedbackCrossGain + delayLineValues[3] * delayFeedbackBaseGain; - temp[4] = channelInput[4] * inGain + (delayLineValues[0] + delayLineValues[1]) * delayFeedbackCrossGain + delayLineValues[4] * delayFeedbackBaseGain; - temp[5] = channelInput[5] * inGain + delayLineValues[5] * delayFeedbackBaseGain; - - for (int j = 0; j < Parameter.ChannelCount; j++) - { - float lowPassResult = state.LowPassFeedbackGain * state.LowPassZ[j] + temp[j] * state.LowPassBaseGain; - - state.LowPassZ[j] = lowPassResult; - state.DelayLines[j].Update(lowPassResult); - - outputBuffers[j].Span[i] = (channelInput[j] * dryGain + delayLineValues[j] * outGain) / 64; - } - } - } - - private void ProcessDelay(CommandList context) - { - Debug.Assert(Parameter.IsChannelCountValid()); - - if (IsEffectEnabled && Parameter.IsChannelCountValid()) - { - ReadOnlyMemory<float>[] inputBuffers = new ReadOnlyMemory<float>[Parameter.ChannelCount]; - Memory<float>[] outputBuffers = new Memory<float>[Parameter.ChannelCount]; - - for (int i = 0; i < Parameter.ChannelCount; i++) - { - inputBuffers[i] = context.GetBufferMemory(InputBufferIndices[i]); - outputBuffers[i] = context.GetBufferMemory(OutputBufferIndices[i]); - } - - switch (Parameter.ChannelCount) - { - case 1: - ProcessDelayMono(outputBuffers[0].Span, inputBuffers[0].Span, context.SampleCount); - break; - case 2: - ProcessDelayStereo(outputBuffers, inputBuffers, context.SampleCount); - break; - case 4: - ProcessDelayQuadraphonic(outputBuffers, inputBuffers, context.SampleCount); - break; - case 6: - ProcessDelaySurround(outputBuffers, inputBuffers, context.SampleCount); - break; - default: - throw new NotImplementedException($"{Parameter.ChannelCount}"); - } - } - else - { - for (int i = 0; i < Parameter.ChannelCount; i++) - { - if (InputBufferIndices[i] != OutputBufferIndices[i]) - { - context.GetBufferMemory(InputBufferIndices[i]).CopyTo(context.GetBufferMemory(OutputBufferIndices[i])); - } - } - } - } - - public void Process(CommandList context) - { - ref DelayState state = ref State.Span[0]; - - if (IsEffectEnabled) - { - if (Parameter.Status == UsageState.Invalid) - { - state = new DelayState(ref _parameter, WorkBuffer); - } - else if (Parameter.Status == UsageState.New) - { - state.UpdateParameter(ref _parameter); - } - } - - ProcessDelay(context); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/DepopForMixBuffersCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/DepopForMixBuffersCommand.cs deleted file mode 100644 index c6feacfb..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/DepopForMixBuffersCommand.cs +++ /dev/null @@ -1,103 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class DepopForMixBuffersCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.DepopForMixBuffers; - - public ulong EstimatedProcessingTime { get; set; } - - public uint MixBufferOffset { get; } - - public uint MixBufferCount { get; } - - public float Decay { get; } - - public Memory<float> DepopBuffer { get; } - - private const int FixedPointPrecisionForDecay = 15; - - public DepopForMixBuffersCommand(Memory<float> depopBuffer, uint bufferOffset, uint mixBufferCount, int nodeId, uint sampleRate) - { - Enabled = true; - NodeId = nodeId; - MixBufferOffset = bufferOffset; - MixBufferCount = mixBufferCount; - DepopBuffer = depopBuffer; - - if (sampleRate == 48000) - { - Decay = 0.962189f; - } - else // if (sampleRate == 32000) - { - Decay = 0.943695f; - } - } - - private float ProcessDepopMix(Span<float> buffer, float depopValue, uint sampleCount) - { - if (depopValue <= 0) - { - for (int i = 0; i < sampleCount; i++) - { - depopValue = FloatingPointHelper.MultiplyRoundDown(Decay, depopValue); - - buffer[i] -= depopValue; - } - - return -depopValue; - } - else - { - for (int i = 0; i < sampleCount; i++) - { - depopValue = FloatingPointHelper.MultiplyRoundDown(Decay, depopValue); - - buffer[i] += depopValue; - } - - return depopValue; - } - - } - - public void Process(CommandList context) - { - uint bufferCount = Math.Min(MixBufferOffset + MixBufferCount, context.BufferCount); - - for (int i = (int)MixBufferOffset; i < bufferCount; i++) - { - float depopValue = DepopBuffer.Span[i]; - if (depopValue != 0) - { - Span<float> buffer = context.GetBuffer(i); - - DepopBuffer.Span[i] = ProcessDepopMix(buffer, depopValue, context.SampleCount); - } - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/DepopPrepareCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/DepopPrepareCommand.cs deleted file mode 100644 index d09c380e..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/DepopPrepareCommand.cs +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using System; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class DepopPrepareCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.DepopPrepare; - - public ulong EstimatedProcessingTime { get; set; } - - public uint MixBufferCount { get; } - - public ushort[] OutputBufferIndices { get; } - - public Memory<VoiceUpdateState> State { get; } - public Memory<float> DepopBuffer { get; } - - public DepopPrepareCommand(Memory<VoiceUpdateState> state, Memory<float> depopBuffer, uint mixBufferCount, uint bufferOffset, int nodeId, bool enabled) - { - Enabled = enabled; - NodeId = nodeId; - MixBufferCount = mixBufferCount; - - OutputBufferIndices = new ushort[RendererConstants.MixBufferCountMax]; - - for (int i = 0; i < RendererConstants.MixBufferCountMax; i++) - { - OutputBufferIndices[i] = (ushort)(bufferOffset + i); - } - - State = state; - DepopBuffer = depopBuffer; - } - - public void Process(CommandList context) - { - ref VoiceUpdateState state = ref State.Span[0]; - - for (int i = 0; i < MixBufferCount; i++) - { - if (state.LastSamples[i] != 0) - { - DepopBuffer.Span[OutputBufferIndices[i]] += state.LastSamples[i]; - - state.LastSamples[i] = 0; - } - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/DeviceSinkCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/DeviceSinkCommand.cs deleted file mode 100644 index 621e0269..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/DeviceSinkCommand.cs +++ /dev/null @@ -1,108 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Integration; -using Ryujinx.Audio.Renderer.Server.Sink; -using System; -using System.Runtime.CompilerServices; -using System.Text; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class DeviceSinkCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.DeviceSink; - - public ulong EstimatedProcessingTime { get; set; } - - public string DeviceName { get; } - - public int SessionId { get; } - - public uint InputCount { get; } - public ushort[] InputBufferIndices { get; } - - public Memory<float> Buffers { get; } - - public DeviceSinkCommand(uint bufferOffset, DeviceSink sink, int sessionId, Memory<float> buffers, int nodeId) - { - Enabled = true; - NodeId = nodeId; - - DeviceName = Encoding.ASCII.GetString(sink.Parameter.DeviceName).TrimEnd('\0'); - SessionId = sessionId; - InputCount = sink.Parameter.InputCount; - InputBufferIndices = new ushort[InputCount]; - - for (int i = 0; i < InputCount; i++) - { - InputBufferIndices[i] = (ushort)(bufferOffset + sink.Parameter.Input[i]); - } - - if (sink.UpsamplerState != null) - { - Buffers = sink.UpsamplerState.OutputBuffer; - } - else - { - Buffers = buffers; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Span<float> GetBuffer(int index, int sampleCount) - { - return Buffers.Span.Slice(index * sampleCount, sampleCount); - } - - public void Process(CommandList context) - { - HardwareDevice device = context.OutputDevice; - - if (device.GetSampleRate() == RendererConstants.TargetSampleRate) - { - int channelCount = (int)device.GetChannelCount(); - uint bufferCount = Math.Min(device.GetChannelCount(), InputCount); - - const int sampleCount = RendererConstants.TargetSampleCount; - - short[] outputBuffer = new short[bufferCount * sampleCount]; - - for (int i = 0; i < bufferCount; i++) - { - ReadOnlySpan<float> inputBuffer = GetBuffer(InputBufferIndices[i], sampleCount); - - for (int j = 0; j < sampleCount; j++) - { - outputBuffer[i + j * channelCount] = PcmHelper.Saturate(inputBuffer[j]); - } - } - - device.AppendBuffer(outputBuffer, InputCount); - } - else - { - // TODO: support resampling for device only supporting something different - throw new NotImplementedException(); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/DownMixSurroundToStereoCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/DownMixSurroundToStereoCommand.cs deleted file mode 100644 index 96138db2..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/DownMixSurroundToStereoCommand.cs +++ /dev/null @@ -1,89 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class DownMixSurroundToStereoCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.DownMixSurroundToStereo; - - public ulong EstimatedProcessingTime { get; set; } - - public ushort[] InputBufferIndices { get; } - public ushort[] OutputBufferIndices { get; } - - public float[] Coefficients { get; } - - public DownMixSurroundToStereoCommand(uint bufferOffset, Span<byte> inputBufferOffset, Span<byte> outputBufferOffset, ReadOnlySpan<float> downMixParameter, int nodeId) - { - Enabled = true; - NodeId = nodeId; - - InputBufferIndices = new ushort[RendererConstants.VoiceChannelCountMax]; - OutputBufferIndices = new ushort[RendererConstants.VoiceChannelCountMax]; - - for (int i = 0; i < RendererConstants.VoiceChannelCountMax; i++) - { - InputBufferIndices[i] = (ushort)(bufferOffset + inputBufferOffset[i]); - OutputBufferIndices[i] = (ushort)(bufferOffset + outputBufferOffset[i]); - } - - Coefficients = downMixParameter.ToArray(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static float DownMixSurroundToStereo(ReadOnlySpan<float> coefficients, float back, float lfe, float center, float front) - { - return FloatingPointHelper.RoundUp(coefficients[3] * back + coefficients[2] * lfe + coefficients[1] * center + coefficients[0] * front); - } - - public void Process(CommandList context) - { - ReadOnlySpan<float> frontLeft = context.GetBuffer(InputBufferIndices[0]); - ReadOnlySpan<float> frontRight = context.GetBuffer(InputBufferIndices[1]); - ReadOnlySpan<float> frontCenter = context.GetBuffer(InputBufferIndices[2]); - ReadOnlySpan<float> lowFrequency = context.GetBuffer(InputBufferIndices[3]); - ReadOnlySpan<float> backLeft = context.GetBuffer(InputBufferIndices[4]); - ReadOnlySpan<float> backRight = context.GetBuffer(InputBufferIndices[5]); - - Span<float> stereoLeft = context.GetBuffer(OutputBufferIndices[0]); - Span<float> stereoRight = context.GetBuffer(OutputBufferIndices[1]); - Span<float> unused2 = context.GetBuffer(OutputBufferIndices[2]); - Span<float> unused3 = context.GetBuffer(OutputBufferIndices[3]); - Span<float> unused4 = context.GetBuffer(OutputBufferIndices[4]); - Span<float> unused5 = context.GetBuffer(OutputBufferIndices[5]); - - for (int i = 0; i < context.SampleCount; i++) - { - stereoLeft[i] = DownMixSurroundToStereo(Coefficients, backLeft[i], lowFrequency[i], frontCenter[i], frontLeft[i]); - stereoRight[i] = DownMixSurroundToStereo(Coefficients, backRight[i], lowFrequency[i], frontCenter[i], frontRight[i]); - } - - unused2.Fill(0); - unused3.Fill(0); - unused4.Fill(0); - unused5.Fill(0); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/ICommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/ICommand.cs deleted file mode 100644 index e2f00ef6..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/ICommand.cs +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public interface ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType { get; } - - public ulong EstimatedProcessingTime { get; } - - public void Process(CommandList context); - - public bool ShouldMeter() - { - return false; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/MixCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/MixCommand.cs deleted file mode 100644 index 566fea92..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/MixCommand.cs +++ /dev/null @@ -1,125 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class MixCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.Mix; - - public ulong EstimatedProcessingTime { get; set; } - - public ushort InputBufferIndex { get; } - public ushort OutputBufferIndex { get; } - - public float Volume { get; } - - public MixCommand(uint inputBufferIndex, uint outputBufferIndex, int nodeId, float volume) - { - Enabled = true; - NodeId = nodeId; - - InputBufferIndex = (ushort)inputBufferIndex; - OutputBufferIndex = (ushort)outputBufferIndex; - - Volume = volume; - } - - private void ProcessMixAvx(Span<float> outputMix, ReadOnlySpan<float> inputMix) - { - Vector256<float> volumeVec = Vector256.Create(Volume); - - ReadOnlySpan<Vector256<float>> inputVec = MemoryMarshal.Cast<float, Vector256<float>>(inputMix); - Span<Vector256<float>> outputVec = MemoryMarshal.Cast<float, Vector256<float>>(outputMix); - - int sisdStart = inputVec.Length * 8; - - for (int i = 0; i < inputVec.Length; i++) - { - outputVec[i] = Avx.Add(outputVec[i], Avx.Ceiling(Avx.Multiply(inputVec[i], volumeVec))); - } - - for (int i = sisdStart; i < inputMix.Length; i++) - { - outputMix[i] += FloatingPointHelper.MultiplyRoundUp(inputMix[i], Volume); - } - } - - private void ProcessMixSse41(Span<float> outputMix, ReadOnlySpan<float> inputMix) - { - Vector128<float> volumeVec = Vector128.Create(Volume); - - ReadOnlySpan<Vector128<float>> inputVec = MemoryMarshal.Cast<float, Vector128<float>>(inputMix); - Span<Vector128<float>> outputVec = MemoryMarshal.Cast<float, Vector128<float>>(outputMix); - - int sisdStart = inputVec.Length * 4; - - for (int i = 0; i < inputVec.Length; i++) - { - outputVec[i] = Sse.Add(outputVec[i], Sse41.Ceiling(Sse.Multiply(inputVec[i], volumeVec))); - } - - for (int i = sisdStart; i < inputMix.Length; i++) - { - outputMix[i] += FloatingPointHelper.MultiplyRoundUp(inputMix[i], Volume); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ProcessMixSlowPath(Span<float> outputMix, ReadOnlySpan<float> inputMix) - { - for (int i = 0; i < inputMix.Length; i++) - { - outputMix[i] += FloatingPointHelper.MultiplyRoundUp(inputMix[i], Volume); - } - } - - private void ProcessMix(Span<float> outputMix, ReadOnlySpan<float> inputMix) - { - if (Avx.IsSupported) - { - ProcessMixAvx(outputMix, inputMix); - } - else if (Sse41.IsSupported) - { - ProcessMixSse41(outputMix, inputMix); - } - else - { - ProcessMixSlowPath(outputMix, inputMix); - } - } - - public void Process(CommandList context) - { - ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndex); - Span<float> outputBuffer = context.GetBuffer(OutputBufferIndex); - - ProcessMix(outputBuffer, inputBuffer); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/MixRampCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/MixRampCommand.cs deleted file mode 100644 index f34e50e4..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/MixRampCommand.cs +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using System; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class MixRampCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.MixRamp; - - public ulong EstimatedProcessingTime { get; set; } - - public ushort InputBufferIndex { get; } - public ushort OutputBufferIndex { get; } - - public float Volume0 { get; } - public float Volume1 { get; } - - public Memory<VoiceUpdateState> State { get; } - - public int LastSampleIndex { get; } - - public MixRampCommand(float volume0, float volume1, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory<VoiceUpdateState> state, int nodeId) - { - Enabled = true; - NodeId = nodeId; - - InputBufferIndex = (ushort)inputBufferIndex; - OutputBufferIndex = (ushort)outputBufferIndex; - - Volume0 = volume0; - Volume1 = volume1; - - State = state; - LastSampleIndex = lastSampleIndex; - } - - private float ProcessMixRamp(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, int sampleCount) - { - float ramp = (Volume1 - Volume0) / sampleCount; - float volume = Volume0; - float state = 0; - - for (int i = 0; i < sampleCount; i++) - { - state = FloatingPointHelper.MultiplyRoundUp(inputBuffer[i], volume); - - outputBuffer[i] += state; - volume += ramp; - } - - return state; - } - - public void Process(CommandList context) - { - ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndex); - Span<float> outputBuffer = context.GetBuffer(OutputBufferIndex); - - State.Span[0].LastSamples[LastSampleIndex] = ProcessMixRamp(outputBuffer, inputBuffer, (int)context.SampleCount); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/MixRampGroupedCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/MixRampGroupedCommand.cs deleted file mode 100644 index d45da1e3..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/MixRampGroupedCommand.cs +++ /dev/null @@ -1,106 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using System; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class MixRampGroupedCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.MixRampGrouped; - - public ulong EstimatedProcessingTime { get; set; } - - public uint MixBufferCount { get; } - - public ushort[] InputBufferIndices { get; } - public ushort[] OutputBufferIndices { get; } - - public float[] Volume0 { get; } - public float[] Volume1 { get; } - - public Memory<VoiceUpdateState> State { get; } - - public MixRampGroupedCommand(uint mixBufferCount, uint inputBufferIndex, uint outputBufferIndex, Span<float> volume0, Span<float> volume1, Memory<VoiceUpdateState> state, int nodeId) - { - Enabled = true; - MixBufferCount = mixBufferCount; - NodeId = nodeId; - - InputBufferIndices = new ushort[RendererConstants.MixBufferCountMax]; - OutputBufferIndices = new ushort[RendererConstants.MixBufferCountMax]; - Volume0 = new float[RendererConstants.MixBufferCountMax]; - Volume1 = new float[RendererConstants.MixBufferCountMax]; - - for (int i = 0; i < mixBufferCount; i++) - { - InputBufferIndices[i] = (ushort)inputBufferIndex; - OutputBufferIndices[i] = (ushort)(outputBufferIndex + i); - - Volume0[i] = volume0[i]; - Volume1[i] = volume1[i]; - } - - State = state; - } - - private float ProcessMixRampGrouped(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, float volume0, float volume1, int sampleCount) - { - float ramp = (volume1 - volume0) / sampleCount; - float volume = volume0; - float state = 0; - - for (int i = 0; i < sampleCount; i++) - { - state = FloatingPointHelper.MultiplyRoundUp(inputBuffer[i], volume); - - outputBuffer[i] += state; - volume += ramp; - } - - return state; - } - - public void Process(CommandList context) - { - for (int i = 0; i < MixBufferCount; i++) - { - ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndices[i]); - Span<float> outputBuffer = context.GetBuffer(OutputBufferIndices[i]); - - float volume0 = Volume0[i]; - float volume1 = Volume1[i]; - - ref VoiceUpdateState state = ref State.Span[0]; - - if (volume0 != 0 || volume1 != 0) - { - state.LastSamples[i] = ProcessMixRampGrouped(outputBuffer, inputBuffer, volume0, volume1, (int)context.SampleCount); - } - else - { - state.LastSamples[i] = 0; - } - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/PcmFloatDataSourceCommandVersion1.cs b/Ryujinx.Audio.Renderer/Dsp/Command/PcmFloatDataSourceCommandVersion1.cs deleted file mode 100644 index d50c61fd..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/PcmFloatDataSourceCommandVersion1.cs +++ /dev/null @@ -1,92 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using System; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class PcmFloatDataSourceCommandVersion1 : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1; - - public ulong EstimatedProcessingTime { get; set; } - - public ushort OutputBufferIndex { get; } - public uint SampleRate { get; } - public uint ChannelIndex { get; } - - public uint ChannelCount { get; } - - public float Pitch { get; } - - public WaveBuffer[] WaveBuffers { get; } - - public Memory<VoiceUpdateState> State { get; } - public DecodingBehaviour DecodingBehaviour { get; } - - public PcmFloatDataSourceCommandVersion1(ref Server.Voice.VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId) - { - Enabled = true; - NodeId = nodeId; - - OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex); - SampleRate = serverState.SampleRate; - ChannelIndex = channelIndex; - ChannelCount = serverState.ChannelsCount; - Pitch = serverState.Pitch; - - WaveBuffers = new WaveBuffer[RendererConstants.VoiceWaveBufferCount]; - - for (int i = 0; i < WaveBuffers.Length; i++) - { - ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i]; - - WaveBuffers[i] = voiceWaveBuffer.ToCommon(1); - } - - State = state; - DecodingBehaviour = serverState.DecodingBehaviour; - } - - public void Process(CommandList context) - { - Span<float> outputBuffer = context.GetBuffer(OutputBufferIndex); - - DataSourceHelper.WaveBufferInformation info = new DataSourceHelper.WaveBufferInformation() - { - State = State, - SourceSampleRate = SampleRate, - SampleFormat = SampleFormat.PcmInt16, - Pitch = Pitch, - DecodingBehaviour = DecodingBehaviour, - WaveBuffers = WaveBuffers, - ExtraParameter = 0, - ExtraParameterSize = 0, - ChannelIndex = (int)ChannelIndex, - ChannelCount = (int)ChannelCount, - }; - - DataSourceHelper.ProcessWaveBuffers(context.MemoryManager, outputBuffer, info, context.SampleRate, (int)context.SampleCount); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/PcmInt16DataSourceCommandVersion1.cs b/Ryujinx.Audio.Renderer/Dsp/Command/PcmInt16DataSourceCommandVersion1.cs deleted file mode 100644 index 9decd431..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/PcmInt16DataSourceCommandVersion1.cs +++ /dev/null @@ -1,92 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using System; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class PcmInt16DataSourceCommandVersion1 : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1; - - public ulong EstimatedProcessingTime { get; set; } - - public ushort OutputBufferIndex { get; } - public uint SampleRate { get; } - public uint ChannelIndex { get; } - - public uint ChannelCount { get; } - - public float Pitch { get; } - - public WaveBuffer[] WaveBuffers { get; } - - public Memory<VoiceUpdateState> State { get; } - public DecodingBehaviour DecodingBehaviour { get; } - - public PcmInt16DataSourceCommandVersion1(ref Server.Voice.VoiceState serverState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId) - { - Enabled = true; - NodeId = nodeId; - - OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex); - SampleRate = serverState.SampleRate; - ChannelIndex = channelIndex; - ChannelCount = serverState.ChannelsCount; - Pitch = serverState.Pitch; - - WaveBuffers = new WaveBuffer[RendererConstants.VoiceWaveBufferCount]; - - for (int i = 0; i < WaveBuffers.Length; i++) - { - ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i]; - - WaveBuffers[i] = voiceWaveBuffer.ToCommon(1); - } - - State = state; - DecodingBehaviour = serverState.DecodingBehaviour; - } - - public void Process(CommandList context) - { - Span<float> outputBuffer = context.GetBuffer(OutputBufferIndex); - - DataSourceHelper.WaveBufferInformation info = new DataSourceHelper.WaveBufferInformation() - { - State = State, - SourceSampleRate = SampleRate, - SampleFormat = SampleFormat.PcmInt16, - Pitch = Pitch, - DecodingBehaviour = DecodingBehaviour, - WaveBuffers = WaveBuffers, - ExtraParameter = 0, - ExtraParameterSize = 0, - ChannelIndex = (int)ChannelIndex, - ChannelCount = (int)ChannelCount, - }; - - DataSourceHelper.ProcessWaveBuffers(context.MemoryManager, outputBuffer, info, context.SampleRate, (int)context.SampleCount); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/PerformanceCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/PerformanceCommand.cs deleted file mode 100644 index 0cc35712..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/PerformanceCommand.cs +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Server.Performance; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class PerformanceCommand : ICommand - { - public enum Type - { - Invalid, - Start, - End - } - - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.Performance; - - public ulong EstimatedProcessingTime { get; set; } - - public PerformanceEntryAddresses PerformanceEntryAddresses { get; } - - public Type PerformanceType { get; set; } - - public PerformanceCommand(ref PerformanceEntryAddresses performanceEntryAddresses, Type performanceType, int nodeId) - { - Enabled = true; - PerformanceEntryAddresses = performanceEntryAddresses; - PerformanceType = performanceType; - NodeId = nodeId; - } - - public void Process(CommandList context) - { - if (PerformanceType == Type.Start) - { - PerformanceEntryAddresses.SetStartTime(context.GetTimeElapsedSinceDspStartedProcessing()); - } - else if (PerformanceType == Type.End) - { - PerformanceEntryAddresses.SetProcessingTime(context.GetTimeElapsedSinceDspStartedProcessing()); - PerformanceEntryAddresses.IncrementEntryCount(); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/Reverb3dCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/Reverb3dCommand.cs deleted file mode 100644 index c1527758..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/Reverb3dCommand.cs +++ /dev/null @@ -1,263 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.Effect; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class Reverb3dCommand : ICommand - { - private static readonly int[] OutputEarlyIndicesTableMono = new int[20] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - private static readonly int[] TargetEarlyDelayLineIndicesTableMono = new int[20] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; - private static readonly int[] TargetOutputFeedbackIndicesTableMono = new int[1] { 0 }; - - private static readonly int[] OutputEarlyIndicesTableStereo = new int[20] { 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1 }; - private static readonly int[] TargetEarlyDelayLineIndicesTableStereo = new int[20] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; - private static readonly int[] TargetOutputFeedbackIndicesTableStereo = new int[2] { 0, 1 }; - - private static readonly int[] OutputEarlyIndicesTableQuadraphonic = new int[20] { 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 3, 3, 3 }; - private static readonly int[] TargetEarlyDelayLineIndicesTableQuadraphonic = new int[20] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; - private static readonly int[] TargetOutputFeedbackIndicesTableQuadraphonic = new int[4] { 0, 1, 2, 3 }; - - private static readonly int[] OutputEarlyIndicesTableSurround = new int[40] { 4, 5, 0, 5, 0, 5, 1, 5, 1, 5, 1, 5, 1, 5, 2, 5, 2, 5, 2, 5, 1, 5, 1, 5, 1, 5, 0, 5, 0, 5, 0, 5, 0, 5, 3, 5, 3, 5, 3, 5 }; - private static readonly int[] TargetEarlyDelayLineIndicesTableSurround = new int[40] { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19 }; - private static readonly int[] TargetOutputFeedbackIndicesTableSurround = new int[6] { 0, 1, 2, 3, -1, 3 }; - - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.Reverb3d; - - public ulong EstimatedProcessingTime { get; set; } - - public ushort InputBufferIndex { get; } - public ushort OutputBufferIndex { get; } - - public Reverb3dParameter Parameter => _parameter; - public Memory<Reverb3dState> State { get; } - public ulong WorkBuffer { get; } - public ushort[] OutputBufferIndices { get; } - public ushort[] InputBufferIndices { get; } - - public bool IsEffectEnabled { get; } - - private Reverb3dParameter _parameter; - - public Reverb3dCommand(uint bufferOffset, Reverb3dParameter parameter, Memory<Reverb3dState> state, bool isEnabled, ulong workBuffer, int nodeId) - { - Enabled = true; - IsEffectEnabled = isEnabled; - NodeId = nodeId; - _parameter = parameter; - State = state; - WorkBuffer = workBuffer; - - InputBufferIndices = new ushort[RendererConstants.VoiceChannelCountMax]; - OutputBufferIndices = new ushort[RendererConstants.VoiceChannelCountMax]; - - for (int i = 0; i < Parameter.ChannelCount; i++) - { - InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]); - OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]); - } - } - - private void ProcessReverb3dMono(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount) - { - ProcessReverb3dGeneric(outputBuffers, inputBuffers, sampleCount, OutputEarlyIndicesTableMono, TargetEarlyDelayLineIndicesTableMono, TargetOutputFeedbackIndicesTableMono); - } - - private void ProcessReverb3dStereo(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount) - { - ProcessReverb3dGeneric(outputBuffers, inputBuffers, sampleCount, OutputEarlyIndicesTableStereo, TargetEarlyDelayLineIndicesTableStereo, TargetOutputFeedbackIndicesTableStereo); - } - - private void ProcessReverb3dQuadraphonic(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount) - { - ProcessReverb3dGeneric(outputBuffers, inputBuffers, sampleCount, OutputEarlyIndicesTableQuadraphonic, TargetEarlyDelayLineIndicesTableQuadraphonic, TargetOutputFeedbackIndicesTableQuadraphonic); - } - - private void ProcessReverb3dSurround(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount) - { - ProcessReverb3dGeneric(outputBuffers, inputBuffers, sampleCount, OutputEarlyIndicesTableSurround, TargetEarlyDelayLineIndicesTableSurround, TargetOutputFeedbackIndicesTableSurround); - } - - private void ProcessReverb3dGeneric(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount, ReadOnlySpan<int> outputEarlyIndicesTable, ReadOnlySpan<int> targetEarlyDelayLineIndicesTable, ReadOnlySpan<int> targetOutputFeedbackIndicesTable) - { - const int delayLineSampleIndexOffset = 1; - - ref Reverb3dState state = ref State.Span[0]; - - bool isMono = Parameter.ChannelCount == 1; - bool isSurround = Parameter.ChannelCount == 6; - - float[] outputValues = new float[RendererConstants.ChannelCountMax]; - float[] channelInput = new float[Parameter.ChannelCount]; - float[] feedbackValues = new float[4]; - float[] feedbackOutputValues = new float[4]; - float[] values = new float[4]; - - for (int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) - { - outputValues.AsSpan().Fill(0); - - float tapOut = state.PreDelayLine.TapUnsafe(state.ReflectionDelayTime, delayLineSampleIndexOffset); - - for (int i = 0; i < targetEarlyDelayLineIndicesTable.Length; i++) - { - int earlyDelayIndex = targetEarlyDelayLineIndicesTable[i]; - int outputIndex = outputEarlyIndicesTable[i]; - - float tempTapOut = state.PreDelayLine.TapUnsafe(state.EarlyDelayTime[earlyDelayIndex], delayLineSampleIndexOffset); - - outputValues[outputIndex] += tempTapOut * state.EarlyGain[earlyDelayIndex]; - } - - float targetPreDelayValue = 0; - - for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++) - { - channelInput[channelIndex] = inputBuffers[channelIndex].Span[sampleIndex]; - targetPreDelayValue += channelInput[channelIndex]; - } - - for (int i = 0; i < Parameter.ChannelCount; i++) - { - outputValues[i] *= state.EarlyReflectionsGain; - } - - state.PreviousPreDelayValue = (targetPreDelayValue * state.TargetPreDelayGain) + (state.PreviousPreDelayValue * state.PreviousPreDelayGain); - - state.PreDelayLine.Update(state.PreviousPreDelayValue); - - for (int i = 0; i < state.FdnDelayLines.Length; i++) - { - float fdnValue = state.FdnDelayLines[i].Read(); - - float feedbackOutputValue = fdnValue * state.DecayDirectFdnGain[i] + state.PreviousFeedbackOutputDecayed[i]; - - state.PreviousFeedbackOutputDecayed[i] = (fdnValue * state.DecayCurrentFdnGain[i]) + (feedbackOutputValue * state.DecayCurrentOutputGain[i]); - - feedbackOutputValues[i] = feedbackOutputValue; - } - - feedbackValues[0] = feedbackOutputValues[2] + feedbackOutputValues[1]; - feedbackValues[1] = -feedbackOutputValues[0] - feedbackOutputValues[3]; - feedbackValues[2] = feedbackOutputValues[0] - feedbackOutputValues[3]; - feedbackValues[3] = feedbackOutputValues[1] - feedbackOutputValues[2]; - - for (int i = 0; i < state.DecayDelays1.Length; i++) - { - float temp = state.DecayDelays1[i].Update(tapOut * state.LateReverbGain + feedbackValues[i]); - - values[i] = state.DecayDelays2[i].Update(temp); - - state.FdnDelayLines[i].Update(values[i]); - } - - for (int channelIndex = 0; channelIndex < targetOutputFeedbackIndicesTable.Length; channelIndex++) - { - int targetOutputFeedbackIndex = targetOutputFeedbackIndicesTable[channelIndex]; - - if (targetOutputFeedbackIndex >= 0) - { - outputBuffers[channelIndex].Span[sampleIndex] = (outputValues[channelIndex] + values[targetOutputFeedbackIndex] + channelInput[channelIndex] * state.DryGain); - } - } - - if (isMono) - { - outputBuffers[0].Span[sampleIndex] += values[1]; - } - - if (isSurround) - { - outputBuffers[4].Span[sampleIndex] += (outputValues[4] + state.BackLeftDelayLine.Update((values[2] - values[3]) * 0.5f) + channelInput[4] * state.DryGain); - } - } - } - - public void ProcessReverb3d(CommandList context) - { - Debug.Assert(Parameter.IsChannelCountValid()); - - if (IsEffectEnabled && Parameter.IsChannelCountValid()) - { - ReadOnlyMemory<float>[] inputBuffers = new ReadOnlyMemory<float>[Parameter.ChannelCount]; - Memory<float>[] outputBuffers = new Memory<float>[Parameter.ChannelCount]; - - for (int i = 0; i < Parameter.ChannelCount; i++) - { - inputBuffers[i] = context.GetBufferMemory(InputBufferIndices[i]); - outputBuffers[i] = context.GetBufferMemory(OutputBufferIndices[i]); - } - - switch (Parameter.ChannelCount) - { - case 1: - ProcessReverb3dMono(outputBuffers, inputBuffers, context.SampleCount); - break; - case 2: - ProcessReverb3dStereo(outputBuffers, inputBuffers, context.SampleCount); - break; - case 4: - ProcessReverb3dQuadraphonic(outputBuffers, inputBuffers, context.SampleCount); - break; - case 6: - ProcessReverb3dSurround(outputBuffers, inputBuffers, context.SampleCount); - break; - default: - throw new NotImplementedException($"{Parameter.ChannelCount}"); - } - } - else - { - for (int i = 0; i < Parameter.ChannelCount; i++) - { - if (InputBufferIndices[i] != OutputBufferIndices[i]) - { - context.GetBufferMemory(InputBufferIndices[i]).CopyTo(context.GetBufferMemory(OutputBufferIndices[i])); - } - } - } - } - - public void Process(CommandList context) - { - ref Reverb3dState state = ref State.Span[0]; - - if (IsEffectEnabled) - { - if (Parameter.ParameterStatus == UsageState.Invalid) - { - state = new Reverb3dState(ref _parameter, WorkBuffer); - } - else if (Parameter.ParameterStatus == UsageState.New) - { - state.UpdateParameter(ref _parameter); - } - } - - ProcessReverb3d(context); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/ReverbCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/ReverbCommand.cs deleted file mode 100644 index f0303ed1..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/ReverbCommand.cs +++ /dev/null @@ -1,284 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class ReverbCommand : ICommand - { - private static readonly int[] OutputEarlyIndicesTableMono = new int[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - private static readonly int[] TargetEarlyDelayLineIndicesTableMono = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - private static readonly int[] OutputIndicesTableMono = new int[4] { 0, 0, 0, 0 }; - private static readonly int[] TargetOutputFeedbackIndicesTableMono = new int[4] { 0, 1, 2, 3 }; - - private static readonly int[] OutputEarlyIndicesTableStereo = new int[10] { 0, 0, 1, 1, 0, 1, 0, 0, 1, 1 }; - private static readonly int[] TargetEarlyDelayLineIndicesTableStereo = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - private static readonly int[] OutputIndicesTableStereo = new int[4] { 0, 0, 1, 1 }; - private static readonly int[] TargetOutputFeedbackIndicesTableStereo = new int[4] { 2, 0, 3, 1 }; - - private static readonly int[] OutputEarlyIndicesTableQuadraphonic = new int[10] { 0, 0, 1, 1, 0, 1, 2, 2, 3, 3 }; - private static readonly int[] TargetEarlyDelayLineIndicesTableQuadraphonic = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - private static readonly int[] OutputIndicesTableQuadraphonic = new int[4] { 0, 1, 2, 3 }; - private static readonly int[] TargetOutputFeedbackIndicesTableQuadraphonic = new int[4] { 0, 1, 2, 3 }; - - private static readonly int[] OutputEarlyIndicesTableSurround = new int[20] { 0, 5, 0, 5, 1, 5, 1, 5, 4, 5, 4, 5, 2, 5, 2, 5, 3, 5, 3, 5 }; - private static readonly int[] TargetEarlyDelayLineIndicesTableSurround = new int[20] { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9 }; - private static readonly int[] OutputIndicesTableSurround = new int[RendererConstants.ChannelCountMax] { 0, 1, 2, 3, 4, 5 }; - private static readonly int[] TargetOutputFeedbackIndicesTableSurround = new int[RendererConstants.ChannelCountMax] { 0, 1, 2, 3, -1, 3 }; - - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.Reverb; - - public ulong EstimatedProcessingTime { get; set; } - - public ReverbParameter Parameter => _parameter; - public Memory<ReverbState> State { get; } - public ulong WorkBuffer { get; } - public ushort[] OutputBufferIndices { get; } - public ushort[] InputBufferIndices { get; } - public bool IsLongSizePreDelaySupported { get; } - - public bool IsEffectEnabled { get; } - - private ReverbParameter _parameter; - - private const int FixedPointPrecision = 14; - - public ReverbCommand(uint bufferOffset, ReverbParameter parameter, Memory<ReverbState> state, bool isEnabled, ulong workBuffer, int nodeId, bool isLongSizePreDelaySupported) - { - Enabled = true; - IsEffectEnabled = isEnabled; - NodeId = nodeId; - _parameter = parameter; - State = state; - WorkBuffer = workBuffer; - - InputBufferIndices = new ushort[RendererConstants.VoiceChannelCountMax]; - OutputBufferIndices = new ushort[RendererConstants.VoiceChannelCountMax]; - - for (int i = 0; i < Parameter.ChannelCount; i++) - { - InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]); - OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]); - } - - IsLongSizePreDelaySupported = isLongSizePreDelaySupported; - } - - private void ProcessReverbMono(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount) - { - ProcessReverbGeneric(outputBuffers, - inputBuffers, - sampleCount, - OutputEarlyIndicesTableMono, - TargetEarlyDelayLineIndicesTableMono, - TargetOutputFeedbackIndicesTableMono, - OutputIndicesTableMono); - } - - private void ProcessReverbStereo(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount) - { - ProcessReverbGeneric(outputBuffers, - inputBuffers, - sampleCount, - OutputEarlyIndicesTableStereo, - TargetEarlyDelayLineIndicesTableStereo, - TargetOutputFeedbackIndicesTableStereo, - OutputIndicesTableStereo); - } - - private void ProcessReverbQuadraphonic(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount) - { - ProcessReverbGeneric(outputBuffers, - inputBuffers, - sampleCount, - OutputEarlyIndicesTableQuadraphonic, - TargetEarlyDelayLineIndicesTableQuadraphonic, - TargetOutputFeedbackIndicesTableQuadraphonic, - OutputIndicesTableQuadraphonic); - } - - private void ProcessReverbSurround(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount) - { - ProcessReverbGeneric(outputBuffers, - inputBuffers, - sampleCount, - OutputEarlyIndicesTableSurround, - TargetEarlyDelayLineIndicesTableSurround, - TargetOutputFeedbackIndicesTableSurround, - OutputIndicesTableSurround); - } - - private void ProcessReverbGeneric(Memory<float>[] outputBuffers, ReadOnlyMemory<float>[] inputBuffers, uint sampleCount, ReadOnlySpan<int> outputEarlyIndicesTable, ReadOnlySpan<int> targetEarlyDelayLineIndicesTable, ReadOnlySpan<int> targetOutputFeedbackIndicesTable, ReadOnlySpan<int> outputIndicesTable) - { - ref ReverbState state = ref State.Span[0]; - - bool isSurround = Parameter.ChannelCount == 6; - - float reverbGain = FixedPointHelper.ToFloat(Parameter.ReverbGain, FixedPointPrecision); - float lateGain = FixedPointHelper.ToFloat(Parameter.LateGain, FixedPointPrecision); - float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); - float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision); - - float[] outputValues = new float[RendererConstants.ChannelCountMax]; - float[] feedbackValues = new float[4]; - float[] feedbackOutputValues = new float[4]; - float[] channelInput = new float[Parameter.ChannelCount]; - - for (int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) - { - outputValues.AsSpan().Fill(0); - - for (int i = 0; i < targetEarlyDelayLineIndicesTable.Length; i++) - { - int earlyDelayIndex = targetEarlyDelayLineIndicesTable[i]; - int outputIndex = outputEarlyIndicesTable[i]; - - float tapOutput = state.PreDelayLine.TapUnsafe(state.EarlyDelayTime[earlyDelayIndex], 0); - - outputValues[outputIndex] += tapOutput * state.EarlyGain[earlyDelayIndex]; - } - - if (isSurround) - { - outputValues[5] *= 0.2f; - } - - float targetPreDelayValue = 0; - - for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++) - { - channelInput[channelIndex] = inputBuffers[channelIndex].Span[sampleIndex] * 64; - targetPreDelayValue += channelInput[channelIndex] * reverbGain; - } - - state.PreDelayLine.Update(targetPreDelayValue); - - float lateValue = state.PreDelayLine.Tap(state.PreDelayLineDelayTime) * lateGain; - - for (int i = 0; i < state.FdnDelayLines.Length; i++) - { - feedbackOutputValues[i] = state.FdnDelayLines[i].Read() * state.HighFrequencyDecayDirectGain[i] + state.PreviousFeedbackOutput[i] * state.HighFrequencyDecayPreviousGain[i]; - state.PreviousFeedbackOutput[i] = feedbackOutputValues[i]; - } - - feedbackValues[0] = feedbackOutputValues[2] + feedbackOutputValues[1]; - feedbackValues[1] = -feedbackOutputValues[0] - feedbackOutputValues[3]; - feedbackValues[2] = feedbackOutputValues[0] - feedbackOutputValues[3]; - feedbackValues[3] = feedbackOutputValues[1] - feedbackOutputValues[2]; - - for (int i = 0; i < state.FdnDelayLines.Length; i++) - { - feedbackOutputValues[i] = state.DecayDelays[i].Update(feedbackValues[i] + lateValue); - state.FdnDelayLines[i].Update(feedbackOutputValues[i]); - } - - for (int i = 0; i < targetOutputFeedbackIndicesTable.Length; i++) - { - int targetOutputFeedbackIndex = targetOutputFeedbackIndicesTable[i]; - int outputIndex = outputIndicesTable[i]; - - if (targetOutputFeedbackIndex >= 0) - { - outputValues[outputIndex] += feedbackOutputValues[targetOutputFeedbackIndex]; - } - } - - if (isSurround) - { - outputValues[4] += state.BackLeftDelayLine.Update((feedbackOutputValues[2] - feedbackOutputValues[3]) * 0.5f); - } - - for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++) - { - outputBuffers[channelIndex].Span[sampleIndex] = (outputValues[channelIndex] * outGain + channelInput[channelIndex] * dryGain) / 64; - } - } - } - - private void ProcessReverb(CommandList context) - { - Debug.Assert(Parameter.IsChannelCountValid()); - - if (IsEffectEnabled && Parameter.IsChannelCountValid()) - { - ReadOnlyMemory<float>[] inputBuffers = new ReadOnlyMemory<float>[Parameter.ChannelCount]; - Memory<float>[] outputBuffers = new Memory<float>[Parameter.ChannelCount]; - - for (int i = 0; i < Parameter.ChannelCount; i++) - { - inputBuffers[i] = context.GetBufferMemory(InputBufferIndices[i]); - outputBuffers[i] = context.GetBufferMemory(OutputBufferIndices[i]); - } - - switch (Parameter.ChannelCount) - { - case 1: - ProcessReverbMono(outputBuffers, inputBuffers, context.SampleCount); - break; - case 2: - ProcessReverbStereo(outputBuffers, inputBuffers, context.SampleCount); - break; - case 4: - ProcessReverbQuadraphonic(outputBuffers, inputBuffers, context.SampleCount); - break; - case 6: - ProcessReverbSurround(outputBuffers, inputBuffers, context.SampleCount); - break; - default: - throw new NotImplementedException($"{Parameter.ChannelCount}"); - } - } - else - { - for (int i = 0; i < Parameter.ChannelCount; i++) - { - if (InputBufferIndices[i] != OutputBufferIndices[i]) - { - context.GetBufferMemory(InputBufferIndices[i]).CopyTo(context.GetBufferMemory(OutputBufferIndices[i])); - } - } - } - } - - public void Process(CommandList context) - { - ref ReverbState state = ref State.Span[0]; - - if (IsEffectEnabled) - { - if (Parameter.Status == Server.Effect.UsageState.Invalid) - { - state = new ReverbState(ref _parameter, WorkBuffer, IsLongSizePreDelaySupported); - } - else if (Parameter.Status == Server.Effect.UsageState.New) - { - state.UpdateParameter(ref _parameter); - } - } - - ProcessReverb(context); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/UpsampleCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/UpsampleCommand.cs deleted file mode 100644 index 3bfaa0f6..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/UpsampleCommand.cs +++ /dev/null @@ -1,87 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Server.Upsampler; -using System; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class UpsampleCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.Upsample; - - public ulong EstimatedProcessingTime { get; set; } - - public uint BufferCount { get; } - public uint InputBufferIndex { get; } - public uint InputSampleCount { get; } - public uint InputSampleRate { get; } - - public UpsamplerState UpsamplerInfo { get; } - - public Memory<float> OutBuffer { get; } - - public UpsampleCommand(uint bufferOffset, UpsamplerState info, uint inputCount, Span<byte> inputBufferOffset, uint bufferCount, uint sampleCount, uint sampleRate, int nodeId) - { - Enabled = true; - NodeId = nodeId; - - InputBufferIndex = 0; - OutBuffer = info.OutputBuffer; - BufferCount = bufferCount; - InputSampleCount = sampleCount; - InputSampleRate = sampleRate; - info.SourceSampleCount = inputCount; - info.InputBufferIndices = new ushort[inputCount]; - - for (int i = 0; i < inputCount; i++) - { - info.InputBufferIndices[i] = (ushort)(bufferOffset + inputBufferOffset[i]); - } - - UpsamplerInfo = info; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Span<float> GetBuffer(int index, int sampleCount) - { - return UpsamplerInfo.OutputBuffer.Span.Slice(index * sampleCount, sampleCount); - } - - public void Process(CommandList context) - { - float ratio = (float)InputSampleRate / RendererConstants.TargetSampleRate; - - uint bufferCount = Math.Min(BufferCount, UpsamplerInfo.SourceSampleCount); - - for (int i = 0; i < bufferCount; i++) - { - Span<float> inputBuffer = context.GetBuffer(UpsamplerInfo.InputBufferIndices[i]); - Span<float> outputBuffer = GetBuffer(UpsamplerInfo.InputBufferIndices[i], (int)UpsamplerInfo.SampleCount); - - float fraction = 0.0f; - - ResamplerHelper.ResampleForUpsampler(outputBuffer, inputBuffer, ratio, ref fraction, (int)(InputSampleCount / ratio)); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/VolumeCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/VolumeCommand.cs deleted file mode 100644 index b58ae1f8..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/VolumeCommand.cs +++ /dev/null @@ -1,125 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class VolumeCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.Volume; - - public ulong EstimatedProcessingTime { get; set; } - - public ushort InputBufferIndex { get; } - public ushort OutputBufferIndex { get; } - - public float Volume { get; } - - public VolumeCommand(float volume, uint bufferIndex, int nodeId) - { - Enabled = true; - NodeId = nodeId; - - InputBufferIndex = (ushort)bufferIndex; - OutputBufferIndex = (ushort)bufferIndex; - - Volume = volume; - } - - private void ProcessVolumeAvx(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer) - { - Vector256<float> volumeVec = Vector256.Create(Volume); - - ReadOnlySpan<Vector256<float>> inputVec = MemoryMarshal.Cast<float, Vector256<float>>(inputBuffer); - Span<Vector256<float>> outputVec = MemoryMarshal.Cast<float, Vector256<float>>(outputBuffer); - - int sisdStart = inputVec.Length * 8; - - for (int i = 0; i < inputVec.Length; i++) - { - outputVec[i] = Avx.Ceiling(Avx.Multiply(inputVec[i], volumeVec)); - } - - for (int i = sisdStart; i < inputBuffer.Length; i++) - { - outputBuffer[i] = FloatingPointHelper.MultiplyRoundUp(inputBuffer[i], Volume); - } - } - - private void ProcessVolumeSse41(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer) - { - Vector128<float> volumeVec = Vector128.Create(Volume); - - ReadOnlySpan<Vector128<float>> inputVec = MemoryMarshal.Cast<float, Vector128<float>>(inputBuffer); - Span<Vector128<float>> outputVec = MemoryMarshal.Cast<float, Vector128<float>>(outputBuffer); - - int sisdStart = inputVec.Length * 4; - - for (int i = 0; i < inputVec.Length; i++) - { - outputVec[i] = Sse41.Ceiling(Sse.Multiply(inputVec[i], volumeVec)); - } - - for (int i = sisdStart; i < inputBuffer.Length; i++) - { - outputBuffer[i] = FloatingPointHelper.MultiplyRoundUp(inputBuffer[i], Volume); - } - } - - private void ProcessVolume(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer) - { - if (Avx.IsSupported) - { - ProcessVolumeAvx(outputBuffer, inputBuffer); - } - else if (Sse41.IsSupported) - { - ProcessVolumeSse41(outputBuffer, inputBuffer); - } - else - { - ProcessVolumeSlowPath(outputBuffer, inputBuffer); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ProcessVolumeSlowPath(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer) - { - for (int i = 0; i < outputBuffer.Length; i++) - { - outputBuffer[i] = FloatingPointHelper.MultiplyRoundUp(inputBuffer[i], Volume); - } - } - - public void Process(CommandList context) - { - ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndex); - Span<float> outputBuffer = context.GetBuffer(OutputBufferIndex); - - ProcessVolume(outputBuffer, inputBuffer); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Command/VolumeRampCommand.cs b/Ryujinx.Audio.Renderer/Dsp/Command/VolumeRampCommand.cs deleted file mode 100644 index d07926c8..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Command/VolumeRampCommand.cs +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; - -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public class VolumeRampCommand : ICommand - { - public bool Enabled { get; set; } - - public int NodeId { get; } - - public CommandType CommandType => CommandType.VolumeRamp; - - public ulong EstimatedProcessingTime { get; set; } - - public ushort InputBufferIndex { get; } - public ushort OutputBufferIndex { get; } - - public float Volume0 { get; } - public float Volume1 { get; } - - public VolumeRampCommand(float volume0, float volume1, uint bufferIndex, int nodeId) - { - Enabled = true; - NodeId = nodeId; - - InputBufferIndex = (ushort)bufferIndex; - OutputBufferIndex = (ushort)bufferIndex; - - Volume0 = volume0; - Volume1 = volume1; - } - - private void ProcessVolumeRamp(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, int sampleCount) - { - float ramp = (Volume1 - Volume0) / sampleCount; - - float volume = Volume0; - - for (int i = 0; i < sampleCount; i++) - { - outputBuffer[i] = FloatingPointHelper.MultiplyRoundUp(inputBuffer[i], volume); - volume += ramp; - } - } - - public void Process(CommandList context) - { - ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndex); - Span<float> outputBuffer = context.GetBuffer(OutputBufferIndex); - - ProcessVolumeRamp(outputBuffer, inputBuffer, (int)context.SampleCount); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/DataSourceHelper.cs b/Ryujinx.Audio.Renderer/Dsp/DataSourceHelper.cs deleted file mode 100644 index bb583dd3..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/DataSourceHelper.cs +++ /dev/null @@ -1,408 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Common.Logging; -using Ryujinx.Memory; -using System; -using System.Buffers; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; - -namespace Ryujinx.Audio.Renderer.Dsp -{ - public static class DataSourceHelper - { - private const int FixedPointPrecision = 15; - - public class WaveBufferInformation - { - public Memory<VoiceUpdateState> State; - public uint SourceSampleRate; - public SampleFormat SampleFormat; - public float Pitch; - public DecodingBehaviour DecodingBehaviour; - public WaveBuffer[] WaveBuffers; - public ulong ExtraParameter; - public ulong ExtraParameterSize; - public int ChannelIndex; - public int ChannelCount; - public SampleRateConversionQuality SrcQuality; - } - - private static int GetPitchLimitBySrcQuality(SampleRateConversionQuality quality) - { - switch (quality) - { - case SampleRateConversionQuality.Default: - case SampleRateConversionQuality.Low: - return 4; - case SampleRateConversionQuality.High: - return 8; - default: - throw new ArgumentException($"{quality}"); - } - } - - public static void ProcessWaveBuffers(IVirtualMemoryManager memoryManager, Span<float> outputBuffer, WaveBufferInformation info, uint targetSampleRate, int sampleCount) - { - const int tempBufferSize = 0x3F00; - - ref VoiceUpdateState state = ref info.State.Span[0]; - - short[] tempBuffer = ArrayPool<short>.Shared.Rent(tempBufferSize); - - float sampleRateRatio = ((float)info.SourceSampleRate / targetSampleRate * info.Pitch); - - float fraction = state.Fraction; - int waveBufferIndex = (int)state.WaveBufferIndex; - ulong playedSampleCount = state.PlayedSampleCount; - int offset = state.Offset; - uint waveBufferConsumed = state.WaveBufferConsumed; - - int pitchMaxLength = GetPitchLimitBySrcQuality(info.SrcQuality); - - int totalNeededSize = (int)MathF.Truncate(fraction + sampleRateRatio * sampleCount); - - if (totalNeededSize + pitchMaxLength <= tempBufferSize && totalNeededSize >= 0) - { - int sourceSampleCountToProcess = sampleCount; - - int maxSampleCountPerIteration = Math.Min((int)MathF.Truncate((tempBufferSize - fraction) / sampleRateRatio), sampleCount); - - bool isStarving = false; - - int i = 0; - - while (i < sourceSampleCountToProcess) - { - int tempBufferIndex = 0; - - if (!info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion)) - { - state.Pitch.ToSpan().Slice(0, pitchMaxLength).CopyTo(tempBuffer.AsSpan()); - tempBufferIndex += pitchMaxLength; - } - - int sampleCountToProcess = Math.Min(sourceSampleCountToProcess, maxSampleCountPerIteration); - - int y = 0; - - int sampleCountToDecode = (int)MathF.Truncate(fraction + sampleRateRatio * sampleCountToProcess); - - while (y < sampleCountToDecode) - { - if (waveBufferIndex >= RendererConstants.VoiceWaveBufferCount) - { - Logger.Error?.Print(LogClass.AudioRenderer, $"Invalid WaveBuffer index {waveBufferIndex}"); - - waveBufferIndex = 0; - playedSampleCount = 0; - } - - if (!state.IsWaveBufferValid[waveBufferIndex]) - { - isStarving = true; - break; - } - - ref WaveBuffer waveBuffer = ref info.WaveBuffers[waveBufferIndex]; - - if (offset == 0 && info.SampleFormat == SampleFormat.Adpcm && waveBuffer.Context != 0) - { - state.LoopContext = memoryManager.Read<AdpcmLoopContext>(waveBuffer.Context); - } - - Span<short> tempSpan = tempBuffer.AsSpan().Slice(tempBufferIndex + y); - - int decodedSampleCount = -1; - - int targetSampleStartOffset; - int targetSampleEndOffset; - - if (state.LoopCount > 0 && waveBuffer.LoopStartSampleOffset != 0 && waveBuffer.LoopEndSampleOffset != 0 && waveBuffer.LoopStartSampleOffset <= waveBuffer.LoopEndSampleOffset) - { - targetSampleStartOffset = (int)waveBuffer.LoopStartSampleOffset; - targetSampleEndOffset = (int)waveBuffer.LoopEndSampleOffset; - } - else - { - targetSampleStartOffset = (int)waveBuffer.StartSampleOffset; - targetSampleEndOffset = (int)waveBuffer.EndSampleOffset; - } - - int targetWaveBufferSampleCount = targetSampleEndOffset - targetSampleStartOffset; - - switch (info.SampleFormat) - { - case SampleFormat.Adpcm: - ReadOnlySpan<byte> waveBufferAdpcm = ReadOnlySpan<byte>.Empty; - - if (waveBuffer.Buffer != 0 && waveBuffer.BufferSize != 0) - { - // TODO: we are possibly copying a lot of unneeded data here, we should only take what we need. - waveBufferAdpcm = memoryManager.GetSpan(waveBuffer.Buffer, (int)waveBuffer.BufferSize); - } - - ReadOnlySpan<short> coefficients = MemoryMarshal.Cast<byte, short>(memoryManager.GetSpan(info.ExtraParameter, (int)info.ExtraParameterSize)); - decodedSampleCount = AdpcmHelper.Decode(tempSpan, waveBufferAdpcm, targetSampleStartOffset, targetSampleEndOffset, offset, sampleCountToDecode - y, coefficients, ref state.LoopContext); - break; - case SampleFormat.PcmInt16: - ReadOnlySpan<short> waveBufferPcm16 = ReadOnlySpan<short>.Empty; - - if (waveBuffer.Buffer != 0 && waveBuffer.BufferSize != 0) - { - ulong bufferOffset = waveBuffer.Buffer + PcmHelper.GetBufferOffset<short>(targetSampleStartOffset, offset, info.ChannelCount); - int bufferSize = PcmHelper.GetBufferSize<short>(targetSampleStartOffset, targetSampleEndOffset, offset, sampleCountToDecode - y) * info.ChannelCount; - - waveBufferPcm16 = MemoryMarshal.Cast<byte, short>(memoryManager.GetSpan(bufferOffset, bufferSize)); - } - - decodedSampleCount = PcmHelper.Decode(tempSpan, waveBufferPcm16, targetSampleStartOffset, targetSampleEndOffset, info.ChannelIndex, info.ChannelCount); - break; - case SampleFormat.PcmFloat: - ReadOnlySpan<float> waveBufferPcmFloat = ReadOnlySpan<float>.Empty; - - if (waveBuffer.Buffer != 0 && waveBuffer.BufferSize != 0) - { - ulong bufferOffset = waveBuffer.Buffer + PcmHelper.GetBufferOffset<float>(targetSampleStartOffset, offset, info.ChannelCount); - int bufferSize = PcmHelper.GetBufferSize<float>(targetSampleStartOffset, targetSampleEndOffset, offset, sampleCountToDecode - y) * info.ChannelCount; - - waveBufferPcmFloat = MemoryMarshal.Cast<byte, float>(memoryManager.GetSpan(bufferOffset, bufferSize)); - } - - decodedSampleCount = PcmHelper.Decode(tempSpan, waveBufferPcmFloat, targetSampleStartOffset, targetSampleEndOffset, info.ChannelIndex, info.ChannelCount); - break; - default: - Logger.Warning?.Print(LogClass.AudioRenderer, $"Unsupported sample format {info.SampleFormat}"); - break; - } - - Debug.Assert(decodedSampleCount <= sampleCountToDecode); - - if (decodedSampleCount < 0) - { - Logger.Warning?.Print(LogClass.AudioRenderer, $"Decoding failed, skipping WaveBuffer"); - - state.MarkEndOfBufferWaveBufferProcessing(ref waveBuffer, ref waveBufferIndex, ref waveBufferConsumed, ref playedSampleCount); - decodedSampleCount = 0; - } - - y += decodedSampleCount; - offset += decodedSampleCount; - playedSampleCount += (uint)decodedSampleCount; - - if (offset >= targetWaveBufferSampleCount || decodedSampleCount == 0) - { - offset = 0; - - if (waveBuffer.Looping) - { - state.LoopCount++; - - if (waveBuffer.LoopCount >= 0) - { - if (decodedSampleCount == 0 || state.LoopCount > waveBuffer.LoopCount) - { - state.MarkEndOfBufferWaveBufferProcessing(ref waveBuffer, ref waveBufferIndex, ref waveBufferConsumed, ref playedSampleCount); - } - } - - if (decodedSampleCount == 0) - { - isStarving = true; - break; - } - - if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.PlayedSampleCountResetWhenLooping)) - { - playedSampleCount = 0; - } - } - else - { - state.MarkEndOfBufferWaveBufferProcessing(ref waveBuffer, ref waveBufferIndex, ref waveBufferConsumed, ref playedSampleCount); - } - } - } - - Span<float> outputSpan = outputBuffer.Slice(i); - Span<int> outputSpanInt = MemoryMarshal.Cast<float, int>(outputSpan); - - if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion)) - { - for (int j = 0; j < y; j++) - { - outputBuffer[j] = tempBuffer[j]; - } - } - else - { - Span<short> tempSpan = tempBuffer.AsSpan().Slice(tempBufferIndex + y); - - tempSpan.Slice(0, sampleCountToDecode - y).Fill(0); - - ToFloat(outputBuffer, outputSpanInt, sampleCountToProcess); - - ResamplerHelper.Resample(outputBuffer, tempBuffer, sampleRateRatio, ref fraction, sampleCountToProcess, info.SrcQuality, y != sourceSampleCountToProcess || info.Pitch != 1.0f); - - tempBuffer.AsSpan().Slice(sampleCountToDecode, pitchMaxLength).CopyTo(state.Pitch.ToSpan()); - } - - i += sampleCountToProcess; - } - - Debug.Assert(sourceSampleCountToProcess == i || !isStarving); - - state.WaveBufferConsumed = waveBufferConsumed; - state.Offset = offset; - state.PlayedSampleCount = playedSampleCount; - state.WaveBufferIndex = (uint)waveBufferIndex; - state.Fraction = fraction; - } - - ArrayPool<short>.Shared.Return(tempBuffer); - } - - private static void ToFloatAvx(Span<float> output, ReadOnlySpan<int> input, int sampleCount) - { - ReadOnlySpan<Vector256<int>> inputVec = MemoryMarshal.Cast<int, Vector256<int>>(input); - Span<Vector256<float>> outputVec = MemoryMarshal.Cast<float, Vector256<float>>(output); - - int sisdStart = inputVec.Length * 8; - - for (int i = 0; i < inputVec.Length; i++) - { - outputVec[i] = Avx.ConvertToVector256Single(inputVec[i]); - } - - for (int i = sisdStart; i < sampleCount; i++) - { - output[i] = input[i]; - } - } - - private static void ToFloatSse2(Span<float> output, ReadOnlySpan<int> input, int sampleCount) - { - ReadOnlySpan<Vector128<int>> inputVec = MemoryMarshal.Cast<int, Vector128<int>>(input); - Span<Vector128<float>> outputVec = MemoryMarshal.Cast<float, Vector128<float>>(output); - - int sisdStart = inputVec.Length * 4; - - for (int i = 0; i < inputVec.Length; i++) - { - outputVec[i] = Sse2.ConvertToVector128Single(inputVec[i]); - } - - for (int i = sisdStart; i < sampleCount; i++) - { - output[i] = input[i]; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ToFloatSlow(Span<float> output, ReadOnlySpan<int> input, int sampleCount) - { - for (int i = 0; i < sampleCount; i++) - { - output[i] = input[i]; - } - } - - public static void ToFloat(Span<float> output, ReadOnlySpan<int> input, int sampleCount) - { - if (Avx.IsSupported) - { - ToFloatAvx(output, input, sampleCount); - } - else if (Sse2.IsSupported) - { - ToFloatSse2(output, input, sampleCount); - } - else - { - ToFloatSlow(output, input, sampleCount); - } - } - - public static void ToIntAvx(Span<int> output, ReadOnlySpan<float> input, int sampleCount) - { - ReadOnlySpan<Vector256<float>> inputVec = MemoryMarshal.Cast<float, Vector256<float>>(input); - Span<Vector256<int>> outputVec = MemoryMarshal.Cast<int, Vector256<int>>(output); - - int sisdStart = inputVec.Length * 8; - - for (int i = 0; i < inputVec.Length; i++) - { - outputVec[i] = Avx.ConvertToVector256Int32(inputVec[i]); - } - - for (int i = sisdStart; i < sampleCount; i++) - { - output[i] = (int)input[i]; - } - } - - public static void ToIntSse2(Span<int> output, ReadOnlySpan<float> input, int sampleCount) - { - ReadOnlySpan<Vector128<float>> inputVec = MemoryMarshal.Cast<float, Vector128<float>>(input); - Span<Vector128<int>> outputVec = MemoryMarshal.Cast<int, Vector128<int>>(output); - - int sisdStart = inputVec.Length * 4; - - for (int i = 0; i < inputVec.Length; i++) - { - outputVec[i] = Avx.ConvertToVector128Int32(inputVec[i]); - } - - for (int i = sisdStart; i < sampleCount; i++) - { - output[i] = (int)input[i]; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ToIntSlow(Span<int> output, ReadOnlySpan<float> input, int sampleCount) - { - for (int i = 0; i < sampleCount; i++) - { - output[i] = (int)input[i]; - } - } - - public static void ToInt(Span<int> output, ReadOnlySpan<float> input, int sampleCount) - { - if (Avx.IsSupported) - { - ToIntAvx(output, input, sampleCount); - } - else if (Sse2.IsSupported) - { - ToIntSse2(output, input, sampleCount); - } - else - { - ToIntSlow(output, input, sampleCount); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Effect/DecayDelay.cs b/Ryujinx.Audio.Renderer/Dsp/Effect/DecayDelay.cs deleted file mode 100644 index 8a815c56..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Effect/DecayDelay.cs +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Dsp.Effect -{ - public class DecayDelay : IDelayLine - { - private readonly IDelayLine _delayLine; - - public uint CurrentSampleCount => _delayLine.CurrentSampleCount; - - public uint SampleCountMax => _delayLine.SampleCountMax; - - private float _decayRate; - - public DecayDelay(IDelayLine delayLine) - { - _decayRate = 0.0f; - _delayLine = delayLine; - } - - public void SetDecayRate(float decayRate) - { - _decayRate = decayRate; - } - - public float Update(float value) - { - float delayLineValue = _delayLine.Read(); - float processedValue = value - (_decayRate * delayLineValue); - - return _delayLine.Update(processedValue) + processedValue * _decayRate; - } - - public void SetDelay(float delayTime) - { - _delayLine.SetDelay(delayTime); - } - - public float Read() - { - return _delayLine.Read(); - } - - public float TapUnsafe(uint sampleIndex, int offset) - { - return _delayLine.TapUnsafe(sampleIndex, offset); - } - - public float Tap(uint sampleIndex) - { - return _delayLine.Tap(sampleIndex); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Effect/DelayLine.cs b/Ryujinx.Audio.Renderer/Dsp/Effect/DelayLine.cs deleted file mode 100644 index d178e699..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Effect/DelayLine.cs +++ /dev/null @@ -1,95 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; - -namespace Ryujinx.Audio.Renderer.Dsp.Effect -{ - public class DelayLine : IDelayLine - { - private float[] _workBuffer; - private uint _sampleRate; - private uint _currentSampleIndex; - private uint _lastSampleIndex; - - public uint CurrentSampleCount { get; private set; } - public uint SampleCountMax { get; private set; } - - public DelayLine(uint sampleRate, float delayTimeMax) - { - _sampleRate = sampleRate; - SampleCountMax = IDelayLine.GetSampleCount(_sampleRate, delayTimeMax); - _workBuffer = new float[SampleCountMax]; - - SetDelay(delayTimeMax); - } - - private void ConfigureDelay(uint targetSampleCount) - { - CurrentSampleCount = Math.Min(SampleCountMax, targetSampleCount); - _currentSampleIndex = 0; - - if (CurrentSampleCount == 0) - { - _lastSampleIndex = 0; - } - else - { - _lastSampleIndex = CurrentSampleCount - 1; - } - } - - public void SetDelay(float delayTime) - { - ConfigureDelay(IDelayLine.GetSampleCount(_sampleRate, delayTime)); - } - - public float Read() - { - return _workBuffer[_currentSampleIndex]; - } - - public float Update(float value) - { - float output = Read(); - - _workBuffer[_currentSampleIndex++] = value; - - if (_currentSampleIndex >= _lastSampleIndex) - { - _currentSampleIndex = 0; - } - - return output; - } - - public float TapUnsafe(uint sampleIndex, int offset) - { - return IDelayLine.Tap(_workBuffer, (int)_currentSampleIndex, (int)sampleIndex + offset, (int)CurrentSampleCount); - } - - public float Tap(uint sampleIndex) - { - if (sampleIndex >= CurrentSampleCount) - { - sampleIndex = CurrentSampleCount - 1; - } - - return TapUnsafe(sampleIndex, -1); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Effect/DelayLineReverb3d.cs b/Ryujinx.Audio.Renderer/Dsp/Effect/DelayLineReverb3d.cs deleted file mode 100644 index a30dcc63..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Effect/DelayLineReverb3d.cs +++ /dev/null @@ -1,93 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Dsp.Effect -{ - public class DelayLine3d : IDelayLine - { - private float[] _workBuffer; - private uint _sampleRate; - private uint _currentSampleIndex; - private uint _lastSampleIndex; - - public uint CurrentSampleCount { get; private set; } - public uint SampleCountMax { get; private set; } - - public DelayLine3d(uint sampleRate, float delayTimeMax) - { - _sampleRate = sampleRate; - SampleCountMax = IDelayLine.GetSampleCount(_sampleRate, delayTimeMax); - _workBuffer = new float[SampleCountMax + 1]; - - SetDelay(delayTimeMax); - } - - private void ConfigureDelay(uint targetSampleCount) - { - if (SampleCountMax >= targetSampleCount) - { - CurrentSampleCount = targetSampleCount; - _lastSampleIndex = (_currentSampleIndex + targetSampleCount) % (SampleCountMax + 1); - } - } - - public void SetDelay(float delayTime) - { - ConfigureDelay(IDelayLine.GetSampleCount(_sampleRate, delayTime)); - } - - public float Read() - { - return _workBuffer[_currentSampleIndex]; - } - - public float Update(float value) - { - Debug.Assert(!float.IsNaN(value) && !float.IsInfinity(value)); - - _workBuffer[_lastSampleIndex++] = value; - - float output = Read(); - - _currentSampleIndex++; - - if (_currentSampleIndex >= SampleCountMax) - { - _currentSampleIndex = 0; - } - - if (_lastSampleIndex >= SampleCountMax) - { - _lastSampleIndex = 0; - } - - return output; - } - - public float TapUnsafe(uint sampleIndex, int offset) - { - return IDelayLine.Tap(_workBuffer, (int)_lastSampleIndex, (int)sampleIndex + offset, (int)SampleCountMax + 1); - } - - public float Tap(uint sampleIndex) - { - return TapUnsafe(sampleIndex, -1); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/Effect/IDelayLine.cs b/Ryujinx.Audio.Renderer/Dsp/Effect/IDelayLine.cs deleted file mode 100644 index ac59445e..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/Effect/IDelayLine.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Dsp.Effect -{ - public interface IDelayLine - { - uint CurrentSampleCount { get; } - uint SampleCountMax { get; } - - void SetDelay(float delayTime); - float Read(); - float Update(float value); - - float TapUnsafe(uint sampleIndex, int offset); - float Tap(uint sampleIndex); - - public static float Tap(Span<float> workBuffer, int baseIndex, int sampleIndex, int delaySampleCount) - { - int targetIndex = baseIndex - sampleIndex; - - if (targetIndex < 0) - { - targetIndex += delaySampleCount; - } - - return workBuffer[targetIndex]; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint GetSampleCount(uint sampleRate, float delayTime) - { - return (uint)MathF.Round(sampleRate * delayTime); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/FixedPointHelper.cs b/Ryujinx.Audio.Renderer/Dsp/FixedPointHelper.cs deleted file mode 100644 index 0afd8926..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/FixedPointHelper.cs +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Dsp -{ - public static class FixedPointHelper - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ToInt(long value, int qBits) - { - return (int)(value >> qBits); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float ToFloat(long value, int qBits) - { - return (float)value / (1 << qBits); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ToFixed(float value, int qBits) - { - return (int)(value * (1 << qBits)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int RoundUpAndToInt(long value, int qBits) - { - int half = 1 << (qBits - 1); - - return ToInt(value + half, qBits); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/FloatingPointHelper.cs b/Ryujinx.Audio.Renderer/Dsp/FloatingPointHelper.cs deleted file mode 100644 index b143d8f9..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/FloatingPointHelper.cs +++ /dev/null @@ -1,84 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Dsp -{ - public static class FloatingPointHelper - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float MultiplyRoundDown(float a, float b) - { - return RoundDown(a * b); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float RoundDown(float a) - { - return MathF.Round(a, 0); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float RoundUp(float a) - { - return MathF.Round(a); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float MultiplyRoundUp(float a, float b) - { - return RoundUp(a * b); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Pow10(float x) - { - // NOTE: Nintendo implementation uses Q15 and a LUT for this, we don't. - // As such, we support the same ranges as Nintendo to avoid unexpected behaviours. - if (x >= 0.0f) - { - return 1.0f; - } - else if (x <= -5.3f) - { - return 0.0f; - } - - return MathF.Pow(10, x); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float DegreesToRadians(float degrees) - { - return degrees * MathF.PI / 180.0f; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Cos(float value) - { - return MathF.Cos(DegreesToRadians(value)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Sin(float value) - { - return MathF.Sin(DegreesToRadians(value)); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/PcmHelper.cs b/Ryujinx.Audio.Renderer/Dsp/PcmHelper.cs deleted file mode 100644 index 12c1d475..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/PcmHelper.cs +++ /dev/null @@ -1,95 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Dsp -{ - public static class PcmHelper - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetCountToDecode(int startSampleOffset, int endSampleOffset, int offset, int count) - { - return Math.Min(count, endSampleOffset - startSampleOffset - offset); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong GetBufferOffset<T>(int startSampleOffset, int offset, int channelCount) where T : unmanaged - { - return (ulong)(Unsafe.SizeOf<T>() * channelCount * (startSampleOffset + offset)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetBufferSize<T>(int startSampleOffset, int endSampleOffset, int offset, int count) where T : unmanaged - { - return GetCountToDecode(startSampleOffset, endSampleOffset, offset, count) * Unsafe.SizeOf<T>(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Decode(Span<short> output, ReadOnlySpan<short> input, int startSampleOffset, int endSampleOffset, int channelIndex, int channelCount) - { - if (input.IsEmpty || endSampleOffset < startSampleOffset) - { - return 0; - } - - int decodedCount = input.Length / channelCount; - - for (int i = 0; i < decodedCount; i++) - { - output[i] = input[i * channelCount + channelIndex]; - } - - return decodedCount; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Decode(Span<short> output, ReadOnlySpan<float> input, int startSampleOffset, int endSampleOffset, int channelIndex, int channelCount) - { - if (input.IsEmpty || endSampleOffset < startSampleOffset) - { - return 0; - } - - int decodedCount = input.Length / channelCount; - - for (int i = 0; i < decodedCount; i++) - { - output[i] = (short)(input[i * channelCount + channelIndex] * short.MaxValue); - } - - return decodedCount; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static short Saturate(float value) - { - if (value > short.MaxValue) - { - return short.MaxValue; - } - - if (value < short.MinValue) - { - return short.MinValue; - } - - return (short)value; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/ResamplerHelper.cs b/Ryujinx.Audio.Renderer/Dsp/ResamplerHelper.cs deleted file mode 100644 index d40da412..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/ResamplerHelper.cs +++ /dev/null @@ -1,624 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; - -namespace Ryujinx.Audio.Renderer.Dsp -{ - public static class ResamplerHelper - { - #region "Default Quality Lookup Tables" - private static short[] _normalCurveLut0 = new short[] - { - 6600, 19426, 6722, 3, 6479, 19424, 6845, 9, 6359, 19419, 6968, 15, 6239, 19412, 7093, 22, - 6121, 19403, 7219, 28, 6004, 19391, 7345, 34, 5888, 19377, 7472, 41, 5773, 19361, 7600, 48, - 5659, 19342, 7728, 55, 5546, 19321, 7857, 62, 5434, 19298, 7987, 69, 5323, 19273, 8118, 77, - 5213, 19245, 8249, 84, 5104, 19215, 8381, 92, 4997, 19183, 8513, 101, 4890, 19148, 8646, 109, - 4785, 19112, 8780, 118, 4681, 19073, 8914, 127, 4579, 19031, 9048, 137, 4477, 18988, 9183, 147, - 4377, 18942, 9318, 157, 4277, 18895, 9454, 168, 4179, 18845, 9590, 179, 4083, 18793, 9726, 190, - 3987, 18738, 9863, 202, 3893, 18682, 10000, 215, 3800, 18624, 10137, 228, 3709, 18563, 10274, 241, - 3618, 18500, 10411, 255, 3529, 18436, 10549, 270, 3441, 18369, 10687, 285, 3355, 18300, 10824, 300, - 3269, 18230, 10962, 317, 3186, 18157, 11100, 334, 3103, 18082, 11238, 351, 3022, 18006, 11375, 369, - 2942, 17927, 11513, 388, 2863, 17847, 11650, 408, 2785, 17765, 11788, 428, 2709, 17681, 11925, 449, - 2635, 17595, 12062, 471, 2561, 17507, 12198, 494, 2489, 17418, 12334, 517, 2418, 17327, 12470, 541, - 2348, 17234, 12606, 566, 2280, 17140, 12741, 592, 2213, 17044, 12876, 619, 2147, 16946, 13010, 647, - 2083, 16846, 13144, 675, 2020, 16745, 13277, 704, 1958, 16643, 13409, 735, 1897, 16539, 13541, 766, - 1838, 16434, 13673, 798, 1780, 16327, 13803, 832, 1723, 16218, 13933, 866, 1667, 16109, 14062, 901, - 1613, 15998, 14191, 937, 1560, 15885, 14318, 975, 1508, 15772, 14445, 1013, 1457, 15657, 14571, 1052, - 1407, 15540, 14695, 1093, 1359, 15423, 14819, 1134, 1312, 15304, 14942, 1177, 1266, 15185, 15064, 1221, - 1221, 15064, 15185, 1266, 1177, 14942, 15304, 1312, 1134, 14819, 15423, 1359, 1093, 14695, 15540, 1407, - 1052, 14571, 15657, 1457, 1013, 14445, 15772, 1508, 975, 14318, 15885, 1560, 937, 14191, 15998, 1613, - 901, 14062, 16109, 1667, 866, 13933, 16218, 1723, 832, 13803, 16327, 1780, 798, 13673, 16434, 1838, - 766, 13541, 16539, 1897, 735, 13409, 16643, 1958, 704, 13277, 16745, 2020, 675, 13144, 16846, 2083, - 647, 13010, 16946, 2147, 619, 12876, 17044, 2213, 592, 12741, 17140, 2280, 566, 12606, 17234, 2348, - 541, 12470, 17327, 2418, 517, 12334, 17418, 2489, 494, 12198, 17507, 2561, 471, 12062, 17595, 2635, - 449, 11925, 17681, 2709, 428, 11788, 17765, 2785, 408, 11650, 17847, 2863, 388, 11513, 17927, 2942, - 369, 11375, 18006, 3022, 351, 11238, 18082, 3103, 334, 11100, 18157, 3186, 317, 10962, 18230, 3269, - 300, 10824, 18300, 3355, 285, 10687, 18369, 3441, 270, 10549, 18436, 3529, 255, 10411, 18500, 3618, - 241, 10274, 18563, 3709, 228, 10137, 18624, 3800, 215, 10000, 18682, 3893, 202, 9863, 18738, 3987, - 190, 9726, 18793, 4083, 179, 9590, 18845, 4179, 168, 9454, 18895, 4277, 157, 9318, 18942, 4377, - 147, 9183, 18988, 4477, 137, 9048, 19031, 4579, 127, 8914, 19073, 4681, 118, 8780, 19112, 4785, - 109, 8646, 19148, 4890, 101, 8513, 19183, 4997, 92, 8381, 19215, 5104, 84, 8249, 19245, 5213, - 77, 8118, 19273, 5323, 69, 7987, 19298, 5434, 62, 7857, 19321, 5546, 55, 7728, 19342, 5659, - 48, 7600, 19361, 5773, 41, 7472, 19377, 5888, 34, 7345, 19391, 6004, 28, 7219, 19403, 6121, - 22, 7093, 19412, 6239, 15, 6968, 19419, 6359, 9, 6845, 19424, 6479, 3, 6722, 19426, 6600 - }; - - private static short[] _normalCurveLut1 = new short[] - { - -68, 32639, 69, -5, -200, 32630, 212, -15, -328, 32613, 359, -26, -450, 32586, 512, -36, - -568, 32551, 669, -47, -680, 32507, 832, -58, -788, 32454, 1000, -69, -891, 32393, 1174, -80, - -990, 32323, 1352, -92, -1084, 32244, 1536, -103, -1173, 32157, 1724, -115, -1258, 32061, 1919, -128, - -1338, 31956, 2118, -140, -1414, 31844, 2322, -153, -1486, 31723, 2532, -167, -1554, 31593, 2747, -180, - -1617, 31456, 2967, -194, -1676, 31310, 3192, -209, -1732, 31157, 3422, -224, -1783, 30995, 3657, -240, - -1830, 30826, 3897, -256, -1874, 30649, 4143, -272, -1914, 30464, 4393, -289, -1951, 30272, 4648, -307, - -1984, 30072, 4908, -325, -2014, 29866, 5172, -343, -2040, 29652, 5442, -362, -2063, 29431, 5716, -382, - -2083, 29203, 5994, -403, -2100, 28968, 6277, -424, -2114, 28727, 6565, -445, -2125, 28480, 6857, -468, - -2133, 28226, 7153, -490, -2139, 27966, 7453, -514, -2142, 27700, 7758, -538, -2142, 27428, 8066, -563, - -2141, 27151, 8378, -588, -2136, 26867, 8694, -614, -2130, 26579, 9013, -641, -2121, 26285, 9336, -668, - -2111, 25987, 9663, -696, -2098, 25683, 9993, -724, -2084, 25375, 10326, -753, -2067, 25063, 10662, -783, - -2049, 24746, 11000, -813, -2030, 24425, 11342, -844, -2009, 24100, 11686, -875, -1986, 23771, 12033, -907, - -1962, 23438, 12382, -939, -1937, 23103, 12733, -972, -1911, 22764, 13086, -1005, -1883, 22422, 13441, -1039, - -1855, 22077, 13798, -1072, -1825, 21729, 14156, -1107, -1795, 21380, 14516, -1141, -1764, 21027, 14877, -1176, - -1732, 20673, 15239, -1211, -1700, 20317, 15602, -1246, -1667, 19959, 15965, -1282, -1633, 19600, 16329, -1317, - -1599, 19239, 16694, -1353, -1564, 18878, 17058, -1388, -1530, 18515, 17423, -1424, -1495, 18151, 17787, -1459, - -1459, 17787, 18151, -1495, -1424, 17423, 18515, -1530, -1388, 17058, 18878, -1564, -1353, 16694, 19239, -1599, - -1317, 16329, 19600, -1633, -1282, 15965, 19959, -1667, -1246, 15602, 20317, -1700, -1211, 15239, 20673, -1732, - -1176, 14877, 21027, -1764, -1141, 14516, 21380, -1795, -1107, 14156, 21729, -1825, -1072, 13798, 22077, -1855, - -1039, 13441, 22422, -1883, -1005, 13086, 22764, -1911, -972, 12733, 23103, -1937, -939, 12382, 23438, -1962, - -907, 12033, 23771, -1986, -875, 11686, 24100, -2009, -844, 11342, 24425, -2030, -813, 11000, 24746, -2049, - -783, 10662, 25063, -2067, -753, 10326, 25375, -2084, -724, 9993, 25683, -2098, -696, 9663, 25987, -2111, - -668, 9336, 26285, -2121, -641, 9013, 26579, -2130, -614, 8694, 26867, -2136, -588, 8378, 27151, -2141, - -563, 8066, 27428, -2142, -538, 7758, 27700, -2142, -514, 7453, 27966, -2139, -490, 7153, 28226, -2133, - -468, 6857, 28480, -2125, -445, 6565, 28727, -2114, -424, 6277, 28968, -2100, -403, 5994, 29203, -2083, - -382, 5716, 29431, -2063, -362, 5442, 29652, -2040, -343, 5172, 29866, -2014, -325, 4908, 30072, -1984, - -307, 4648, 30272, -1951, -289, 4393, 30464, -1914, -272, 4143, 30649, -1874, -256, 3897, 30826, -1830, - -240, 3657, 30995, -1783, -224, 3422, 31157, -1732, -209, 3192, 31310, -1676, -194, 2967, 31456, -1617, - -180, 2747, 31593, -1554, -167, 2532, 31723, -1486, -153, 2322, 31844, -1414, -140, 2118, 31956, -1338, - -128, 1919, 32061, -1258, -115, 1724, 32157, -1173, -103, 1536, 32244, -1084, -92, 1352, 32323, -990, - -80, 1174, 32393, -891, -69, 1000, 32454, -788, -58, 832, 32507, -680, -47, 669, 32551, -568, - -36, 512, 32586, -450, -26, 359, 32613, -328, -15, 212, 32630, -200, -5, 69, 32639, -68 - }; - - private static short[] _normalCurveLut2 = new short[] - { - 3195, 26287, 3329, -32, 3064, 26281, 3467, -34, 2936, 26270, 3608, -38, 2811, 26253, 3751, -42, - 2688, 26230, 3897, -46, 2568, 26202, 4046, -50, 2451, 26169, 4199, -54, 2338, 26130, 4354, -58, - 2227, 26085, 4512, -63, 2120, 26035, 4673, -67, 2015, 25980, 4837, -72, 1912, 25919, 5004, -76, - 1813, 25852, 5174, -81, 1716, 25780, 5347, -87, 1622, 25704, 5522, -92, 1531, 25621, 5701, -98, - 1442, 25533, 5882, -103, 1357, 25440, 6066, -109, 1274, 25342, 6253, -115, 1193, 25239, 6442, -121, - 1115, 25131, 6635, -127, 1040, 25018, 6830, -133, 967, 24899, 7027, -140, 897, 24776, 7227, -146, - 829, 24648, 7430, -153, 764, 24516, 7635, -159, 701, 24379, 7842, -166, 641, 24237, 8052, -174, - 583, 24091, 8264, -181, 526, 23940, 8478, -187, 472, 23785, 8695, -194, 420, 23626, 8914, -202, - 371, 23462, 9135, -209, 324, 23295, 9358, -215, 279, 23123, 9583, -222, 236, 22948, 9809, -230, - 194, 22769, 10038, -237, 154, 22586, 10269, -243, 117, 22399, 10501, -250, 81, 22208, 10735, -258, - 47, 22015, 10970, -265, 15, 21818, 11206, -271, -16, 21618, 11444, -277, -44, 21415, 11684, -283, - -71, 21208, 11924, -290, -97, 20999, 12166, -296, -121, 20786, 12409, -302, -143, 20571, 12653, -306, - -163, 20354, 12898, -311, -183, 20134, 13143, -316, -201, 19911, 13389, -321, -218, 19686, 13635, -325, - -234, 19459, 13882, -328, -248, 19230, 14130, -332, -261, 18998, 14377, -335, -273, 18765, 14625, -337, - -284, 18531, 14873, -339, -294, 18295, 15121, -341, -302, 18057, 15369, -341, -310, 17817, 15617, -341, - -317, 17577, 15864, -340, -323, 17335, 16111, -340, -328, 17092, 16357, -338, -332, 16848, 16603, -336, - -336, 16603, 16848, -332, -338, 16357, 17092, -328, -340, 16111, 17335, -323, -340, 15864, 17577, -317, - -341, 15617, 17817, -310, -341, 15369, 18057, -302, -341, 15121, 18295, -294, -339, 14873, 18531, -284, - -337, 14625, 18765, -273, -335, 14377, 18998, -261, -332, 14130, 19230, -248, -328, 13882, 19459, -234, - -325, 13635, 19686, -218, -321, 13389, 19911, -201, -316, 13143, 20134, -183, -311, 12898, 20354, -163, - -306, 12653, 20571, -143, -302, 12409, 20786, -121, -296, 12166, 20999, -97, -290, 11924, 21208, -71, - -283, 11684, 21415, -44, -277, 11444, 21618, -16, -271, 11206, 21818, 15, -265, 10970, 22015, 47, - -258, 10735, 22208, 81, -250, 10501, 22399, 117, -243, 10269, 22586, 154, -237, 10038, 22769, 194, - -230, 9809, 22948, 236, -222, 9583, 23123, 279, -215, 9358, 23295, 324, -209, 9135, 23462, 371, - -202, 8914, 23626, 420, -194, 8695, 23785, 472, -187, 8478, 23940, 526, -181, 8264, 24091, 583, - -174, 8052, 24237, 641, -166, 7842, 24379, 701, -159, 7635, 24516, 764, -153, 7430, 24648, 829, - -146, 7227, 24776, 897, -140, 7027, 24899, 967, -133, 6830, 25018, 1040, -127, 6635, 25131, 1115, - -121, 6442, 25239, 1193, -115, 6253, 25342, 1274, -109, 6066, 25440, 1357, -103, 5882, 25533, 1442, - -98, 5701, 25621, 1531, -92, 5522, 25704, 1622, -87, 5347, 25780, 1716, -81, 5174, 25852, 1813, - -76, 5004, 25919, 1912, -72, 4837, 25980, 2015, -67, 4673, 26035, 2120, -63, 4512, 26085, 2227, - -58, 4354, 26130, 2338, -54, 4199, 26169, 2451, -50, 4046, 26202, 2568, -46, 3897, 26230, 2688, - -42, 3751, 26253, 2811, -38, 3608, 26270, 2936, -34, 3467, 26281, 3064, -32, 3329, 26287, 3195 - }; - #endregion - - #region "High Quality Lookup Tables" - private static short[] _highCurveLut0 = new short[] - { - -582, -23, 8740, 16386, 8833, 8, -590, 0, -573, -54, 8647, 16385, 8925, 40, -598, -1, - -565, -84, 8555, 16383, 9018, 72, -606, -1, -557, -113, 8462, 16379, 9110, 105, -614, -2, - -549, -142, 8370, 16375, 9203, 139, -622, -2, -541, -170, 8277, 16369, 9295, 173, -630, -3, - -533, -198, 8185, 16362, 9387, 208, -638, -4, -525, -225, 8093, 16354, 9480, 244, -646, -5, - -516, -251, 8000, 16344, 9572, 280, -654, -5, -508, -277, 7908, 16334, 9664, 317, -662, -6, - -500, -302, 7816, 16322, 9756, 355, -670, -7, -492, -327, 7724, 16310, 9847, 393, -678, -8, - -484, -351, 7632, 16296, 9939, 432, -686, -9, -476, -374, 7540, 16281, 10030, 471, -694, -10, - -468, -397, 7449, 16265, 10121, 511, -702, -11, -460, -419, 7357, 16247, 10212, 552, -709, -13, - -452, -441, 7266, 16229, 10303, 593, -717, -14, -445, -462, 7175, 16209, 10394, 635, -724, -15, - -437, -483, 7084, 16189, 10484, 678, -732, -16, -429, -503, 6994, 16167, 10574, 722, -739, -18, - -421, -523, 6903, 16144, 10664, 766, -747, -19, -414, -542, 6813, 16120, 10754, 810, -754, -21, - -406, -560, 6723, 16095, 10843, 856, -761, -22, -398, -578, 6633, 16068, 10932, 902, -768, -24, - -391, -596, 6544, 16041, 11021, 949, -775, -26, -383, -612, 6454, 16012, 11109, 996, -782, -27, - -376, -629, 6366, 15983, 11197, 1044, -789, -29, -368, -645, 6277, 15952, 11285, 1093, -796, -31, - -361, -660, 6189, 15920, 11372, 1142, -802, -33, -354, -675, 6100, 15887, 11459, 1192, -809, -35, - -347, -689, 6013, 15853, 11546, 1243, -815, -37, -339, -703, 5925, 15818, 11632, 1294, -821, -39, - -332, -717, 5838, 15782, 11718, 1346, -827, -41, -325, -730, 5751, 15745, 11803, 1399, -833, -43, - -318, -742, 5665, 15707, 11888, 1452, -839, -46, -312, -754, 5579, 15668, 11973, 1506, -845, -48, - -305, -766, 5493, 15627, 12057, 1561, -850, -50, -298, -777, 5408, 15586, 12140, 1616, -855, -53, - -291, -787, 5323, 15544, 12224, 1672, -861, -56, -285, -798, 5239, 15500, 12306, 1729, -866, -58, - -278, -807, 5155, 15456, 12388, 1786, -871, -61, -272, -817, 5071, 15410, 12470, 1844, -875, -64, - -265, -826, 4988, 15364, 12551, 1902, -880, -67, -259, -834, 4905, 15317, 12631, 1962, -884, -70, - -253, -842, 4823, 15268, 12711, 2022, -888, -73, -247, -850, 4741, 15219, 12790, 2082, -892, -76, - -241, -857, 4659, 15168, 12869, 2143, -896, -79, -235, -864, 4578, 15117, 12947, 2205, -899, -82, - -229, -870, 4498, 15065, 13025, 2267, -903, -85, -223, -876, 4417, 15012, 13102, 2331, -906, -89, - -217, -882, 4338, 14958, 13178, 2394, -909, -92, -211, -887, 4259, 14903, 13254, 2459, -911, -96, - -206, -892, 4180, 14847, 13329, 2523, -914, -100, -200, -896, 4102, 14790, 13403, 2589, -916, -103, - -195, -900, 4024, 14732, 13477, 2655, -918, -107, -190, -904, 3947, 14673, 13550, 2722, -919, -111, - -184, -908, 3871, 14614, 13622, 2789, -921, -115, -179, -911, 3795, 14553, 13693, 2857, -922, -119, - -174, -913, 3719, 14492, 13764, 2926, -923, -123, -169, -916, 3644, 14430, 13834, 2995, -923, -127, - -164, -918, 3570, 14367, 13904, 3065, -924, -132, -159, -920, 3496, 14303, 13972, 3136, -924, -136, - -154, -921, 3423, 14239, 14040, 3207, -924, -140, -150, -922, 3350, 14173, 14107, 3278, -923, -145, - -145, -923, 3278, 14107, 14173, 3350, -922, -150, -140, -924, 3207, 14040, 14239, 3423, -921, -154, - -136, -924, 3136, 13972, 14303, 3496, -920, -159, -132, -924, 3065, 13904, 14367, 3570, -918, -164, - -127, -923, 2995, 13834, 14430, 3644, -916, -169, -123, -923, 2926, 13764, 14492, 3719, -913, -174, - -119, -922, 2857, 13693, 14553, 3795, -911, -179, -115, -921, 2789, 13622, 14614, 3871, -908, -184, - -111, -919, 2722, 13550, 14673, 3947, -904, -190, -107, -918, 2655, 13477, 14732, 4024, -900, -195, - -103, -916, 2589, 13403, 14790, 4102, -896, -200, -100, -914, 2523, 13329, 14847, 4180, -892, -206, - -96, -911, 2459, 13254, 14903, 4259, -887, -211, -92, -909, 2394, 13178, 14958, 4338, -882, -217, - -89, -906, 2331, 13102, 15012, 4417, -876, -223, -85, -903, 2267, 13025, 15065, 4498, -870, -229, - -82, -899, 2205, 12947, 15117, 4578, -864, -235, -79, -896, 2143, 12869, 15168, 4659, -857, -241, - -76, -892, 2082, 12790, 15219, 4741, -850, -247, -73, -888, 2022, 12711, 15268, 4823, -842, -253, - -70, -884, 1962, 12631, 15317, 4905, -834, -259, -67, -880, 1902, 12551, 15364, 4988, -826, -265, - -64, -875, 1844, 12470, 15410, 5071, -817, -272, -61, -871, 1786, 12388, 15456, 5155, -807, -278, - -58, -866, 1729, 12306, 15500, 5239, -798, -285, -56, -861, 1672, 12224, 15544, 5323, -787, -291, - -53, -855, 1616, 12140, 15586, 5408, -777, -298, -50, -850, 1561, 12057, 15627, 5493, -766, -305, - -48, -845, 1506, 11973, 15668, 5579, -754, -312, -46, -839, 1452, 11888, 15707, 5665, -742, -318, - -43, -833, 1399, 11803, 15745, 5751, -730, -325, -41, -827, 1346, 11718, 15782, 5838, -717, -332, - -39, -821, 1294, 11632, 15818, 5925, -703, -339, -37, -815, 1243, 11546, 15853, 6013, -689, -347, - -35, -809, 1192, 11459, 15887, 6100, -675, -354, -33, -802, 1142, 11372, 15920, 6189, -660, -361, - -31, -796, 1093, 11285, 15952, 6277, -645, -368, -29, -789, 1044, 11197, 15983, 6366, -629, -376, - -27, -782, 996, 11109, 16012, 6454, -612, -383, -26, -775, 949, 11021, 16041, 6544, -596, -391, - -24, -768, 902, 10932, 16068, 6633, -578, -398, -22, -761, 856, 10843, 16095, 6723, -560, -406, - -21, -754, 810, 10754, 16120, 6813, -542, -414, -19, -747, 766, 10664, 16144, 6903, -523, -421, - -18, -739, 722, 10574, 16167, 6994, -503, -429, -16, -732, 678, 10484, 16189, 7084, -483, -437, - -15, -724, 635, 10394, 16209, 7175, -462, -445, -14, -717, 593, 10303, 16229, 7266, -441, -452, - -13, -709, 552, 10212, 16247, 7357, -419, -460, -11, -702, 511, 10121, 16265, 7449, -397, -468, - -10, -694, 471, 10030, 16281, 7540, -374, -476, -9, -686, 432, 9939, 16296, 7632, -351, -484, - -8, -678, 393, 9847, 16310, 7724, -327, -492, -7, -670, 355, 9756, 16322, 7816, -302, -500, - -6, -662, 317, 9664, 16334, 7908, -277, -508, -5, -654, 280, 9572, 16344, 8000, -251, -516, - -5, -646, 244, 9480, 16354, 8093, -225, -525, -4, -638, 208, 9387, 16362, 8185, -198, -533, - -3, -630, 173, 9295, 16369, 8277, -170, -541, -2, -622, 139, 9203, 16375, 8370, -142, -549, - -2, -614, 105, 9110, 16379, 8462, -113, -557, -1, -606, 72, 9018, 16383, 8555, -84, -565, - -1, -598, 40, 8925, 16385, 8647, -54, -573, 0, -590, 8, 8833, 16386, 8740, -23, -582, - }; - - private static short[] _highCurveLut1 = new short[] - { - -12, 47, -134, 32767, 81, -16, 2, 0, -26, 108, -345, 32760, 301, -79, 17, -1, - -40, 168, -552, 32745, 526, -144, 32, -2, -53, 226, -753, 32723, 755, -210, 47, -3, - -66, 284, -950, 32694, 989, -277, 63, -5, -78, 340, -1143, 32658, 1226, -346, 79, -6, - -90, 394, -1331, 32615, 1469, -415, 96, -8, -101, 447, -1514, 32564, 1715, -486, 113, -9, - -112, 499, -1692, 32506, 1966, -557, 130, -11, -123, 550, -1865, 32441, 2221, -630, 148, -13, - -133, 599, -2034, 32369, 2480, -703, 166, -14, -143, 646, -2198, 32290, 2743, -778, 185, -16, - -152, 693, -2357, 32204, 3010, -853, 204, -18, -162, 738, -2512, 32110, 3281, -929, 223, -20, - -170, 781, -2662, 32010, 3555, -1007, 242, -23, -178, 823, -2807, 31903, 3834, -1084, 262, -25, - -186, 864, -2947, 31789, 4116, -1163, 282, -27, -194, 903, -3082, 31668, 4403, -1242, 303, -30, - -201, 940, -3213, 31540, 4692, -1322, 323, -32, -207, 977, -3339, 31406, 4985, -1403, 344, -35, - -214, 1011, -3460, 31265, 5282, -1484, 365, -37, -220, 1045, -3577, 31117, 5582, -1566, 387, -40, - -225, 1077, -3688, 30963, 5885, -1648, 409, -43, -230, 1107, -3796, 30802, 6191, -1730, 431, -46, - -235, 1136, -3898, 30635, 6501, -1813, 453, -49, -240, 1164, -3996, 30462, 6813, -1896, 475, -52, - -244, 1190, -4089, 30282, 7128, -1980, 498, -55, -247, 1215, -4178, 30097, 7446, -2064, 520, -58, - -251, 1239, -4262, 29905, 7767, -2148, 543, -62, -254, 1261, -4342, 29707, 8091, -2231, 566, -65, - -257, 1281, -4417, 29503, 8416, -2315, 589, -69, -259, 1301, -4488, 29293, 8745, -2399, 613, -72, - -261, 1319, -4555, 29078, 9075, -2483, 636, -76, -263, 1336, -4617, 28857, 9408, -2567, 659, -80, - -265, 1351, -4674, 28631, 9743, -2651, 683, -83, -266, 1365, -4728, 28399, 10080, -2734, 706, -87, - -267, 1378, -4777, 28161, 10418, -2817, 730, -91, -267, 1389, -4822, 27919, 10759, -2899, 753, -95, - -268, 1400, -4863, 27671, 11100, -2981, 777, -99, -268, 1409, -4900, 27418, 11444, -3063, 800, -103, - -268, 1416, -4933, 27161, 11789, -3144, 824, -107, -267, 1423, -4962, 26898, 12135, -3224, 847, -112, - -267, 1428, -4987, 26631, 12482, -3303, 870, -116, -266, 1433, -5008, 26359, 12830, -3382, 893, -120, - -265, 1436, -5026, 26083, 13179, -3460, 916, -125, -264, 1438, -5039, 25802, 13529, -3537, 939, -129, - -262, 1438, -5049, 25517, 13880, -3613, 962, -133, -260, 1438, -5055, 25228, 14231, -3687, 984, -138, - -258, 1437, -5058, 24935, 14582, -3761, 1006, -142, -256, 1435, -5058, 24639, 14934, -3833, 1028, -147, - -254, 1431, -5053, 24338, 15286, -3904, 1049, -151, -252, 1427, -5046, 24034, 15638, -3974, 1071, -155, - -249, 1422, -5035, 23726, 15989, -4042, 1091, -160, -246, 1416, -5021, 23415, 16341, -4109, 1112, -164, - -243, 1408, -5004, 23101, 16691, -4174, 1132, -169, -240, 1400, -4984, 22783, 17042, -4237, 1152, -173, - -237, 1392, -4960, 22463, 17392, -4299, 1171, -178, -234, 1382, -4934, 22140, 17740, -4358, 1190, -182, - -230, 1371, -4905, 21814, 18088, -4416, 1209, -186, -227, 1360, -4873, 21485, 18435, -4472, 1226, -191, - -223, 1348, -4839, 21154, 18781, -4526, 1244, -195, -219, 1335, -4801, 20821, 19125, -4578, 1260, -199, - -215, 1321, -4761, 20486, 19468, -4627, 1277, -203, -211, 1307, -4719, 20148, 19809, -4674, 1292, -207, - -207, 1292, -4674, 19809, 20148, -4719, 1307, -211, -203, 1277, -4627, 19468, 20486, -4761, 1321, -215, - -199, 1260, -4578, 19125, 20821, -4801, 1335, -219, -195, 1244, -4526, 18781, 21154, -4839, 1348, -223, - -191, 1226, -4472, 18435, 21485, -4873, 1360, -227, -186, 1209, -4416, 18088, 21814, -4905, 1371, -230, - -182, 1190, -4358, 17740, 22140, -4934, 1382, -234, -178, 1171, -4299, 17392, 22463, -4960, 1392, -237, - -173, 1152, -4237, 17042, 22783, -4984, 1400, -240, -169, 1132, -4174, 16691, 23101, -5004, 1408, -243, - -164, 1112, -4109, 16341, 23415, -5021, 1416, -246, -160, 1091, -4042, 15989, 23726, -5035, 1422, -249, - -155, 1071, -3974, 15638, 24034, -5046, 1427, -252, -151, 1049, -3904, 15286, 24338, -5053, 1431, -254, - -147, 1028, -3833, 14934, 24639, -5058, 1435, -256, -142, 1006, -3761, 14582, 24935, -5058, 1437, -258, - -138, 984, -3687, 14231, 25228, -5055, 1438, -260, -133, 962, -3613, 13880, 25517, -5049, 1438, -262, - -129, 939, -3537, 13529, 25802, -5039, 1438, -264, -125, 916, -3460, 13179, 26083, -5026, 1436, -265, - -120, 893, -3382, 12830, 26359, -5008, 1433, -266, -116, 870, -3303, 12482, 26631, -4987, 1428, -267, - -112, 847, -3224, 12135, 26898, -4962, 1423, -267, -107, 824, -3144, 11789, 27161, -4933, 1416, -268, - -103, 800, -3063, 11444, 27418, -4900, 1409, -268, -99, 777, -2981, 11100, 27671, -4863, 1400, -268, - -95, 753, -2899, 10759, 27919, -4822, 1389, -267, -91, 730, -2817, 10418, 28161, -4777, 1378, -267, - -87, 706, -2734, 10080, 28399, -4728, 1365, -266, -83, 683, -2651, 9743, 28631, -4674, 1351, -265, - -80, 659, -2567, 9408, 28857, -4617, 1336, -263, -76, 636, -2483, 9075, 29078, -4555, 1319, -261, - -72, 613, -2399, 8745, 29293, -4488, 1301, -259, -69, 589, -2315, 8416, 29503, -4417, 1281, -257, - -65, 566, -2231, 8091, 29707, -4342, 1261, -254, -62, 543, -2148, 7767, 29905, -4262, 1239, -251, - -58, 520, -2064, 7446, 30097, -4178, 1215, -247, -55, 498, -1980, 7128, 30282, -4089, 1190, -244, - -52, 475, -1896, 6813, 30462, -3996, 1164, -240, -49, 453, -1813, 6501, 30635, -3898, 1136, -235, - -46, 431, -1730, 6191, 30802, -3796, 1107, -230, -43, 409, -1648, 5885, 30963, -3688, 1077, -225, - -40, 387, -1566, 5582, 31117, -3577, 1045, -220, -37, 365, -1484, 5282, 31265, -3460, 1011, -214, - -35, 344, -1403, 4985, 31406, -3339, 977, -207, -32, 323, -1322, 4692, 31540, -3213, 940, -201, - -30, 303, -1242, 4403, 31668, -3082, 903, -194, -27, 282, -1163, 4116, 31789, -2947, 864, -186, - -25, 262, -1084, 3834, 31903, -2807, 823, -178, -23, 242, -1007, 3555, 32010, -2662, 781, -170, - -20, 223, -929, 3281, 32110, -2512, 738, -162, -18, 204, -853, 3010, 32204, -2357, 693, -152, - -16, 185, -778, 2743, 32290, -2198, 646, -143, -14, 166, -703, 2480, 32369, -2034, 599, -133, - -13, 148, -630, 2221, 32441, -1865, 550, -123, -11, 130, -557, 1966, 32506, -1692, 499, -112, - -9, 113, -486, 1715, 32564, -1514, 447, -101, -8, 96, -415, 1469, 32615, -1331, 394, -90, - -6, 79, -346, 1226, 32658, -1143, 340, -78, -5, 63, -277, 989, 32694, -950, 284, -66, - -3, 47, -210, 755, 32723, -753, 226, -53, -2, 32, -144, 526, 32745, -552, 168, -40, - -1, 17, -79, 301, 32760, -345, 108, -26, 0, 2, -16, 81, 32767, -134, 47, -12, - }; - - private static short[] _highCurveLut2 = new short[] - { - 418, -2538, 6118, 24615, 6298, -2563, 417, 0, 420, -2512, 5939, 24611, 6479, -2588, 415, 1, - 421, -2485, 5761, 24605, 6662, -2612, 412, 2, 422, -2458, 5585, 24595, 6846, -2635, 409, 3, - 423, -2430, 5410, 24582, 7030, -2658, 406, 4, 423, -2402, 5236, 24565, 7216, -2680, 403, 5, - 423, -2373, 5064, 24546, 7403, -2701, 399, 6, 423, -2343, 4893, 24523, 7591, -2721, 395, 7, - 423, -2313, 4724, 24496, 7780, -2741, 391, 8, 422, -2283, 4556, 24467, 7970, -2759, 386, 9, - 421, -2252, 4390, 24434, 8161, -2777, 381, 11, 420, -2221, 4225, 24398, 8353, -2794, 376, 12, - 419, -2190, 4062, 24359, 8545, -2810, 370, 14, 418, -2158, 3900, 24316, 8739, -2825, 364, 15, - 416, -2126, 3740, 24271, 8933, -2839, 358, 17, 414, -2093, 3582, 24222, 9127, -2851, 351, 19, - 412, -2060, 3425, 24170, 9323, -2863, 344, 21, 410, -2027, 3270, 24115, 9519, -2874, 336, 22, - 407, -1993, 3117, 24056, 9715, -2884, 328, 24, 404, -1960, 2966, 23995, 9912, -2893, 319, 26, - 402, -1926, 2816, 23930, 10110, -2900, 311, 29, 398, -1892, 2668, 23863, 10308, -2907, 301, 31, - 395, -1858, 2522, 23792, 10506, -2912, 292, 33, 392, -1823, 2378, 23718, 10705, -2916, 282, 35, - 389, -1789, 2235, 23641, 10904, -2919, 271, 38, 385, -1754, 2095, 23561, 11103, -2920, 261, 40, - 381, -1719, 1956, 23478, 11303, -2921, 249, 43, 377, -1684, 1819, 23393, 11502, -2920, 238, 45, - 373, -1649, 1684, 23304, 11702, -2917, 225, 48, 369, -1615, 1551, 23212, 11902, -2914, 213, 51, - 365, -1580, 1420, 23118, 12102, -2909, 200, 54, 361, -1545, 1291, 23020, 12302, -2902, 186, 57, - 356, -1510, 1163, 22920, 12502, -2895, 173, 60, 352, -1475, 1038, 22817, 12702, -2885, 158, 63, - 347, -1440, 915, 22711, 12901, -2875, 143, 66, 342, -1405, 793, 22602, 13101, -2863, 128, 69, - 338, -1370, 674, 22491, 13300, -2849, 113, 73, 333, -1335, 557, 22377, 13499, -2834, 97, 76, - 328, -1301, 441, 22260, 13698, -2817, 80, 80, 323, -1266, 328, 22141, 13896, -2799, 63, 83, - 318, -1232, 217, 22019, 14094, -2779, 46, 87, 313, -1197, 107, 21894, 14291, -2758, 28, 91, - 307, -1163, 0, 21767, 14488, -2735, 9, 95, 302, -1129, -105, 21637, 14684, -2710, -9, 98, - 297, -1096, -208, 21506, 14879, -2684, -29, 102, 292, -1062, -310, 21371, 15074, -2656, -48, 106, - 286, -1029, -409, 21234, 15268, -2626, -69, 111, 281, -996, -506, 21095, 15461, -2595, -89, 115, - 276, -963, -601, 20954, 15654, -2562, -110, 119, 270, -930, -694, 20810, 15846, -2527, -132, 123, - 265, -898, -785, 20664, 16036, -2490, -154, 128, 260, -866, -874, 20516, 16226, -2452, -176, 132, - 254, -834, -961, 20366, 16415, -2411, -199, 137, 249, -803, -1046, 20213, 16602, -2369, -222, 141, - 243, -771, -1129, 20059, 16789, -2326, -246, 146, 238, -740, -1209, 19902, 16974, -2280, -270, 151, - 233, -710, -1288, 19744, 17158, -2232, -294, 156, 227, -680, -1365, 19583, 17341, -2183, -319, 160, - 222, -650, -1440, 19421, 17523, -2132, -345, 165, 217, -620, -1513, 19257, 17703, -2079, -370, 170, - 211, -591, -1583, 19091, 17882, -2023, -396, 175, 206, -562, -1652, 18923, 18059, -1966, -423, 180, - 201, -533, -1719, 18754, 18235, -1907, -450, 185, 196, -505, -1784, 18582, 18410, -1847, -477, 191, - 191, -477, -1847, 18410, 18582, -1784, -505, 196, 185, -450, -1907, 18235, 18754, -1719, -533, 201, - 180, -423, -1966, 18059, 18923, -1652, -562, 206, 175, -396, -2023, 17882, 19091, -1583, -591, 211, - 170, -370, -2079, 17703, 19257, -1513, -620, 217, 165, -345, -2132, 17523, 19421, -1440, -650, 222, - 160, -319, -2183, 17341, 19583, -1365, -680, 227, 156, -294, -2232, 17158, 19744, -1288, -710, 233, - 151, -270, -2280, 16974, 19902, -1209, -740, 238, 146, -246, -2326, 16789, 20059, -1129, -771, 243, - 141, -222, -2369, 16602, 20213, -1046, -803, 249, 137, -199, -2411, 16415, 20366, -961, -834, 254, - 132, -176, -2452, 16226, 20516, -874, -866, 260, 128, -154, -2490, 16036, 20664, -785, -898, 265, - 123, -132, -2527, 15846, 20810, -694, -930, 270, 119, -110, -2562, 15654, 20954, -601, -963, 276, - 115, -89, -2595, 15461, 21095, -506, -996, 281, 111, -69, -2626, 15268, 21234, -409, -1029, 286, - 106, -48, -2656, 15074, 21371, -310, -1062, 292, 102, -29, -2684, 14879, 21506, -208, -1096, 297, - 98, -9, -2710, 14684, 21637, -105, -1129, 302, 95, 9, -2735, 14488, 21767, 0, -1163, 307, - 91, 28, -2758, 14291, 21894, 107, -1197, 313, 87, 46, -2779, 14094, 22019, 217, -1232, 318, - 83, 63, -2799, 13896, 22141, 328, -1266, 323, 80, 80, -2817, 13698, 22260, 441, -1301, 328, - 76, 97, -2834, 13499, 22377, 557, -1335, 333, 73, 113, -2849, 13300, 22491, 674, -1370, 338, - 69, 128, -2863, 13101, 22602, 793, -1405, 342, 66, 143, -2875, 12901, 22711, 915, -1440, 347, - 63, 158, -2885, 12702, 22817, 1038, -1475, 352, 60, 173, -2895, 12502, 22920, 1163, -1510, 356, - 57, 186, -2902, 12302, 23020, 1291, -1545, 361, 54, 200, -2909, 12102, 23118, 1420, -1580, 365, - 51, 213, -2914, 11902, 23212, 1551, -1615, 369, 48, 225, -2917, 11702, 23304, 1684, -1649, 373, - 45, 238, -2920, 11502, 23393, 1819, -1684, 377, 43, 249, -2921, 11303, 23478, 1956, -1719, 381, - 40, 261, -2920, 11103, 23561, 2095, -1754, 385, 38, 271, -2919, 10904, 23641, 2235, -1789, 389, - 35, 282, -2916, 10705, 23718, 2378, -1823, 392, 33, 292, -2912, 10506, 23792, 2522, -1858, 395, - 31, 301, -2907, 10308, 23863, 2668, -1892, 398, 29, 311, -2900, 10110, 23930, 2816, -1926, 402, - 26, 319, -2893, 9912, 23995, 2966, -1960, 404, 24, 328, -2884, 9715, 24056, 3117, -1993, 407, - 22, 336, -2874, 9519, 24115, 3270, -2027, 410, 21, 344, -2863, 9323, 24170, 3425, -2060, 412, - 19, 351, -2851, 9127, 24222, 3582, -2093, 414, 17, 358, -2839, 8933, 24271, 3740, -2126, 416, - 15, 364, -2825, 8739, 24316, 3900, -2158, 418, 14, 370, -2810, 8545, 24359, 4062, -2190, 419, - 12, 376, -2794, 8353, 24398, 4225, -2221, 420, 11, 381, -2777, 8161, 24434, 4390, -2252, 421, - 9, 386, -2759, 7970, 24467, 4556, -2283, 422, 8, 391, -2741, 7780, 24496, 4724, -2313, 423, - 7, 395, -2721, 7591, 24523, 4893, -2343, 423, 6, 399, -2701, 7403, 24546, 5064, -2373, 423, - 5, 403, -2680, 7216, 24565, 5236, -2402, 423, 4, 406, -2658, 7030, 24582, 5410, -2430, 423, - 3, 409, -2635, 6846, 24595, 5585, -2458, 422, 2, 412, -2612, 6662, 24605, 5761, -2485, 421, - 1, 415, -2588, 6479, 24611, 5939, -2512, 420, 0, 417, -2563, 6298, 24615, 6118, -2538, 418, - }; - #endregion - - private static float[] _normalCurveLut0F; - private static float[] _normalCurveLut1F; - private static float[] _normalCurveLut2F; - - private static float[] _highCurveLut0F; - private static float[] _highCurveLut1F; - private static float[] _highCurveLut2F; - - static ResamplerHelper() - { - _normalCurveLut0F = _normalCurveLut0.Select(x => x / 32768f).ToArray(); - _normalCurveLut1F = _normalCurveLut1.Select(x => x / 32768f).ToArray(); - _normalCurveLut2F = _normalCurveLut2.Select(x => x / 32768f).ToArray(); - - _highCurveLut0F = _highCurveLut0.Select(x => x / 32768f).ToArray(); - _highCurveLut1F = _highCurveLut1.Select(x => x / 32768f).ToArray(); - _highCurveLut2F = _highCurveLut2.Select(x => x / 32768f).ToArray(); - } - - private const int FixedPointPrecision = 15; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Resample(Span<float> outputBuffer, ReadOnlySpan<short> inputBuffer, float ratio, ref float fraction, int sampleCount, SampleRateConversionQuality srcQuality, bool needPitch) - { - switch (srcQuality) - { - case SampleRateConversionQuality.Default: - ResampleDefaultQuality(outputBuffer, inputBuffer, ratio, ref fraction, sampleCount, needPitch); - break; - case SampleRateConversionQuality.Low: - ResampleLowQuality(outputBuffer, inputBuffer, ratio, ref fraction, sampleCount); - break; - case SampleRateConversionQuality.High: - ResampleHighQuality(outputBuffer, inputBuffer, ratio, ref fraction, sampleCount); - break; - default: - throw new NotImplementedException($"{srcQuality}"); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ReadOnlySpan<float> GetDefaultParameter(float ratio) - { - if (ratio <= 1.0f) - { - return _normalCurveLut1F; - } - else if (ratio > 1.333313f) - { - return _normalCurveLut0F; - } - - return _normalCurveLut2F; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe static void ResampleDefaultQuality(Span<float> outputBuffer, ReadOnlySpan<short> inputBuffer, float ratio, ref float fraction, int sampleCount, bool needPitch) - { - ReadOnlySpan<float> parameters = GetDefaultParameter(ratio); - - int inputBufferIndex = 0, i = 0; - - // TODO: REV8 fast path (when needPitch == false the input index progression is constant + we need SIMD) - - if (Sse41.IsSupported) - { - if (ratio == 1f) - { - fixed (short* pInput = inputBuffer) - { - fixed (float* pOutput = outputBuffer, pParameters = parameters) - { - Vector128<float> parameter = Sse.LoadVector128(pParameters); - - for (; i < (sampleCount & ~3); i += 4) - { - Vector128<int> intInput0 = Sse41.ConvertToVector128Int32(pInput + (uint)i); - Vector128<int> intInput1 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 1); - Vector128<int> intInput2 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 2); - Vector128<int> intInput3 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 3); - - Vector128<float> input0 = Sse2.ConvertToVector128Single(intInput0); - Vector128<float> input1 = Sse2.ConvertToVector128Single(intInput1); - Vector128<float> input2 = Sse2.ConvertToVector128Single(intInput2); - Vector128<float> input3 = Sse2.ConvertToVector128Single(intInput3); - - Vector128<float> mix0 = Sse.Multiply(input0, parameter); - Vector128<float> mix1 = Sse.Multiply(input1, parameter); - Vector128<float> mix2 = Sse.Multiply(input2, parameter); - Vector128<float> mix3 = Sse.Multiply(input3, parameter); - - Vector128<float> mix01 = Sse3.HorizontalAdd(mix0, mix1); - Vector128<float> mix23 = Sse3.HorizontalAdd(mix2, mix3); - - Vector128<float> mix0123 = Sse3.HorizontalAdd(mix01, mix23); - - Sse.Store(pOutput + (uint)i, Sse41.RoundToNearestInteger(mix0123)); - } - } - } - - inputBufferIndex = i; - } - else - { - fixed (short* pInput = inputBuffer) - { - fixed (float* pOutput = outputBuffer, pParameters = parameters) - { - for (; i < (sampleCount & ~3); i += 4) - { - uint baseIndex0 = (uint)(fraction * 128) * 4; - uint inputIndex0 = (uint)inputBufferIndex; - - fraction += ratio; - - uint baseIndex1 = ((uint)(fraction * 128) & 127) * 4; - uint inputIndex1 = (uint)inputBufferIndex + (uint)fraction; - - fraction += ratio; - - uint baseIndex2 = ((uint)(fraction * 128) & 127) * 4; - uint inputIndex2 = (uint)inputBufferIndex + (uint)fraction; - - fraction += ratio; - - uint baseIndex3 = ((uint)(fraction * 128) & 127) * 4; - uint inputIndex3 = (uint)inputBufferIndex + (uint)fraction; - - fraction += ratio; - inputBufferIndex += (int)fraction; - - // Only keep lower part (safe as fraction isn't supposed to be negative) - fraction -= (int)fraction; - - Vector128<float> parameter0 = Sse.LoadVector128(pParameters + baseIndex0); - Vector128<float> parameter1 = Sse.LoadVector128(pParameters + baseIndex1); - Vector128<float> parameter2 = Sse.LoadVector128(pParameters + baseIndex2); - Vector128<float> parameter3 = Sse.LoadVector128(pParameters + baseIndex3); - - Vector128<int> intInput0 = Sse41.ConvertToVector128Int32(pInput + inputIndex0); - Vector128<int> intInput1 = Sse41.ConvertToVector128Int32(pInput + inputIndex1); - Vector128<int> intInput2 = Sse41.ConvertToVector128Int32(pInput + inputIndex2); - Vector128<int> intInput3 = Sse41.ConvertToVector128Int32(pInput + inputIndex3); - - Vector128<float> input0 = Sse2.ConvertToVector128Single(intInput0); - Vector128<float> input1 = Sse2.ConvertToVector128Single(intInput1); - Vector128<float> input2 = Sse2.ConvertToVector128Single(intInput2); - Vector128<float> input3 = Sse2.ConvertToVector128Single(intInput3); - - Vector128<float> mix0 = Sse.Multiply(input0, parameter0); - Vector128<float> mix1 = Sse.Multiply(input1, parameter1); - Vector128<float> mix2 = Sse.Multiply(input2, parameter2); - Vector128<float> mix3 = Sse.Multiply(input3, parameter3); - - Vector128<float> mix01 = Sse3.HorizontalAdd(mix0, mix1); - Vector128<float> mix23 = Sse3.HorizontalAdd(mix2, mix3); - - Vector128<float> mix0123 = Sse3.HorizontalAdd(mix01, mix23); - - Sse.Store(pOutput + (uint)i, Sse41.RoundToNearestInteger(mix0123)); - } - } - } - } - } - - for (; i < sampleCount; i++) - { - int baseIndex = (int)(fraction * 128) * 4; - ReadOnlySpan<float> parameter = parameters.Slice(baseIndex, 4); - ReadOnlySpan<short> currentInput = inputBuffer.Slice(inputBufferIndex, 4); - - outputBuffer[i] = (float)Math.Round(currentInput[0] * parameter[0] + - currentInput[1] * parameter[1] + - currentInput[2] * parameter[2] + - currentInput[3] * parameter[3]); - - fraction += ratio; - inputBufferIndex += (int)fraction; - - // Only keep lower part (safe as fraction isn't supposed to be negative) - fraction -= (int)fraction; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ReadOnlySpan<float> GetHighParameter(float ratio) - { - if (ratio <= 1.0f) - { - return _highCurveLut1F; - } - else if (ratio > 1.333313f) - { - return _highCurveLut0F; - } - - return _highCurveLut2F; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ResampleHighQuality(Span<float> outputBuffer, ReadOnlySpan<short> inputBuffer, float ratio, ref float fraction, int sampleCount) - { - ReadOnlySpan<float> parameters = GetHighParameter(ratio); - - int inputBufferIndex = 0; - - // TODO: fast path - - for (int i = 0; i < sampleCount; i++) - { - int baseIndex = (int)(fraction * 128) * 8; - ReadOnlySpan<float> parameter = parameters.Slice(baseIndex, 8); - ReadOnlySpan<short> currentInput = inputBuffer.Slice(inputBufferIndex, 8); - - outputBuffer[i] = (float)Math.Round(currentInput[0] * parameter[0] + - currentInput[1] * parameter[1] + - currentInput[2] * parameter[2] + - currentInput[3] * parameter[3] + - currentInput[4] * parameter[4] + - currentInput[5] * parameter[5] + - currentInput[6] * parameter[6] + - currentInput[7] * parameter[7]); - - fraction += ratio; - inputBufferIndex += (int)MathF.Truncate(fraction); - - fraction -= (int)fraction; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ResampleLowQuality(Span<float> outputBuffer, ReadOnlySpan<short> inputBuffer, float ratio, ref float fraction, int sampleCount) - { - int inputBufferIndex = 0; - - for (int i = 0; i < sampleCount; i++) - { - int outputData = inputBuffer[inputBufferIndex]; - - if (fraction > 1.0f) - { - outputData = inputBuffer[inputBufferIndex + 1]; - } - - outputBuffer[i] = outputData; - - fraction += ratio; - inputBufferIndex += (int)MathF.Truncate(fraction); - - fraction -= (int)fraction; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ResampleForUpsampler(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, float ratio, ref float fraction, int sampleCount) - { - // TODO: use a bandwidth filter to have better resampling. - int inputBufferIndex = 0; - - for (int i = 0; i < sampleCount; i++) - { - float outputData = inputBuffer[inputBufferIndex]; - - if (fraction > 1.0f) - { - outputData = inputBuffer[inputBufferIndex + 1]; - } - - outputBuffer[i] = outputData; - - fraction += ratio; - inputBufferIndex += (int)MathF.Truncate(fraction); - - fraction -= (int)fraction; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/State/AdpcmLoopContext.cs b/Ryujinx.Audio.Renderer/Dsp/State/AdpcmLoopContext.cs deleted file mode 100644 index 695b32d2..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/State/AdpcmLoopContext.cs +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Dsp.State -{ - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 6)] - public struct AdpcmLoopContext - { - public short PredScale; - public short History0; - public short History1; - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/State/AuxiliaryBufferHeader.cs b/Ryujinx.Audio.Renderer/Dsp/State/AuxiliaryBufferHeader.cs deleted file mode 100644 index 3cf24302..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/State/AuxiliaryBufferHeader.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Dsp.State -{ - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x40)] - public struct AuxiliaryBufferHeader - { - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0xC)] - public struct AuxiliaryBufferInfo - { - private const uint ReadOffsetPosition = 0x0; - private const uint WriteOffsetPosition = 0x4; - - public uint ReadOffset; - public uint WriteOffset; - private uint _reserved; - - public static uint GetReadOffset(IVirtualMemoryManager manager, ulong bufferAddress) - { - return manager.Read<uint>(bufferAddress + ReadOffsetPosition); - } - - public static uint GetWriteOffset(IVirtualMemoryManager manager, ulong bufferAddress) - { - return manager.Read<uint>(bufferAddress + WriteOffsetPosition); - } - - public static void SetReadOffset(IVirtualMemoryManager manager, ulong bufferAddress, uint value) - { - manager.Write(bufferAddress + ReadOffsetPosition, value); - } - - public static void SetWriteOffset(IVirtualMemoryManager manager, ulong bufferAddress, uint value) - { - manager.Write(bufferAddress + WriteOffsetPosition, value); - } - } - - public AuxiliaryBufferInfo BufferInfo; - public unsafe fixed uint Unknown[13]; - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/State/BiquadFilterState.cs b/Ryujinx.Audio.Renderer/Dsp/State/BiquadFilterState.cs deleted file mode 100644 index 9677333d..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/State/BiquadFilterState.cs +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Dsp.State -{ - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] - public struct BiquadFilterState - { - public float Z1; - public float Z2; - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/State/DelayState.cs b/Ryujinx.Audio.Renderer/Dsp/State/DelayState.cs deleted file mode 100644 index 7b694fb0..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/State/DelayState.cs +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp.Effect; -using Ryujinx.Audio.Renderer.Parameter.Effect; - -namespace Ryujinx.Audio.Renderer.Dsp.State -{ - public class DelayState - { - public DelayLine[] DelayLines { get; } - public float[] LowPassZ { get; set; } - public float FeedbackGain { get; private set; } - public float DelayFeedbackBaseGain { get; private set; } - public float DelayFeedbackCrossGain { get; private set; } - public float LowPassFeedbackGain { get; private set; } - public float LowPassBaseGain { get; private set; } - - private const int FixedPointPrecision = 14; - - public DelayState(ref DelayParameter parameter, ulong workBuffer) - { - DelayLines = new DelayLine[parameter.ChannelCount]; - LowPassZ = new float[parameter.ChannelCount]; - - uint sampleRate = (uint)FixedPointHelper.ToInt(parameter.SampleRate, FixedPointPrecision) / 1000; - - for (int i = 0; i < DelayLines.Length; i++) - { - DelayLines[i] = new DelayLine(sampleRate, parameter.DelayTimeMax); - DelayLines[i].SetDelay(parameter.DelayTime); - LowPassZ[0] = 0; - } - - UpdateParameter(ref parameter); - } - - public void UpdateParameter(ref DelayParameter parameter) - { - FeedbackGain = FixedPointHelper.ToFloat(parameter.FeedbackGain, FixedPointPrecision) * 0.98f; - - float channelSpread = FixedPointHelper.ToFloat(parameter.ChannelSpread, FixedPointPrecision); - - DelayFeedbackBaseGain = (1.0f - channelSpread) * FeedbackGain; - - if (parameter.ChannelCount == 4 || parameter.ChannelCount == 6) - { - DelayFeedbackCrossGain = channelSpread * 0.5f * FeedbackGain; - } - else - { - DelayFeedbackCrossGain = channelSpread * FeedbackGain; - } - - LowPassFeedbackGain = 0.95f * FixedPointHelper.ToFloat(parameter.LowPassAmount, FixedPointPrecision); - LowPassBaseGain = 1.0f - LowPassFeedbackGain; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/State/Reverb3dState.cs b/Ryujinx.Audio.Renderer/Dsp/State/Reverb3dState.cs deleted file mode 100644 index be0f9734..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/State/Reverb3dState.cs +++ /dev/null @@ -1,136 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp.Effect; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using System; - -namespace Ryujinx.Audio.Renderer.Dsp.State -{ - public class Reverb3dState - { - private readonly float[] FdnDelayMinTimes = new float[4] { 5.0f, 6.0f, 13.0f, 14.0f }; - private readonly float[] FdnDelayMaxTimes = new float[4] { 45.704f, 82.782f, 149.94f, 271.58f }; - private readonly float[] DecayDelayMaxTimes1 = new float[4] { 17.0f, 13.0f, 9.0f, 7.0f }; - private readonly float[] DecayDelayMaxTimes2 = new float[4] { 19.0f, 11.0f, 10.0f, 6.0f }; - private readonly float[] EarlyDelayTimes = new float[20] { 0.017136f, 0.059154f, 0.16173f, 0.39019f, 0.42526f, 0.45541f, 0.68974f, 0.74591f, 0.83384f, 0.8595f, 0.0f, 0.075024f, 0.16879f, 0.2999f, 0.33744f, 0.3719f, 0.59901f, 0.71674f, 0.81786f, 0.85166f }; - public readonly float[] EarlyGain = new float[20] { 0.67096f, 0.61027f, 1.0f, 0.35680f, 0.68361f, 0.65978f, 0.51939f, 0.24712f, 0.45945f, 0.45021f, 0.64196f, 0.54879f, 0.92925f, 0.38270f, 0.72867f, 0.69794f, 0.5464f, 0.24563f, 0.45214f, 0.44042f }; - - public IDelayLine[] FdnDelayLines { get; } - public DecayDelay[] DecayDelays1 { get; } - public DecayDelay[] DecayDelays2 { get; } - public IDelayLine PreDelayLine { get; } - public IDelayLine BackLeftDelayLine { get; } - public float DryGain { get; private set; } - public uint[] EarlyDelayTime { get; private set; } - public float PreviousPreDelayValue { get; set; } - public float PreviousPreDelayGain { get; private set; } - public float TargetPreDelayGain { get; private set; } - public float EarlyReflectionsGain { get; private set; } - public float LateReverbGain { get; private set; } - public uint ReflectionDelayTime { get; private set; } - public float EchoLateReverbDecay { get; private set; } - public float[] DecayDirectFdnGain { get; private set; } - public float[] DecayCurrentFdnGain { get; private set; } - public float[] DecayCurrentOutputGain { get; private set; } - public float[] PreviousFeedbackOutputDecayed { get; private set; } - - public Reverb3dState(ref Reverb3dParameter parameter, ulong workBuffer) - { - FdnDelayLines = new IDelayLine[4]; - DecayDelays1 = new DecayDelay[4]; - DecayDelays2 = new DecayDelay[4]; - DecayDirectFdnGain = new float[4]; - DecayCurrentFdnGain = new float[4]; - DecayCurrentOutputGain = new float[4]; - PreviousFeedbackOutputDecayed = new float[4]; - - uint sampleRate = parameter.SampleRate / 1000; - - for (int i = 0; i < 4; i++) - { - FdnDelayLines[i] = new DelayLine3d(sampleRate, FdnDelayMaxTimes[i]); - DecayDelays1[i] = new DecayDelay(new DelayLine3d(sampleRate, DecayDelayMaxTimes1[i])); - DecayDelays2[i] = new DecayDelay(new DelayLine3d(sampleRate, DecayDelayMaxTimes2[i])); - } - - PreDelayLine = new DelayLine3d(sampleRate, 400); - BackLeftDelayLine = new DelayLine3d(sampleRate, 5); - - UpdateParameter(ref parameter); - } - - public void UpdateParameter(ref Reverb3dParameter parameter) - { - uint sampleRate = parameter.SampleRate / 1000; - - EarlyDelayTime = new uint[20]; - DryGain = parameter.DryGain; - PreviousFeedbackOutputDecayed.AsSpan().Fill(0); - PreviousPreDelayValue = 0; - - EarlyReflectionsGain = FloatingPointHelper.Pow10(Math.Min(parameter.RoomGain + parameter.ReflectionsGain, 5000.0f) / 2000.0f); - LateReverbGain = FloatingPointHelper.Pow10(Math.Min(parameter.RoomGain + parameter.ReverbGain, 5000.0f) / 2000.0f); - - float highFrequencyRoomGain = FloatingPointHelper.Pow10(parameter.RoomHf / 2000.0f); - - if (highFrequencyRoomGain < 1.0f) - { - float tempA = 1.0f - highFrequencyRoomGain; - float tempB = 2.0f - ((2.0f * highFrequencyRoomGain) * FloatingPointHelper.Cos(256.0f * parameter.HfReference / parameter.SampleRate)); - float tempC = MathF.Sqrt(MathF.Pow(tempB, 2) - (4.0f * (1.0f - highFrequencyRoomGain) * (1.0f - highFrequencyRoomGain))); - - PreviousPreDelayGain = (tempB - tempC) / (2.0f * tempA); - TargetPreDelayGain = 1.0f - PreviousPreDelayGain; - } - else - { - PreviousPreDelayGain = 0.0f; - TargetPreDelayGain = 1.0f; - } - - ReflectionDelayTime = IDelayLine.GetSampleCount(sampleRate, 1000.0f * (parameter.ReflectionDelay + parameter.ReverbDelayTime)); - EchoLateReverbDecay = 0.6f * parameter.Diffusion * 0.01f; - - for (int i = 0; i < FdnDelayLines.Length; i++) - { - FdnDelayLines[i].SetDelay(FdnDelayMinTimes[i] + (parameter.Density / 100 * (FdnDelayMaxTimes[i] - FdnDelayMinTimes[i]))); - - uint tempSampleCount = FdnDelayLines[i].CurrentSampleCount + DecayDelays1[i].CurrentSampleCount + DecayDelays2[i].CurrentSampleCount; - - float tempA = (-60.0f * tempSampleCount) / (parameter.DecayTime * parameter.SampleRate); - float tempB = tempA / parameter.HfDecayRatio; - float tempC = FloatingPointHelper.Cos(128.0f * 0.5f * parameter.HfReference / parameter.SampleRate) / FloatingPointHelper.Sin(128.0f * 0.5f * parameter.HfReference / parameter.SampleRate); - float tempD = FloatingPointHelper.Pow10((tempB - tempA) / 40.0f); - float tempE = FloatingPointHelper.Pow10((tempB + tempA) / 40.0f) * 0.7071f; - - DecayDirectFdnGain[i] = tempE * ((tempD * tempC) + 1.0f) / (tempC + tempD); - DecayCurrentFdnGain[i] = tempE * (1.0f - (tempD * tempC)) / (tempC + tempD); - DecayCurrentOutputGain[i] = (tempC - tempD) / (tempC + tempD); - - DecayDelays1[i].SetDecayRate(EchoLateReverbDecay); - DecayDelays2[i].SetDecayRate(EchoLateReverbDecay * -0.9f); - } - - for (int i = 0; i < EarlyDelayTime.Length; i++) - { - uint sampleCount = Math.Min(IDelayLine.GetSampleCount(sampleRate, (parameter.ReflectionDelay * 1000.0f) + (EarlyDelayTimes[i] * 1000.0f * ((parameter.ReverbDelayTime * 0.9998f) + 0.02f))), PreDelayLine.SampleCountMax); - EarlyDelayTime[i] = sampleCount; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Dsp/State/ReverbState.cs b/Ryujinx.Audio.Renderer/Dsp/State/ReverbState.cs deleted file mode 100644 index 60d8e284..00000000 --- a/Ryujinx.Audio.Renderer/Dsp/State/ReverbState.cs +++ /dev/null @@ -1,221 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.Effect; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using System; - -namespace Ryujinx.Audio.Renderer.Dsp.State -{ - public class ReverbState - { - private static readonly float[] FdnDelayTimes = new float[20] - { - // Room - 53.953247f, 79.192566f, 116.238770f, 130.615295f, - // Hall - 53.953247f, 79.192566f, 116.238770f, 170.615295f, - // Plate - 5f, 10f, 5f, 10f, - // Cathedral - 47.03f, 71f, 103f, 170f, - // Max delay (Hall is the one with the highest values so identical to Hall) - 53.953247f, 79.192566f, 116.238770f, 170.615295f, - }; - - private static readonly float[] DecayDelayTimes = new float[20] - { - // Room - 7f, 9f, 13f, 17f, - // Hall - 7f, 9f, 13f, 17f, - // Plate (no decay) - 1f, 1f, 1f, 1f, - // Cathedral - 7f, 7f, 13f, 9f, - // Max delay (Hall is the one with the highest values so identical to Hall) - 7f, 9f, 13f, 17f, - }; - - private static readonly float[] EarlyDelayTimes = new float[50] - { - // Room - 0.0f, 3.5f, 2.8f, 3.9f, 2.7f, 13.4f, 7.9f, 8.4f, 9.9f, 12.0f, - // Chamber - 0.0f, 11.8f, 5.5f, 11.2f, 10.4f, 38.1f, 22.2f, 29.6f, 21.2f, 24.8f, - // Hall - 0.0f, 41.5f, 20.5f, 41.3f, 0.0f, 29.5f, 33.8f, 45.2f, 46.8f, 0.0f, - // Cathedral - 33.1f, 43.3f, 22.8f, 37.9f, 14.9f, 35.3f, 17.9f, 34.2f, 0.0f, 43.3f, - // Disabled - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f - }; - - private static readonly float[] EarlyGainBase = new float[50] - { - // Room - 0.70f, 0.68f, 0.70f, 0.68f, 0.70f, 0.68f, 0.70f, 0.68f, 0.68f, 0.68f, - // Chamber - 0.70f, 0.68f, 0.70f, 0.68f, 0.70f, 0.68f, 0.68f, 0.68f, 0.68f, 0.68f, - // Hall - 0.50f, 0.70f, 0.70f, 0.68f, 0.50f, 0.68f, 0.68f, 0.70f, 0.68f, 0.00f, - // Cathedral - 0.93f, 0.92f, 0.87f, 0.86f, 0.94f, 0.81f, 0.80f, 0.77f, 0.76f, 0.65f, - // Disabled - 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f - }; - - private static readonly float[] PreDelayTimes = new float[5] - { - // Room - 12.5f, - // Chamber - 40.0f, - // Hall - 50.0f, - // Cathedral - 50.0f, - // Disabled - 0.0f - }; - - public IDelayLine[] FdnDelayLines { get; } - public DecayDelay[] DecayDelays { get; } - public IDelayLine PreDelayLine { get; } - public IDelayLine BackLeftDelayLine { get; } - public uint[] EarlyDelayTime { get; } - public float[] EarlyGain { get; } - public uint PreDelayLineDelayTime { get; private set; } - - public float[] HighFrequencyDecayDirectGain { get; } - public float[] HighFrequencyDecayPreviousGain { get; } - public float[] PreviousFeedbackOutput { get; } - - public const int EarlyModeCount = 10; - - private const int FixedPointPrecision = 14; - - private ReadOnlySpan<float> GetFdnDelayTimesByLateMode(ReverbLateMode lateMode) - { - return FdnDelayTimes.AsSpan().Slice((int)lateMode * 4, 4); - } - - private ReadOnlySpan<float> GetDecayDelayTimesByLateMode(ReverbLateMode lateMode) - { - return DecayDelayTimes.AsSpan().Slice((int)lateMode * 4, 4); - } - - public ReverbState(ref ReverbParameter parameter, ulong workBuffer, bool isLongSizePreDelaySupported) - { - FdnDelayLines = new IDelayLine[4]; - DecayDelays = new DecayDelay[4]; - EarlyDelayTime = new uint[EarlyModeCount]; - EarlyGain = new float[EarlyModeCount]; - HighFrequencyDecayDirectGain = new float[4]; - HighFrequencyDecayPreviousGain = new float[4]; - PreviousFeedbackOutput = new float[4]; - - ReadOnlySpan<float> fdnDelayTimes = GetFdnDelayTimesByLateMode(ReverbLateMode.Limit); - ReadOnlySpan<float> decayDelayTimes = GetDecayDelayTimesByLateMode(ReverbLateMode.Limit); - - uint sampleRate = (uint)FixedPointHelper.ToFloat((uint)parameter.SampleRate, FixedPointPrecision); - - for (int i = 0; i < 4; i++) - { - FdnDelayLines[i] = new DelayLine(sampleRate, fdnDelayTimes[i]); - DecayDelays[i] = new DecayDelay(new DelayLine(sampleRate, decayDelayTimes[i])); - } - - float preDelayTimeMax = 150.0f; - - if (isLongSizePreDelaySupported) - { - preDelayTimeMax = 350.0f; - } - - PreDelayLine = new DelayLine(sampleRate, preDelayTimeMax); - BackLeftDelayLine = new DelayLine(sampleRate, 5.0f); - - UpdateParameter(ref parameter); - } - - public void UpdateParameter(ref ReverbParameter parameter) - { - uint sampleRate = (uint)FixedPointHelper.ToFloat((uint)parameter.SampleRate, FixedPointPrecision); - - float preDelayTimeInMilliseconds = FixedPointHelper.ToFloat(parameter.PreDelayTime, FixedPointPrecision); - float earlyGain = FixedPointHelper.ToFloat(parameter.EarlyGain, FixedPointPrecision); - float coloration = FixedPointHelper.ToFloat(parameter.Coloration, FixedPointPrecision); - float decayTime = FixedPointHelper.ToFloat(parameter.DecayTime, FixedPointPrecision); - - for (int i = 0; i < 10; i++) - { - EarlyDelayTime[i] = Math.Min(IDelayLine.GetSampleCount(sampleRate, EarlyDelayTimes[i] + preDelayTimeInMilliseconds), PreDelayLine.SampleCountMax) + 1; - EarlyGain[i] = EarlyGainBase[i] * earlyGain; - } - - if (parameter.ChannelCount == 2) - { - EarlyGain[4] = EarlyGain[4] * 0.5f; - EarlyGain[5] = EarlyGain[5] * 0.5f; - } - - PreDelayLineDelayTime = Math.Min(IDelayLine.GetSampleCount(sampleRate, PreDelayTimes[(int)parameter.EarlyMode] + preDelayTimeInMilliseconds), PreDelayLine.SampleCountMax); - - ReadOnlySpan<float> fdnDelayTimes = GetFdnDelayTimesByLateMode(parameter.LateMode); - ReadOnlySpan<float> decayDelayTimes = GetDecayDelayTimesByLateMode(parameter.LateMode); - - float highFrequencyDecayRatio = FixedPointHelper.ToFloat(parameter.HighFrequencyDecayRatio, FixedPointPrecision); - float highFrequencyUnknownValue = FloatingPointHelper.Cos(1280.0f / sampleRate); - - for (int i = 0; i < 4; i++) - { - FdnDelayLines[i].SetDelay(fdnDelayTimes[i]); - DecayDelays[i].SetDelay(decayDelayTimes[i]); - - float tempA = -3 * (DecayDelays[i].CurrentSampleCount + FdnDelayLines[i].CurrentSampleCount); - float tempB = tempA / (decayTime * sampleRate); - float tempC; - float tempD; - - if (highFrequencyDecayRatio < 0.995f) - { - float tempE = FloatingPointHelper.Pow10((((1.0f / highFrequencyDecayRatio) - 1.0f) * 2) / 100 * (tempB / 10)); - float tempF = 1.0f - tempE; - float tempG = 2.0f - (tempE * 2 * highFrequencyUnknownValue); - float tempH = MathF.Sqrt((tempG * tempG) - (tempF * tempF * 4)); - - tempC = (tempG - tempH) / (tempF * 2); - tempD = 1.0f - tempC; - } - else - { - // no high frequency decay ratio - tempC = 0.0f; - tempD = 1.0f; - } - - HighFrequencyDecayDirectGain[i] = FloatingPointHelper.Pow10(tempB / 1000) * tempD * 0.7071f; - HighFrequencyDecayPreviousGain[i] = tempC; - PreviousFeedbackOutput[i] = 0.0f; - - DecayDelays[i].SetDecayRate(0.6f * (1.0f - coloration)); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Integration/HardwareDevice.cs b/Ryujinx.Audio.Renderer/Integration/HardwareDevice.cs deleted file mode 100644 index 6a82ec85..00000000 --- a/Ryujinx.Audio.Renderer/Integration/HardwareDevice.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Integration -{ - /// <summary> - /// Represent an hardware device used in <see cref="Dsp.Command.DeviceSinkCommand"/> - /// </summary> - public interface HardwareDevice : IDisposable - { - /// <summary> - /// Get the supported sample rate of this device. - /// </summary> - /// <returns>The supported sample rate of this device.</returns> - uint GetSampleRate(); - - /// <summary> - /// Get the channel count supported by this device. - /// </summary> - /// <returns>The channel count supported by this device.</returns> - uint GetChannelCount(); - - /// <summary> - /// Appends new PCM16 samples to the device. - /// </summary> - /// <param name="data">The new PCM16 samples.</param> - /// <param name="channelCount">The number of channels.</param> - void AppendBuffer(ReadOnlySpan<short> data, uint channelCount); - - /// <summary> - /// Check if the audio renderer needs to perform downmixing. - /// </summary> - /// <returns>True if downmixing is needed.</returns> - public bool NeedDownmixing() - { - uint channelCount = GetChannelCount(); - - Debug.Assert(channelCount > 0 && channelCount <= RendererConstants.ChannelCountMax); - - return channelCount != RendererConstants.ChannelCountMax; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Integration/IWritableEvent.cs b/Ryujinx.Audio.Renderer/Integration/IWritableEvent.cs deleted file mode 100644 index 22864b74..00000000 --- a/Ryujinx.Audio.Renderer/Integration/IWritableEvent.cs +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Integration -{ - /// <summary> - /// Represent a writable event with manual clear. - /// </summary> - public interface IWritableEvent - { - /// <summary> - /// Signal the event. - /// </summary> - void Signal(); - - /// <summary> - /// Clear the signaled state of the event. - /// </summary> - void Clear(); - } -} diff --git a/Ryujinx.Audio.Renderer/LICENSE.txt b/Ryujinx.Audio.Renderer/LICENSE.txt deleted file mode 100644 index 0a041280..00000000 --- a/Ryujinx.Audio.Renderer/LICENSE.txt +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/Ryujinx.Audio.Renderer/Parameter/AudioRendererConfiguration.cs b/Ryujinx.Audio.Renderer/Parameter/AudioRendererConfiguration.cs deleted file mode 100644 index 047aa279..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/AudioRendererConfiguration.cs +++ /dev/null @@ -1,116 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/BehaviourErrorInfoOutStatus.cs b/Ryujinx.Audio.Renderer/Parameter/BehaviourErrorInfoOutStatus.cs deleted file mode 100644 index e5312f04..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/BehaviourErrorInfoOutStatus.cs +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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]; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/BiquadFilterParameter.cs b/Ryujinx.Audio.Renderer/Parameter/BiquadFilterParameter.cs deleted file mode 100644 index de6b9577..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/BiquadFilterParameter.cs +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/Effect/AuxiliaryBufferParameter.cs b/Ryujinx.Audio.Renderer/Parameter/Effect/AuxiliaryBufferParameter.cs deleted file mode 100644 index 5a747922..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/Effect/AuxiliaryBufferParameter.cs +++ /dev/null @@ -1,100 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Parameter.Effect -{ - /// <summary> - /// <see cref="EffectInParameter.SpecificData"/> for <see cref="Common.EffectType.AuxiliaryBuffer"/>. - /// </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> - 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; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/Effect/BiquadFilterEffectParameter.cs b/Ryujinx.Audio.Renderer/Parameter/Effect/BiquadFilterEffectParameter.cs deleted file mode 100644 index 7d58d4be..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/Effect/BiquadFilterEffectParameter.cs +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Server.Effect; -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Parameter.Effect -{ - /// <summary> - /// <see cref="EffectInParameter.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; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/Effect/BufferMixerParameter.cs b/Ryujinx.Audio.Renderer/Parameter/Effect/BufferMixerParameter.cs deleted file mode 100644 index b0c0c337..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/Effect/BufferMixerParameter.cs +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Parameter.Effect -{ - /// <summary> - /// <see cref="EffectInParameter.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; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/Effect/DelayParameter.cs b/Ryujinx.Audio.Renderer/Parameter/Effect/DelayParameter.cs deleted file mode 100644 index e0dbeb7c..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/Effect/DelayParameter.cs +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Server.Effect; -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Parameter.Effect -{ - /// <summary> - /// <see cref="EffectInParameter.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 EffectInParameter.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 EffectInParameter.IsChannelCountValid(ChannelCountMax); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/Effect/Reverb3dParameter.cs b/Ryujinx.Audio.Renderer/Parameter/Effect/Reverb3dParameter.cs deleted file mode 100644 index 0dbecfb8..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/Effect/Reverb3dParameter.cs +++ /dev/null @@ -1,144 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Server.Effect; -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Parameter.Effect -{ - /// <summary> - /// <see cref="EffectInParameter.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 EffectInParameter.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 EffectInParameter.IsChannelCountValid(ChannelCountMax); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/Effect/ReverbParameter.cs b/Ryujinx.Audio.Renderer/Parameter/Effect/ReverbParameter.cs deleted file mode 100644 index daa81c51..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/Effect/ReverbParameter.cs +++ /dev/null @@ -1,136 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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="EffectInParameter.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 EffectInParameter.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 EffectInParameter.IsChannelCountValid(ChannelCountMax); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/EffectInParameter.cs b/Ryujinx.Audio.Renderer/Parameter/EffectInParameter.cs deleted file mode 100644 index af8edeff..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/EffectInParameter.cs +++ /dev/null @@ -1,103 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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. - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct EffectInParameter - { - /// <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 { } - - /// <summary> - /// Specific data changing depending of the <see cref="Type"/>. See also the <see cref="Effect"/> namespace. - /// </summary> - public Span<byte> SpecificData => SpanHelpers.AsSpan<SpecificDataStruct, byte>(ref _specificDataStart); - - /// <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; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/EffectOutStatus.cs b/Ryujinx.Audio.Renderer/Parameter/EffectOutStatus.cs deleted file mode 100644 index 7ed2c7ba..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/EffectOutStatus.cs +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Parameter -{ - /// <summary> - /// Output information for an effect. - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct EffectOutStatus - { - /// <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 - } - - /// <summary> - /// Current effect state. - /// </summary> - // TODO: enum? - public EffectState State; - - /// <summary> - /// Unused/Reserved. - /// </summary> - private unsafe fixed byte _reserved[15]; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/MemoryPoolInParameter.cs b/Ryujinx.Audio.Renderer/Parameter/MemoryPoolInParameter.cs deleted file mode 100644 index 15498cca..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/MemoryPoolInParameter.cs +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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]; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/MemoryPoolOutStatus.cs b/Ryujinx.Audio.Renderer/Parameter/MemoryPoolOutStatus.cs deleted file mode 100644 index c125cb8b..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/MemoryPoolOutStatus.cs +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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]; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/MixInParameterDirtyOnlyUpdate.cs b/Ryujinx.Audio.Renderer/Parameter/MixInParameterDirtyOnlyUpdate.cs deleted file mode 100644 index cdbd5871..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/MixInParameterDirtyOnlyUpdate.cs +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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]; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/MixParameter.cs b/Ryujinx.Audio.Renderer/Parameter/MixParameter.cs deleted file mode 100644 index 7f45bca6..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/MixParameter.cs +++ /dev/null @@ -1,112 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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 * RendererConstants.MixBufferCountMax * RendererConstants.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); - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/Performance/PerformanceInParameter.cs b/Ryujinx.Audio.Renderer/Parameter/Performance/PerformanceInParameter.cs deleted file mode 100644 index 929f006b..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/Performance/PerformanceInParameter.cs +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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]; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/Performance/PerformanceOutStatus.cs b/Ryujinx.Audio.Renderer/Parameter/Performance/PerformanceOutStatus.cs deleted file mode 100644 index 9263362c..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/Performance/PerformanceOutStatus.cs +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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]; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/RendererInfoOutStatus.cs b/Ryujinx.Audio.Renderer/Parameter/RendererInfoOutStatus.cs deleted file mode 100644 index 315f0968..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/RendererInfoOutStatus.cs +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/Sink/CircularBufferParameter.cs b/Ryujinx.Audio.Renderer/Parameter/Sink/CircularBufferParameter.cs deleted file mode 100644 index d688529a..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/Sink/CircularBufferParameter.cs +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/Sink/DeviceParameter.cs b/Ryujinx.Audio.Renderer/Parameter/Sink/DeviceParameter.cs deleted file mode 100644 index 591b4945..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/Sink/DeviceParameter.cs +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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); - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/SinkInParameter.cs b/Ryujinx.Audio.Renderer/Parameter/SinkInParameter.cs deleted file mode 100644 index 0859ef31..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/SinkInParameter.cs +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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); - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/SinkOutStatus.cs b/Ryujinx.Audio.Renderer/Parameter/SinkOutStatus.cs deleted file mode 100644 index e0cb4942..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/SinkOutStatus.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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]; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/SplitterDestinationInParameter.cs b/Ryujinx.Audio.Renderer/Parameter/SplitterDestinationInParameter.cs deleted file mode 100644 index a1c18d57..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/SplitterDestinationInParameter.cs +++ /dev/null @@ -1,84 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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 * RendererConstants.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; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/SplitterInParameter.cs b/Ryujinx.Audio.Renderer/Parameter/SplitterInParameter.cs deleted file mode 100644 index a829abf9..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/SplitterInParameter.cs +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/SplitterInParameterHeader.cs b/Ryujinx.Audio.Renderer/Parameter/SplitterInParameterHeader.cs deleted file mode 100644 index 746d59b7..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/SplitterInParameterHeader.cs +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/VoiceChannelResourceInParameter.cs b/Ryujinx.Audio.Renderer/Parameter/VoiceChannelResourceInParameter.cs deleted file mode 100644 index 73ad2bfd..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/VoiceChannelResourceInParameter.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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; - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/VoiceInParameter.cs b/Ryujinx.Audio.Renderer/Parameter/VoiceInParameter.cs deleted file mode 100644 index 9a18a95a..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/VoiceInParameter.cs +++ /dev/null @@ -1,360 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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 - } - } -} diff --git a/Ryujinx.Audio.Renderer/Parameter/VoiceOutStatus.cs b/Ryujinx.Audio.Renderer/Parameter/VoiceOutStatus.cs deleted file mode 100644 index 62d17a5a..00000000 --- a/Ryujinx.Audio.Renderer/Parameter/VoiceOutStatus.cs +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -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]; - } -} diff --git a/Ryujinx.Audio.Renderer/RendererConstants.cs b/Ryujinx.Audio.Renderer/RendererConstants.cs deleted file mode 100644 index d2697378..00000000 --- a/Ryujinx.Audio.Renderer/RendererConstants.cs +++ /dev/null @@ -1,167 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer -{ - /// <summary> - /// Define constants used by the Audio Renderer. - /// </summary> - public static class RendererConstants - { - /// <summary> - /// The maximum number of channels supported. (6 channels for 5.1 surround) - /// </summary> - public const int ChannelCountMax = 6; - - /// <summary> - /// The maximum number of channels supported per voice. - /// </summary> - public const int VoiceChannelCountMax = ChannelCountMax; - - /// <summary> - /// The max count of mix buffer supported per operations (volumes, mix effect, ...) - /// </summary> - public const int MixBufferCountMax = 24; - - /// <summary> - /// The max count of wavebuffer per voice. - /// </summary> - public const int VoiceWaveBufferCount = 4; - - /// <summary> - /// The max count of biquad filter per voice. - /// </summary> - public const int VoiceBiquadFilterCount = 2; - - /// <summary> - /// The lowest priority that a voice can have. - /// </summary> - public const int VoiceLowestPriority = 0xFF; - - /// <summary> - /// The highest priority that a voice can have. - /// </summary> - /// <remarks>Voices with the highest priority will not be dropped if a voice drop needs to occur.</remarks> - public const int VoiceHighestPriority = 0; - - /// <summary> - /// Max <see cref="Common.BehaviourParameter.ErrorInfo"/> that can be returned by <see cref="Parameter.BehaviourErrorInfoOutStatus"/>. - /// </summary> - public const int MaxErrorInfos = 10; - - /// <summary> - /// Default alignment for buffers. - /// </summary> - public const int BufferAlignment = 0x40; - - /// <summary> - /// Alignment required for the work buffer. - /// </summary> - public const int WorkBufferAlignment = 0x1000; - - /// <summary> - /// Alignment required for every performance metrics frame. - /// </summary> - public const int PerformanceMetricsPerFramesSizeAlignment = 0x100; - - /// <summary> - /// The id of the final mix. - /// </summary> - public const int FinalMixId = 0; - - /// <summary> - /// The id defining an unused mix id. - /// </summary> - public const int UnusedMixId = int.MaxValue; - - /// <summary> - /// The id defining an unused splitter id as a signed integer. - /// </summary> - public const int UnusedSplitterIdInt = -1; - - /// <summary> - /// The id defining an unused splitter id. - /// </summary> - public const uint UnusedSplitterId = uint.MaxValue; - - /// <summary> - /// The id of invalid/unused node id. - /// </summary> - public const int InvalidNodeId = -268435456; - - /// <summary> - /// The indice considered invalid for processing order. - /// </summary> - public const int InvalidProcessingOrder = -1; - - /// <summary> - /// The max number of audio renderer sessions allowed to be created system wide. - /// </summary> - public const int AudioRendererSessionCountMax = 2; - - /// <summary> - /// The target sample rate of the audio renderer. (48kHz) - /// </summary> - public const uint TargetSampleRate = 48000; - - /// <summary> - /// The target sample size of the audio renderer. (PCM16) - /// </summary> - public const int TargetSampleSize = sizeof(ushort); - - /// <summary> - /// The target sample count per audio renderer update. - /// </summary> - public const int TargetSampleCount = 240; - - /// <summary> - /// The size of an upsampler entry to process upsampling to <see cref="TargetSampleRate"/>. - /// </summary> - public const int UpSampleEntrySize = TargetSampleCount * VoiceChannelCountMax; - - /// <summary> - /// The target audio latency computed from <see cref="TargetSampleRate"/> and <see cref="TargetSampleCount"/>. - /// </summary> - public const int AudioProcessorMaxUpdateTimeTarget = 1000000000 / ((int)TargetSampleRate / TargetSampleCount); // 5.00 ms - - /// <summary> - /// The max update time of the DSP on original hardware. - /// </summary> - public const int AudioProcessorMaxUpdateTime = 5760000; // 5.76 ms - - /// <summary> - /// The max update time per audio renderer session. - /// </summary> - public const int AudioProcessorMaxUpdateTimePerSessions = AudioProcessorMaxUpdateTime / AudioRendererSessionCountMax; - - /// <summary> - /// Guest timer frequency used for system ticks. - /// </summary> - public const int TargetTimerFrequency = 19200000; - - /// <summary> - /// The default coefficients used for standard 5.1 surround to stereo downmixing. - /// </summary> - public static float[] DefaultSurroundToStereoCoefficients = new float[4] - { - 1.0f, - 0.707f, - 0.251f, - 0.707f, - }; - } -} diff --git a/Ryujinx.Audio.Renderer/ResultCode.cs b/Ryujinx.Audio.Renderer/ResultCode.cs deleted file mode 100644 index 9b11aefa..00000000 --- a/Ryujinx.Audio.Renderer/ResultCode.cs +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer -{ - public enum ResultCode - { - ModuleId = 153, - ErrorCodeShift = 9, - - Success = 0, - - OperationFailed = (2 << ErrorCodeShift) | ModuleId, - WorkBufferTooSmall = (4 << ErrorCodeShift) | ModuleId, - InvalidUpdateInfo = (41 << ErrorCodeShift) | ModuleId, - InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId, - InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId, - UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId, - } -} diff --git a/Ryujinx.Audio.Renderer/Ryujinx.Audio.Renderer.csproj b/Ryujinx.Audio.Renderer/Ryujinx.Audio.Renderer.csproj deleted file mode 100644 index ccdeae3e..00000000 --- a/Ryujinx.Audio.Renderer/Ryujinx.Audio.Renderer.csproj +++ /dev/null @@ -1,14 +0,0 @@ -<Project Sdk="Microsoft.NET.Sdk"> - - <PropertyGroup> - <TargetFramework>net5.0</TargetFramework> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - </PropertyGroup> - - <ItemGroup> - <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" /> - <ProjectReference Include="..\Ryujinx.Cpu\Ryujinx.Cpu.csproj" /> - <ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" /> - </ItemGroup> - -</Project> diff --git a/Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs b/Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs deleted file mode 100644 index 9b87957a..00000000 --- a/Ryujinx.Audio.Renderer/Server/AudioRenderSystem.cs +++ /dev/null @@ -1,838 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.Command; -using Ryujinx.Audio.Renderer.Integration; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using Ryujinx.Audio.Renderer.Server.Mix; -using Ryujinx.Audio.Renderer.Server.Performance; -using Ryujinx.Audio.Renderer.Server.Sink; -using Ryujinx.Audio.Renderer.Server.Splitter; -using Ryujinx.Audio.Renderer.Server.Types; -using Ryujinx.Audio.Renderer.Server.Upsampler; -using Ryujinx.Audio.Renderer.Server.Voice; -using Ryujinx.Audio.Renderer.Utils; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Memory; -using System; -using System.Buffers; -using System.Diagnostics; -using System.Threading; - -using CpuAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server -{ - public class AudioRenderSystem : IDisposable - { - private object _lock = new object(); - - private AudioRendererExecutionMode _executionMode; - private IWritableEvent _systemEvent; - private ManualResetEvent _terminationEvent; - private MemoryPoolState _dspMemoryPoolState; - private VoiceContext _voiceContext; - private MixContext _mixContext; - private SinkContext _sinkContext; - private SplitterContext _splitterContext; - private EffectContext _effectContext; - private PerformanceManager _performanceManager; - private UpsamplerManager _upsamplerManager; - private bool _isActive; - private BehaviourContext _behaviourContext; - private ulong _totalElapsedTicksUpdating; - private ulong _totalElapsedTicks; - private int _sessionId; - private Memory<MemoryPoolState> _memoryPools; - - private uint _sampleRate; - private uint _sampleCount; - private uint _mixBufferCount; - private uint _voiceChannelCountMax; - private uint _upsamplerCount; - private uint _memoryPoolCount; - private uint _processHandle; - private ulong _appletResourceId; - - private WritableRegion _workBufferRegion; - private MemoryHandle _workBufferMemoryPin; - - private Memory<float> _mixBuffer; - private Memory<float> _depopBuffer; - - private uint _renderingTimeLimitPercent; - private bool _voiceDropEnabled; - private uint _voiceDropCount; - private bool _isDspRunningBehind; - - private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator; - - private Memory<byte> _performanceBuffer; - - public IVirtualMemoryManager MemoryManager { get; private set; } - - private ulong _elapsedFrameCount; - private ulong _renderingStartTick; - - private AudioRendererManager _manager; - - public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent) - { - _manager = manager; - _terminationEvent = new ManualResetEvent(false); - _dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp); - _voiceContext = new VoiceContext(); - _mixContext = new MixContext(); - _sinkContext = new SinkContext(); - _splitterContext = new SplitterContext(); - _effectContext = new EffectContext(); - - _commandProcessingTimeEstimator = null; - _systemEvent = systemEvent; - _behaviourContext = new BehaviourContext(); - - _totalElapsedTicksUpdating = 0; - _sessionId = 0; - } - - public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, IVirtualMemoryManager memoryManager) - { - if (!BehaviourContext.CheckValidRevision(parameter.Revision)) - { - return ResultCode.OperationFailed; - } - - if (GetWorkBufferSize(ref parameter) > workBufferSize) - { - return ResultCode.WorkBufferTooSmall; - } - - Debug.Assert(parameter.RenderingDevice == AudioRendererRenderingDevice.Dsp && parameter.ExecutionMode == AudioRendererExecutionMode.Auto); - - Logger.Info?.Print(LogClass.AudioRenderer, $"Initializing with REV{BehaviourContext.GetRevisionNumber(parameter.Revision)}"); - - _behaviourContext.SetUserRevision(parameter.Revision); - - _sampleRate = parameter.SampleRate; - _sampleCount = parameter.SampleCount; - _mixBufferCount = parameter.MixBufferCount; - _voiceChannelCountMax = RendererConstants.VoiceChannelCountMax; - _upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount; - _appletResourceId = appletResourceId; - _memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * RendererConstants.VoiceWaveBufferCount; - _executionMode = parameter.ExecutionMode; - _sessionId = sessionId; - MemoryManager = memoryManager; - - WorkBufferAllocator workBufferAllocator; - - _workBufferRegion = MemoryManager.GetWritableRegion(workBuffer, (int)workBufferSize); - _workBufferRegion.Memory.Span.Fill(0); - _workBufferMemoryPin = _workBufferRegion.Memory.Pin(); - - workBufferAllocator = new WorkBufferAllocator(_workBufferRegion.Memory); - - PoolMapper poolMapper = new PoolMapper(processHandle, false); - poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize); - - _mixBuffer = workBufferAllocator.Allocate<float>(_sampleCount * (_voiceChannelCountMax + _mixBufferCount), 0x10); - - if (_mixBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - Memory<float> upSamplerWorkBuffer = workBufferAllocator.Allocate<float>(RendererConstants.TargetSampleCount * (_voiceChannelCountMax + _mixBufferCount) * _upsamplerCount, 0x10); - - if (upSamplerWorkBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - _depopBuffer = workBufferAllocator.Allocate<float>((ulong)BitUtils.AlignUp(parameter.MixBufferCount, RendererConstants.BufferAlignment), RendererConstants.BufferAlignment); - - if (_depopBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - // Invalidate DSP cache on what was currently allocated with workBuffer. - AudioProcessorMemoryManager.InvalidateDspCache(_dspMemoryPoolState.Translate(workBuffer, workBufferAllocator.Offset), workBufferAllocator.Offset); - - Debug.Assert((workBufferAllocator.Offset % RendererConstants.BufferAlignment) == 0); - - Memory<VoiceState> voices = workBufferAllocator.Allocate<VoiceState>(parameter.VoiceCount, VoiceState.Alignment); - - if (voices.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - foreach (ref VoiceState voice in voices.Span) - { - voice.Initialize(); - } - - // A pain to handle as we can't have VoiceState*, use indices to be a bit more safe - Memory<int> sortedVoices = workBufferAllocator.Allocate<int>(parameter.VoiceCount, 0x10); - - if (sortedVoices.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - // Clear memory (use -1 as it's an invalid index) - sortedVoices.Span.Fill(-1); - - Memory<VoiceChannelResource> voiceChannelResources = workBufferAllocator.Allocate<VoiceChannelResource>(parameter.VoiceCount, VoiceChannelResource.Alignment); - - if (voiceChannelResources.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - for (uint id = 0; id < voiceChannelResources.Length; id++) - { - ref VoiceChannelResource voiceChannelResource = ref voiceChannelResources.Span[(int)id]; - - voiceChannelResource.Id = id; - voiceChannelResource.IsUsed = false; - } - - Memory<VoiceUpdateState> voiceUpdateStates = workBufferAllocator.Allocate<VoiceUpdateState>(parameter.VoiceCount, VoiceUpdateState.Align); - - if (voiceUpdateStates.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - uint mixesCount = parameter.SubMixBufferCount + 1; - - Memory<MixState> mixes = workBufferAllocator.Allocate<MixState>(mixesCount, MixState.Alignment); - - if (mixes.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - if (parameter.EffectCount == 0) - { - foreach (ref MixState mix in mixes.Span) - { - mix = new MixState(Memory<int>.Empty, ref _behaviourContext); - } - } - else - { - Memory<int> effectProcessingOrderArray = workBufferAllocator.Allocate<int>(parameter.EffectCount * mixesCount, 0x10); - - foreach (ref MixState mix in mixes.Span) - { - mix = new MixState(effectProcessingOrderArray.Slice(0, (int)parameter.EffectCount), ref _behaviourContext); - - effectProcessingOrderArray = effectProcessingOrderArray.Slice((int)parameter.EffectCount); - } - } - - // Initialize the final mix id - mixes.Span[0].MixId = RendererConstants.FinalMixId; - - Memory<int> sortedMixesState = workBufferAllocator.Allocate<int>(mixesCount, 0x10); - - if (sortedMixesState.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - // Clear memory (use -1 as it's an invalid index) - sortedMixesState.Span.Fill(-1); - - Memory<byte> nodeStatesWorkBuffer = Memory<byte>.Empty; - Memory<byte> edgeMatrixWorkBuffer = Memory<byte>.Empty; - - if (_behaviourContext.IsSplitterSupported()) - { - nodeStatesWorkBuffer = workBufferAllocator.Allocate((uint)NodeStates.GetWorkBufferSize((int)mixesCount), 1); - edgeMatrixWorkBuffer = workBufferAllocator.Allocate((uint)EdgeMatrix.GetWorkBufferSize((int)mixesCount), 1); - - if (nodeStatesWorkBuffer.IsEmpty || edgeMatrixWorkBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - } - - _mixContext.Initialize(sortedMixesState, mixes, nodeStatesWorkBuffer, edgeMatrixWorkBuffer); - - _memoryPools = workBufferAllocator.Allocate<MemoryPoolState>(_memoryPoolCount, MemoryPoolState.Alignment); - - if (_memoryPools.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - foreach (ref MemoryPoolState state in _memoryPools.Span) - { - state = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu); - } - - if (!_splitterContext.Initialize(ref _behaviourContext, ref parameter, workBufferAllocator)) - { - return ResultCode.WorkBufferTooSmall; - } - - _processHandle = processHandle; - - _upsamplerManager = new UpsamplerManager(upSamplerWorkBuffer, _upsamplerCount); - - _effectContext.Initialize(parameter.EffectCount); - _sinkContext.Initialize(parameter.SinkCount); - - Memory<VoiceUpdateState> voiceUpdateStatesDsp = workBufferAllocator.Allocate<VoiceUpdateState>(parameter.VoiceCount, VoiceUpdateState.Align); - - if (voiceUpdateStatesDsp.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - _voiceContext.Initialize(sortedVoices, voices, voiceChannelResources, voiceUpdateStates, voiceUpdateStatesDsp, parameter.VoiceCount); - - if (parameter.PerformanceMetricFramesCount > 0) - { - ulong performanceBufferSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref _behaviourContext) * (parameter.PerformanceMetricFramesCount + 1) + 0xC; - - _performanceBuffer = workBufferAllocator.Allocate(performanceBufferSize, RendererConstants.BufferAlignment); - - if (_performanceBuffer.IsEmpty) - { - return ResultCode.WorkBufferTooSmall; - } - - _performanceManager = PerformanceManager.Create(_performanceBuffer, ref parameter, _behaviourContext); - } - else - { - _performanceManager = null; - } - - _totalElapsedTicksUpdating = 0; - _totalElapsedTicks = 0; - _renderingTimeLimitPercent = 100; - _voiceDropEnabled = parameter.VoiceDropEnabled && _executionMode == AudioRendererExecutionMode.Auto; - - AudioProcessorMemoryManager.InvalidateDataCache(workBuffer, workBufferSize); - - _processHandle = processHandle; - _elapsedFrameCount = 0; - - switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion()) - { - case 1: - _commandProcessingTimeEstimator = new CommandProcessingTimeEstimatorVersion1(_sampleCount, _mixBufferCount); - break; - case 2: - _commandProcessingTimeEstimator = new CommandProcessingTimeEstimatorVersion2(_sampleCount, _mixBufferCount); - break; - case 3: - _commandProcessingTimeEstimator = new CommandProcessingTimeEstimatorVersion3(_sampleCount, _mixBufferCount); - break; - default: - throw new NotImplementedException($"Unsupported processing time estimator version {_behaviourContext.GetCommandProcessingTimeEstimatorVersion()}."); - } - - return ResultCode.Success; - } - - public void Start() - { - Logger.Info?.Print(LogClass.AudioRenderer, $"Starting renderer id {_sessionId}"); - - lock (_lock) - { - _elapsedFrameCount = 0; - _isActive = true; - } - } - - public void Stop() - { - Logger.Info?.Print(LogClass.AudioRenderer, $"Stopping renderer id {_sessionId}"); - - lock (_lock) - { - _isActive = false; - } - - if (_executionMode == AudioRendererExecutionMode.Auto) - { - _terminationEvent.WaitOne(); - } - - Logger.Info?.Print(LogClass.AudioRenderer, $"Stopped renderer id {_sessionId}"); - } - - public ResultCode Update(Memory<byte> output, Memory<byte> performanceOutput, ReadOnlyMemory<byte> input) - { - lock (_lock) - { - ulong updateStartTicks = GetSystemTicks(); - - output.Span.Fill(0); - - StateUpdater stateUpdater = new StateUpdater(input, output, _processHandle, _behaviourContext); - - ResultCode result; - - result = stateUpdater.UpdateBehaviourContext(); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateMemoryPools(_memoryPools.Span); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateVoiceChannelResources(_voiceContext); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateVoices(_voiceContext, _memoryPools); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateEffects(_effectContext, _isActive, _memoryPools); - - if (result != ResultCode.Success) - { - return result; - } - - if (_behaviourContext.IsSplitterSupported()) - { - result = stateUpdater.UpdateSplitter(_splitterContext); - - if (result != ResultCode.Success) - { - return result; - } - } - - result = stateUpdater.UpdateMixes(_mixContext, GetMixBufferCount(), _effectContext, _splitterContext); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateSinks(_sinkContext, _memoryPools); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdatePerformanceBuffer(_performanceManager, performanceOutput.Span); - - if (result != ResultCode.Success) - { - return result; - } - - result = stateUpdater.UpdateErrorInfo(); - - if (result != ResultCode.Success) - { - return result; - } - - if (_behaviourContext.IsElapsedFrameCountSupported()) - { - result = stateUpdater.UpdateRendererInfo(_elapsedFrameCount); - - if (result != ResultCode.Success) - { - return result; - } - } - - result = stateUpdater.CheckConsumedSize(); - - if (result != ResultCode.Success) - { - return result; - } - - _systemEvent.Clear(); - - ulong updateEndTicks = GetSystemTicks(); - - _totalElapsedTicksUpdating += (updateEndTicks - updateStartTicks); - - return result; - } - } - - private ulong GetSystemTicks() - { - double ticks = ARMeilleure.State.ExecutionContext.ElapsedTicks * ARMeilleure.State.ExecutionContext.TickFrequency; - - return (ulong)(ticks * RendererConstants.TargetTimerFrequency); - } - - private uint ComputeVoiceDrop(CommandBuffer commandBuffer, long voicesEstimatedTime, long deltaTimeDsp) - { - int i; - - for (i = 0; i < commandBuffer.CommandList.Commands.Count; i++) - { - ICommand command = commandBuffer.CommandList.Commands[i]; - - CommandType commandType = command.CommandType; - - if (commandType == CommandType.AdpcmDataSourceVersion1 || - commandType == CommandType.AdpcmDataSourceVersion2 || - commandType == CommandType.PcmInt16DataSourceVersion1 || - commandType == CommandType.PcmInt16DataSourceVersion2 || - commandType == CommandType.PcmFloatDataSourceVersion1 || - commandType == CommandType.PcmFloatDataSourceVersion2 || - commandType == CommandType.Performance) - { - break; - } - } - - uint voiceDropped = 0; - - for (; i < commandBuffer.CommandList.Commands.Count; i++) - { - ICommand targetCommand = commandBuffer.CommandList.Commands[i]; - - int targetNodeId = targetCommand.NodeId; - - if (voicesEstimatedTime <= deltaTimeDsp || NodeIdHelper.GetType(targetNodeId) != NodeIdType.Voice) - { - break; - } - - ref VoiceState voice = ref _voiceContext.GetState(NodeIdHelper.GetBase(targetNodeId)); - - if (voice.Priority == RendererConstants.VoiceHighestPriority) - { - break; - } - - // We can safely drop this voice, disable all associated commands while activating depop preparation commands. - voiceDropped++; - voice.VoiceDropFlag = true; - - Logger.Warning?.Print(LogClass.AudioRenderer, $"Dropping voice {voice.NodeId}"); - - for (; i < commandBuffer.CommandList.Commands.Count; i++) - { - ICommand command = commandBuffer.CommandList.Commands[i]; - - if (command.NodeId != targetNodeId) - { - break; - } - - if (command.CommandType == CommandType.DepopPrepare) - { - command.Enabled = true; - } - else if (command.CommandType == CommandType.Performance || !command.Enabled) - { - continue; - } - else - { - command.Enabled = false; - - voicesEstimatedTime -= (long)command.EstimatedProcessingTime; - } - } - } - - return voiceDropped; - } - - private void GenerateCommandList(out CommandList commandList) - { - Debug.Assert(_executionMode == AudioRendererExecutionMode.Auto); - - PoolMapper.ClearUsageState(_memoryPools); - - ulong startTicks = GetSystemTicks(); - - commandList = new CommandList(this); - - if (_performanceManager != null) - { - _performanceManager.TapFrame(_isDspRunningBehind, _voiceDropCount, _renderingStartTick); - - _isDspRunningBehind = false; - _voiceDropCount = 0; - _renderingStartTick = 0; - } - - CommandBuffer commandBuffer = new CommandBuffer(commandList, _commandProcessingTimeEstimator); - - CommandGenerator commandGenerator = new CommandGenerator(commandBuffer, GetContext(), _voiceContext, _mixContext, _effectContext, _sinkContext, _splitterContext, _performanceManager); - - _voiceContext.Sort(); - commandGenerator.GenerateVoices(); - - long voicesEstimatedTime = (long)commandBuffer.EstimatedProcessingTime; - - commandGenerator.GenerateSubMixes(); - commandGenerator.GenerateFinalMixes(); - commandGenerator.GenerateSinks(); - - long totalEstimatedTime = (long)commandBuffer.EstimatedProcessingTime; - - if (_voiceDropEnabled) - { - long maxDspTime = GetMaxAllocatedTimeForDsp(); - - long restEstimateTime = totalEstimatedTime - voicesEstimatedTime; - - long deltaTimeDsp = Math.Max(maxDspTime - restEstimateTime, 0); - - _voiceDropCount = ComputeVoiceDrop(commandBuffer, voicesEstimatedTime, deltaTimeDsp); - } - - _voiceContext.UpdateForCommandGeneration(); - - ulong endTicks = GetSystemTicks(); - - _totalElapsedTicks = endTicks - startTicks; - - _renderingStartTick = GetSystemTicks(); - _elapsedFrameCount++; - } - - private int GetMaxAllocatedTimeForDsp() - { - return (int)(RendererConstants.AudioProcessorMaxUpdateTimePerSessions * _behaviourContext.GetAudioRendererProcessingTimeLimit() * (GetRenderingTimeLimit() / 100.0f)); - } - - public void SendCommands() - { - lock (_lock) - { - if (_isActive) - { - _terminationEvent.Reset(); - - GenerateCommandList(out CommandList commands); - - _manager.Processor.Send(_sessionId, - commands, - GetMaxAllocatedTimeForDsp(), - _appletResourceId); - - _systemEvent.Signal(); - } - else - { - _terminationEvent.Set(); - } - } - } - - public uint GetMixBufferCount() - { - return _mixBufferCount; - } - - public void SetRenderingTimeLimitPercent(uint percent) - { - Debug.Assert(percent <= 100); - - _renderingTimeLimitPercent = percent; - } - - public uint GetRenderingTimeLimit() - { - return _renderingTimeLimitPercent; - } - - public Memory<float> GetMixBuffer() - { - return _mixBuffer; - } - - public uint GetSampleCount() - { - return _sampleCount; - } - - public uint GetSampleRate() - { - return _sampleRate; - } - - public uint GetVoiceChannelCountMax() - { - return _voiceChannelCountMax; - } - - public bool IsActive() - { - return _isActive; - } - - private RendererSystemContext GetContext() - { - return new RendererSystemContext - { - ChannelCount = _manager.OutputDevices[_sessionId].GetChannelCount(), - BehaviourContext = _behaviourContext, - DepopBuffer = _depopBuffer, - MixBufferCount = GetMixBufferCount(), - SessionId = _sessionId, - UpsamplerManager = _upsamplerManager - }; - } - - public int GetSessionId() - { - return _sessionId; - } - - public static ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter) - { - BehaviourContext behaviourContext = new BehaviourContext(); - - behaviourContext.SetUserRevision(parameter.Revision); - - uint mixesCount = parameter.SubMixBufferCount + 1; - - uint memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * RendererConstants.VoiceWaveBufferCount; - - ulong size = 0; - - // Mix Buffers - size = WorkBufferAllocator.GetTargetSize<float>(size, parameter.SampleCount * (RendererConstants.VoiceChannelCountMax + parameter.MixBufferCount), 0x10); - - // Upsampler workbuffer - size = WorkBufferAllocator.GetTargetSize<float>(size, RendererConstants.TargetSampleCount * (RendererConstants.VoiceChannelCountMax + parameter.MixBufferCount) * (parameter.SinkCount + parameter.SubMixBufferCount), 0x10); - - // Depop buffer - size = WorkBufferAllocator.GetTargetSize<float>(size, (ulong)BitUtils.AlignUp(parameter.MixBufferCount, RendererConstants.BufferAlignment), RendererConstants.BufferAlignment); - - // Voice - size = WorkBufferAllocator.GetTargetSize<VoiceState>(size, parameter.VoiceCount, VoiceState.Alignment); - size = WorkBufferAllocator.GetTargetSize<int>(size, parameter.VoiceCount, 0x10); - size = WorkBufferAllocator.GetTargetSize<VoiceChannelResource>(size, parameter.VoiceCount, VoiceChannelResource.Alignment); - size = WorkBufferAllocator.GetTargetSize<VoiceUpdateState>(size, parameter.VoiceCount, VoiceUpdateState.Align); - - // Mix - size = WorkBufferAllocator.GetTargetSize<MixState>(size, mixesCount, MixState.Alignment); - size = WorkBufferAllocator.GetTargetSize<int>(size, parameter.EffectCount * mixesCount, 0x10); - size = WorkBufferAllocator.GetTargetSize<int>(size, mixesCount, 0x10); - - if (behaviourContext.IsSplitterSupported()) - { - size += (ulong)BitUtils.AlignUp(NodeStates.GetWorkBufferSize((int)mixesCount) + EdgeMatrix.GetWorkBufferSize((int)mixesCount), 0x10); - } - - // Memory Pool - size = WorkBufferAllocator.GetTargetSize<MemoryPoolState>(size, memoryPoolCount, MemoryPoolState.Alignment); - - // Splitter - size = SplitterContext.GetWorkBufferSize(size, ref behaviourContext, ref parameter); - - // DSP Voice - size = WorkBufferAllocator.GetTargetSize<VoiceUpdateState>(size, parameter.VoiceCount, VoiceUpdateState.Align); - - // Performance - if (parameter.PerformanceMetricFramesCount > 0) - { - ulong performanceMetricsPerFramesSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref behaviourContext) * (parameter.PerformanceMetricFramesCount + 1) + 0xC; - - size += BitUtils.AlignUp(performanceMetricsPerFramesSize, RendererConstants.PerformanceMetricsPerFramesSizeAlignment); - } - - return BitUtils.AlignUp(size, RendererConstants.WorkBufferAlignment); - } - - public ResultCode QuerySystemEvent(out IWritableEvent systemEvent) - { - systemEvent = default; - - if (_executionMode == AudioRendererExecutionMode.Manual) - { - return ResultCode.UnsupportedOperation; - } - - systemEvent = _systemEvent; - - return ResultCode.Success; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - if (_isActive) - { - Stop(); - } - - PoolMapper mapper = new PoolMapper(_processHandle, false); - mapper.Unmap(ref _dspMemoryPoolState); - - PoolMapper.ClearUsageState(_memoryPools); - - for (int i = 0; i < _memoryPoolCount; i++) - { - ref MemoryPoolState memoryPool = ref _memoryPools.Span[i]; - - if (memoryPool.IsMapped()) - { - mapper.Unmap(ref memoryPool); - } - } - - _manager.Unregister(this); - _terminationEvent.Dispose(); - _workBufferMemoryPin.Dispose(); - _workBufferRegion.Dispose(); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs b/Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs deleted file mode 100644 index f552935b..00000000 --- a/Ryujinx.Audio.Renderer/Server/AudioRendererManager.cs +++ /dev/null @@ -1,341 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp; -using Ryujinx.Audio.Renderer.Integration; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Common.Logging; -using Ryujinx.Memory; -using System; -using System.Diagnostics; -using System.Threading; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// <summary> - /// The audio renderer manager. - /// </summary> - public class AudioRendererManager : IDisposable - { - /// <summary> - /// Lock used for session allocation. - /// </summary> - private object _sessionLock = new object(); - - /// <summary> - /// Lock used to control the <see cref="AudioProcessor"/> running state. - /// </summary> - private object _audioProcessorLock = new object(); - - /// <summary> - /// The session ids allocation table. - /// </summary> - private int[] _sessionIds; - - /// <summary> - /// The events linked to each session. - /// </summary> - private IWritableEvent[] _sessionsSystemEvent; - - /// <summary> - /// The <see cref="AudioRenderSystem"/> sessions instances. - /// </summary> - private AudioRenderSystem[] _sessions; - - /// <summary> - /// The count of active sessions. - /// </summary> - private int _activeSessionCount; - - /// <summary> - /// The worker thread used to run <see cref="SendCommands"/>. - /// </summary> - private Thread _workerThread; - - /// <summary> - /// Indicate if the worker thread and <see cref="AudioProcessor"/> are running. - /// </summary> - private bool _isRunning; - - /// <summary> - /// The output devices associated to each session. - /// </summary> - // TODO: get ride of this with the audout rewrite. - public HardwareDevice[] OutputDevices { get; private set; } - - /// <summary> - /// The <see cref="AudioProcessor"/> instance associated to this manager. - /// </summary> - public AudioProcessor Processor { get; } - - /// <summary> - /// Create a new <see cref="AudioRendererManager"/>. - /// </summary> - public AudioRendererManager() - { - Processor = new AudioProcessor(); - _sessionIds = new int[RendererConstants.AudioRendererSessionCountMax]; - _sessions = new AudioRenderSystem[RendererConstants.AudioRendererSessionCountMax]; - _activeSessionCount = 0; - - for (int i = 0; i < _sessionIds.Length; i++) - { - _sessionIds[i] = i; - } - } - - /// <summary> - /// Initialize the <see cref="AudioRendererManager"/>. - /// </summary> - /// <param name="sessionSystemEvents">The events associated to each session.</param> - /// <param name="devices">The output devices associated to each session.</param> - public void Initialize(IWritableEvent[] sessionSystemEvents, HardwareDevice[] devices) - { - _sessionsSystemEvent = sessionSystemEvents; - OutputDevices = devices; - } - - /// <summary> - /// Get the work buffer size required by a session. - /// </summary> - /// <param name="parameter">The user configuration</param> - /// <returns>The work buffer size required by a session.</returns> - public static ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter) - { - return AudioRenderSystem.GetWorkBufferSize(ref parameter); - } - - /// <summary> - /// Acquire a new session id. - /// </summary> - /// <returns>A new session id.</returns> - private int AcquireSessionId() - { - lock (_sessionLock) - { - int index = _activeSessionCount; - - Debug.Assert(index < _sessionIds.Length); - - int sessionId = _sessionIds[index]; - - _sessionIds[index] = -1; - - _activeSessionCount++; - - Logger.Info?.Print(LogClass.AudioRenderer, $"Registered new renderer ({sessionId})"); - - return sessionId; - } - } - - /// <summary> - /// Release a given <paramref name="sessionId"/>. - /// </summary> - /// <param name="sessionId">The session id to release.</param> - private void ReleaseSessionId(int sessionId) - { - lock (_sessionLock) - { - Debug.Assert(_activeSessionCount > 0); - - int newIndex = --_activeSessionCount; - - _sessionIds[newIndex] = sessionId; - } - - Logger.Info?.Print(LogClass.AudioRenderer, $"Unregistered renderer ({sessionId})"); - } - - /// <summary> - /// Check if there is any audio renderer active. - /// </summary> - /// <returns>Returns true if there is any audio renderer active.</returns> - private bool HasAnyActiveRendererLocked() - { - foreach (AudioRenderSystem renderer in _sessions) - { - if (renderer != null) - { - return true; - } - } - - return false; - } - - /// <summary> - /// Start the <see cref="AudioProcessor"/> and worker thread. - /// </summary> - private void StartLocked() - { - _isRunning = true; - - // TODO: virtual device mapping (IAudioDevice) - Processor.SetOutputDevices(OutputDevices); - Processor.Start(); - - _workerThread = new Thread(SendCommands) - { - Name = "AudioRendererManager.Worker" - }; - - _workerThread.Start(); - } - - /// <summary> - /// Stop the <see cref="AudioProcessor"/> and worker thread. - /// </summary> - private void StopLocked() - { - _isRunning = false; - - _workerThread.Join(); - Processor.Stop(); - - Logger.Info?.Print(LogClass.AudioRenderer, "Stopped audio renderer"); - } - - /// <summary> - /// Worker main function. This is used to dispatch audio renderer commands to the <see cref="AudioProcessor"/>. - /// </summary> - private void SendCommands() - { - Logger.Info?.Print(LogClass.AudioRenderer, "Starting audio renderer"); - Processor.Wait(); - - while (_isRunning) - { - lock (_sessionLock) - { - foreach(AudioRenderSystem renderer in _sessions) - { - renderer?.SendCommands(); - } - } - - Processor.Signal(); - Processor.Wait(); - } - } - - /// <summary> - /// Register a new <see cref="AudioRenderSystem"/>. - /// </summary> - /// <param name="renderer">The <see cref="AudioRenderSystem"/> to register.</param> - private void Register(AudioRenderSystem renderer) - { - lock (_sessionLock) - { - _sessions[renderer.GetSessionId()] = renderer; - } - - lock (_audioProcessorLock) - { - if (!_isRunning) - { - StartLocked(); - } - } - } - - /// <summary> - /// Unregister a new <see cref="AudioRenderSystem"/>. - /// </summary> - /// <param name="renderer">The <see cref="AudioRenderSystem"/> to unregister.</param> - internal void Unregister(AudioRenderSystem renderer) - { - lock (_sessionLock) - { - int sessionId = renderer.GetSessionId(); - - _sessions[renderer.GetSessionId()] = null; - - ReleaseSessionId(sessionId); - } - - lock (_audioProcessorLock) - { - if (_isRunning && !HasAnyActiveRendererLocked()) - { - StopLocked(); - } - } - } - - /// <summary> - /// Open a new <see cref="AudioRenderSystem"/> - /// </summary> - /// <param name="renderer">The new <see cref="AudioRenderSystem"/></param> - /// <param name="memoryManager">The memory manager that will be used for all guest memory operations.</param> - /// <param name="parameter">The user configuration</param> - /// <param name="appletResourceUserId">The applet resource user id of the application.</param> - /// <param name="workBufferAddress">The guest work buffer address.</param> - /// <param name="workBufferSize">The guest work buffer size.</param> - /// <param name="processHandle">The process handle of the application.</param> - /// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns> - public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, IVirtualMemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle) - { - int sessionId = AcquireSessionId(); - - AudioRenderSystem audioRenderer = new AudioRenderSystem(this, _sessionsSystemEvent[sessionId]); - - ResultCode result = audioRenderer.Initialize(ref parameter, processHandle, workBufferAddress, workBufferSize, sessionId, appletResourceUserId, memoryManager); - - if (result == ResultCode.Success) - { - renderer = audioRenderer; - - Register(renderer); - } - else - { - ReleaseSessionId(sessionId); - - renderer = null; - } - - return result; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - lock (_audioProcessorLock) - { - if (_isRunning) - { - StopLocked(); - } - } - - Processor.Dispose(); - - foreach (HardwareDevice device in OutputDevices) - { - device.Dispose(); - } - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/BehaviourContext.cs b/Ryujinx.Audio.Renderer/Server/BehaviourContext.cs deleted file mode 100644 index 28bcdac5..00000000 --- a/Ryujinx.Audio.Renderer/Server/BehaviourContext.cs +++ /dev/null @@ -1,405 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Diagnostics; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// <summary> - /// Behaviour context. - /// </summary> - /// <remarks>This handles features based on the audio renderer revision provided by the user.</remarks> - public class BehaviourContext - { - /// <summary> - /// The base magic of the Audio Renderer revision. - /// </summary> - public const int BaseRevisionMagic = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('0' << 24); - - /// <summary> - /// REV1: first revision. - /// </summary> - public const int Revision1 = 1 << 24; - - /// <summary> - /// REV2: Added support for splitter and fix GC-ADPCM context not being provided to the DSP. - /// </summary> - /// <remarks>This was added in system update 2.0.0</remarks> - public const int Revision2 = 2 << 24; - - /// <summary> - /// REV3: Incremented the max pre-delay from 150 to 350 for the reverb command and removed the (unused) codec system. - /// </summary> - /// <remarks>This was added in system update 3.0.0</remarks> - public const int Revision3 = 3 << 24; - - /// <summary> - /// REV4: Added USB audio device support and incremented the rendering limit percent to 75%. - /// </summary> - /// <remarks>This was added in system update 4.0.0</remarks> - public const int Revision4 = 4 << 24; - - /// <summary> - /// REV5: <see cref="Parameter.VoiceInParameter.DecodingBehaviour"/>, <see cref="Parameter.VoiceInParameter.FlushWaveBufferCount"/> were added to voice. - /// A new performance frame format (version 2) was added with support for more information about DSP timing. - /// <see cref="Parameter.RendererInfoOutStatus"/> was added to supply the count of update done sent to the DSP. - /// A new version of the command estimator was added to address timing changes caused by the voice changes. - /// Additionally, the rendering limit percent was incremented to 80%. - /// - /// </summary> - /// <remarks>This was added in system update 6.0.0</remarks> - public const int Revision5 = 5 << 24; - - /// <summary> - /// REV6: This fixed a bug in the biquad filter command not clearing up <see cref="Dsp.State.BiquadFilterState"/> with <see cref="Effect.UsageState.New"/> usage state. - /// </summary> - /// <remarks>This was added in system update 6.1.0</remarks> - public const int Revision6 = 6 << 24; - - /// <summary> - /// REV7: Client side (finally) doesn't send all the mix client state to the server and can do partial updates. - /// </summary> - /// <remarks>This was added in system update 8.0.0</remarks> - public const int Revision7 = 7 << 24; - - /// <summary> - /// REV8: - /// Wavebuffer was changed to support more control over loop (you can now specify where to start and end a loop, and how many times to loop). - /// <see cref="Parameter.VoiceInParameter.SrcQuality"/> was added (see <see cref="Parameter.VoiceInParameter.SampleRateConversionQuality"/> for more info). - /// Final leftovers of the codec system were removed. - /// <see cref="Common.SampleFormat.PcmFloat"/> support was added. - /// A new version of the command estimator was added to address timing changes caused by the voice and command changes. - /// </summary> - /// <remarks>This was added in system update 9.0.0</remarks> - public const int Revision8 = 8 << 24; - - /// <summary> - /// Last revision supported by the implementation. - /// </summary> - public const int LastRevision = Revision8; - - /// <summary> - /// Target revision magic supported by the implementation. - /// </summary> - public const int ProcessRevision = BaseRevisionMagic + LastRevision; - - /// <summary> - /// Get the revision number from the revision magic. - /// </summary> - /// <param name="revision">The revision magic.</param> - /// <returns>The revision number.</returns> - public static int GetRevisionNumber(int revision) => (revision - BaseRevisionMagic) >> 24; - - /// <summary> - /// Current active revision. - /// </summary> - public int UserRevision { get; private set; } - - /// <summary> - /// Error storage. - /// </summary> - private ErrorInfo[] _errorInfos; - - /// <summary> - /// Current position in the <see cref="_errorInfos"/> array. - /// </summary> - private uint _errorIndex; - - /// <summary> - /// Current flags of the <see cref="BehaviourContext"/>. - /// </summary> - private ulong _flags; - - /// <summary> - /// Create a new instance of <see cref="BehaviourContext"/>. - /// </summary> - public BehaviourContext() - { - UserRevision = 0; - _errorInfos = new ErrorInfo[RendererConstants.MaxErrorInfos]; - _errorIndex = 0; - } - - /// <summary> - /// Set the active revision. - /// </summary> - /// <param name="userRevision">The active revision.</param> - public void SetUserRevision(int userRevision) - { - UserRevision = userRevision; - } - - /// <summary> - /// Update flags of the <see cref="BehaviourContext"/>. - /// </summary> - /// <param name="flags">The new flags.</param> - public void UpdateFlags(ulong flags) - { - _flags = flags; - } - - /// <summary> - /// Check if a given revision is valid/supported. - /// </summary> - /// <param name="revision">The revision magic to check.</param> - /// <returns>Returns true if the given revision is valid/supported</returns> - public static bool CheckValidRevision(int revision) - { - return GetRevisionNumber(revision) <= GetRevisionNumber(ProcessRevision); - } - - /// <summary> - /// Check if the given revision is greater than or equal the supported revision. - /// </summary> - /// <param name="revision">The revision magic to check.</param> - /// <param name="supportedRevision">The revision magic of the supported revision.</param> - /// <returns>Returns true if the given revision is greater than or equal the supported revision.</returns> - public static bool CheckFeatureSupported(int revision, int supportedRevision) - { - int revA = GetRevisionNumber(revision); - int revB = GetRevisionNumber(supportedRevision); - - if (revA > LastRevision) - { - revA = 1; - } - - if (revB > LastRevision) - { - revB = 1; - } - - return revA >= revB; - } - - /// <summary> - /// Check if the memory pool mapping bypass flag is active. - /// </summary> - /// <returns>True if the memory pool mapping bypass flag is active.</returns> - public bool IsMemoryPoolForceMappingEnabled() - { - return (_flags & 1) != 0; - } - - /// <summary> - /// Check if the audio renderer should fix the GC-ADPCM context not being provided to the DSP. - /// </summary> - /// <returns>True if if the audio renderer should fix it.</returns> - public bool IsAdpcmLoopContextBugFixed() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision2); - } - - /// <summary> - /// Check if the audio renderer should accept splitters. - /// </summary> - /// <returns>True if the audio renderer should accept splitters.</returns> - public bool IsSplitterSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision2); - } - - /// <summary> - /// Check if the audio renderer should use a max pre-delay of 350 instead of 150. - /// </summary> - /// <returns>True if the max pre-delay must be 350.</returns> - public bool IsLongSizePreDelaySupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision3); - } - - /// <summary> - /// Check if the audio renderer should expose USB audio device. - /// </summary> - /// <returns>True if the audio renderer should expose USB audio device.</returns> - public bool IsAudioUsbDeviceOutputSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision4); - } - - /// <summary> - /// Get the percentage allocated to the audio renderer on the DSP for processing. - /// </summary> - /// <returns>The percentage allocated to the audio renderer on the DSP for processing.</returns> - public float GetAudioRendererProcessingTimeLimit() - { - if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5)) - { - return 0.80f; - } - else if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision4)) - { - return 0.75f; - } - - return 0.70f; - } - - /// <summary> - /// Check if the audio render should support voice flushing. - /// </summary> - /// <returns>True if the audio render should support voice flushing.</returns> - public bool IsFlushVoiceWaveBuffersSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5); - } - - /// <summary> - /// Check if the audio renderer should trust the user destination count in <see cref="Splitter.SplitterState.Update(Splitter.SplitterContext, ref Parameter.SplitterInParameter, ReadOnlySpan{byte})"/>. - /// </summary> - /// <returns>True if the audio renderer should trust the user destination count.</returns> - public bool IsSplitterBugFixed() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5); - } - - /// <summary> - /// Check if the audio renderer should supply the elapsed frame count to the user when updating. - /// </summary> - /// <returns>True if the audio renderer should supply the elapsed frame count to the user when updating.</returns> - public bool IsElapsedFrameCountSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5); - } - - /// <summary> - /// Get the performance metric data format version. - /// </summary> - /// <returns>The performance metric data format version.</returns> - public uint GetPerformanceMetricsDataFormat() - { - if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5)) - { - return 2; - } - else - { - return 1; - } - } - - /// <summary> - /// Check if the audio renderer should support <see cref="Parameter.VoiceInParameter.DecodingBehaviour"/>. - /// </summary> - /// <returns>True if the audio renderer should support <see cref="Parameter.VoiceInParameter.DecodingBehaviour"/>.</returns> - public bool IsDecodingBehaviourFlagSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5); - } - - /// <summary> - /// Check if the audio renderer should fix the biquad filter command not clearing up <see cref="Dsp.State.BiquadFilterState"/> with <see cref="Effect.UsageState.New"/> usage state. - /// </summary> - /// <returns>True if the biquad filter state should be cleared.</returns> - public bool IsBiquadFilterEffectStateClearBugFixed() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision6); - } - - /// <summary> - /// Check if the audio renderer should accept partial mix updates. - /// </summary> - /// <returns>True if the audio renderer should accept partial mix updates.</returns> - public bool IsMixInParameterDirtyOnlyUpdateSupported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision7); - } - - /// <summary> - /// Check if the audio renderer should use the new wavebuffer format. - /// </summary> - /// <returns>True if the audio renderer should use the new wavebuffer format.</returns> - public bool IsWaveBufferVersion2Supported() - { - return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision8); - } - - /// <summary> - /// Get the version of the <see cref="ICommandProcessingTimeEstimator"/>. - /// </summary> - /// <returns>The version of the <see cref="ICommandProcessingTimeEstimator"/>.</returns> - public int GetCommandProcessingTimeEstimatorVersion() - { - if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision8)) - { - return 3; - } - - if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision5)) - { - return 2; - } - - return 1; - } - - /// <summary> - /// Append a new <see cref="ErrorInfo"/> to the error array. - /// </summary> - /// <param name="errorInfo">The new <see cref="ErrorInfo"/> to add.</param> - public void AppendError(ref ErrorInfo errorInfo) - { - Debug.Assert(errorInfo.ErrorCode == ResultCode.Success); - - if (_errorIndex <= RendererConstants.MaxErrorInfos - 1) - { - _errorInfos[_errorIndex++] = errorInfo; - } - } - - /// <summary> - /// Copy the internal <see cref="ErrorInfo"/> array to the given <see cref="Span{ErrorInfo}"/> and output the count copied. - /// </summary> - /// <param name="errorInfos">The output <see cref="Span{ErrorInfo}"/>.</param> - /// <param name="errorCount">The output error count containing the count of <see cref="ErrorInfo"/> copied.</param> - public void CopyErrorInfo(Span<ErrorInfo> errorInfos, out uint errorCount) - { - if (errorInfos.Length != RendererConstants.MaxErrorInfos) - { - throw new ArgumentException("Invalid size of errorInfos span!"); - } - - errorCount = Math.Min(_errorIndex, RendererConstants.MaxErrorInfos); - - for (int i = 0; i < RendererConstants.MaxErrorInfos; i++) - { - if (i < errorCount) - { - errorInfos[i] = _errorInfos[i]; - } - else - { - errorInfos[i] = new ErrorInfo - { - ErrorCode = 0, - ExtraErrorInfo = 0 - }; - } - } - } - - /// <summary> - /// Clear the <see cref="ErrorInfo"/> array. - /// </summary> - public void ClearError() - { - _errorIndex = 0; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/CommandBuffer.cs b/Ryujinx.Audio.Renderer/Server/CommandBuffer.cs deleted file mode 100644 index ca37e090..00000000 --- a/Ryujinx.Audio.Renderer/Server/CommandBuffer.cs +++ /dev/null @@ -1,484 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.Command; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.Performance; -using Ryujinx.Audio.Renderer.Server.Sink; -using Ryujinx.Audio.Renderer.Server.Upsampler; -using Ryujinx.Audio.Renderer.Server.Voice; -using System; -using CpuAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// <summary> - /// An API to generate commands and aggregate them into a <see cref="CommandList"/>. - /// </summary> - public class CommandBuffer - { - /// <summary> - /// The command processing time estimator in use. - /// </summary> - private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator; - - /// <summary> - /// The estimated total processing time. - /// </summary> - public ulong EstimatedProcessingTime { get; set; } - - /// <summary> - /// The command list that is populated by the <see cref="CommandBuffer"/>. - /// </summary> - public CommandList CommandList { get; } - - /// <summary> - /// Create a new <see cref="CommandBuffer"/>. - /// </summary> - /// <param name="commandList">The command list that will store the generated commands.</param> - /// <param name="commandProcessingTimeEstimator">The command processing time estimator to use.</param> - public CommandBuffer(CommandList commandList, ICommandProcessingTimeEstimator commandProcessingTimeEstimator) - { - CommandList = commandList; - EstimatedProcessingTime = 0; - _commandProcessingTimeEstimator = commandProcessingTimeEstimator; - } - - /// <summary> - /// Add a new generated command to the <see cref="CommandList"/>. - /// </summary> - /// <param name="command">The command to add.</param> - private void AddCommand(ICommand command) - { - EstimatedProcessingTime += command.EstimatedProcessingTime; - - CommandList.AddCommand(command); - } - - /// <summary> - /// Generate a new <see cref="ClearMixBufferCommand"/>. - /// </summary> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateClearMixBuffer(int nodeId) - { - ClearMixBufferCommand command = new ClearMixBufferCommand(nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Generate a new <see cref="DepopPrepareCommand"/>. - /// </summary> - /// <param name="state">The voice state associated.</param> - /// <param name="depopBuffer">The depop buffer.</param> - /// <param name="bufferCount">The buffer count.</param> - /// <param name="bufferOffset">The target buffer offset.</param> - /// <param name="nodeId">The node id associated to this command.</param> - /// <param name="wasPlaying">Set to true if the voice was playing previously.</param> - public void GenerateDepopPrepare(Memory<VoiceUpdateState> state, Memory<float> depopBuffer, uint bufferCount, uint bufferOffset, int nodeId, bool wasPlaying) - { - DepopPrepareCommand command = new DepopPrepareCommand(state, depopBuffer, bufferCount, bufferOffset, nodeId, wasPlaying); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Generate a new <see cref="PerformanceCommand"/>. - /// </summary> - /// <param name="performanceEntryAddresses">The <see cref="PerformanceEntryAddresses"/>.</param> - /// <param name="type">The performance operation to perform.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GeneratePerformance(ref PerformanceEntryAddresses performanceEntryAddresses, PerformanceCommand.Type type, int nodeId) - { - PerformanceCommand command = new PerformanceCommand(ref performanceEntryAddresses, type, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Create a new <see cref="VolumeRampCommand"/>. - /// </summary> - /// <param name="previousVolume">The previous volume.</param> - /// <param name="volume">The new volume.</param> - /// <param name="bufferIndex">The index of the mix buffer to use.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateVolumeRamp(float previousVolume, float volume, uint bufferIndex, int nodeId) - { - VolumeRampCommand command = new VolumeRampCommand(previousVolume, volume, bufferIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Create a new <see cref="DataSourceVersion2Command"/>. - /// </summary> - /// <param name="voiceState">The <see cref="VoiceState"/> to generate the command from.</param> - /// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param> - /// <param name="outputBufferIndex">The output buffer index to use.</param> - /// <param name="channelIndex">The target channel index.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateDataSourceVersion2(ref VoiceState voiceState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId) - { - DataSourceVersion2Command command = new DataSourceVersion2Command(ref voiceState, state, outputBufferIndex, channelIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Create a new <see cref="PcmInt16DataSourceCommandVersion1"/>. - /// </summary> - /// <param name="voiceState">The <see cref="VoiceState"/> to generate the command from.</param> - /// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param> - /// <param name="outputBufferIndex">The output buffer index to use.</param> - /// <param name="channelIndex">The target channel index.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GeneratePcmInt16DataSourceVersion1(ref VoiceState voiceState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId) - { - PcmInt16DataSourceCommandVersion1 command = new PcmInt16DataSourceCommandVersion1(ref voiceState, state, outputBufferIndex, channelIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Create a new <see cref="PcmFloatDataSourceCommandVersion1"/>. - /// </summary> - /// <param name="voiceState">The <see cref="VoiceState"/> to generate the command from.</param> - /// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param> - /// <param name="outputBufferIndex">The output buffer index to use.</param> - /// <param name="channelIndex">The target channel index.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GeneratePcmFloatDataSourceVersion1(ref VoiceState voiceState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, ushort channelIndex, int nodeId) - { - PcmFloatDataSourceCommandVersion1 command = new PcmFloatDataSourceCommandVersion1(ref voiceState, state, outputBufferIndex, channelIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Create a new <see cref="AdpcmDataSourceCommandVersion1"/>. - /// </summary> - /// <param name="voiceState">The <see cref="VoiceState"/> to generate the command from.</param> - /// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param> - /// <param name="outputBufferIndex">The output buffer index to use.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateAdpcmDataSourceVersion1(ref VoiceState voiceState, Memory<VoiceUpdateState> state, ushort outputBufferIndex, int nodeId) - { - AdpcmDataSourceCommandVersion1 command = new AdpcmDataSourceCommandVersion1(ref voiceState, state, outputBufferIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Create a new <see cref="BiquadFilterCommand"/>. - /// </summary> - /// <param name="baseIndex">The base index of the input and output buffer.</param> - /// <param name="filter">The biquad filter parameter.</param> - /// <param name="biquadFilterStateMemory">The biquad state.</param> - /// <param name="inputBufferOffset">The input buffer offset.</param> - /// <param name="outputBufferOffset">The output buffer offset.</param> - /// <param name="needInitialization">Set to true if the biquad filter state needs to be initialized.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateBiquadFilter(int baseIndex, ref BiquadFilterParameter filter, Memory<BiquadFilterState> biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, bool needInitialization, int nodeId) - { - BiquadFilterCommand command = new BiquadFilterCommand(baseIndex, ref filter, biquadFilterStateMemory, inputBufferOffset, outputBufferOffset, needInitialization, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Generate a new <see cref="MixRampGroupedCommand"/>. - /// </summary> - /// <param name="mixBufferCount">The mix buffer count.</param> - /// <param name="inputBufferIndex">The base input index.</param> - /// <param name="outputBufferIndex">The base output index.</param> - /// <param name="previousVolume">The previous volume.</param> - /// <param name="volume">The new volume.</param> - /// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateMixRampGrouped(uint mixBufferCount, uint inputBufferIndex, uint outputBufferIndex, Span<float> previousVolume, Span<float> volume, Memory<VoiceUpdateState> state, int nodeId) - { - MixRampGroupedCommand command = new MixRampGroupedCommand(mixBufferCount, inputBufferIndex, outputBufferIndex, previousVolume, volume, state, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Generate a new <see cref="MixRampCommand"/>. - /// </summary> - /// <param name="previousVolume">The previous volume.</param> - /// <param name="volume">The new volume.</param> - /// <param name="inputBufferIndex">The input buffer index.</param> - /// <param name="outputBufferIndex">The output buffer index.</param> - /// <param name="lastSampleIndex">The index in the <see cref="VoiceUpdateState.LastSamples"/> array to store the ramped sample.</param> - /// <param name="state">The <see cref="VoiceUpdateState"/> to generate the command from.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateMixRamp(float previousVolume, float volume, uint inputBufferIndex, uint outputBufferIndex, int lastSampleIndex, Memory<VoiceUpdateState> state, int nodeId) - { - MixRampCommand command = new MixRampCommand(previousVolume, volume, inputBufferIndex, outputBufferIndex, lastSampleIndex, state, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Generate a new <see cref="DepopForMixBuffersCommand"/>. - /// </summary> - /// <param name="depopBuffer">The depop buffer.</param> - /// <param name="bufferOffset">The target buffer offset.</param> - /// <param name="bufferCount">The buffer count.</param> - /// <param name="nodeId">The node id associated to this command.</param> - /// <param name="sampleRate">The target sample rate in use.</param> - public void GenerateDepopForMixBuffersCommand(Memory<float> depopBuffer, uint bufferOffset, uint bufferCount, int nodeId, uint sampleRate) - { - DepopForMixBuffersCommand command = new DepopForMixBuffersCommand(depopBuffer, bufferOffset, bufferCount, nodeId, sampleRate); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Generate a new <see cref="CopyMixBufferCommand"/>. - /// </summary> - /// <param name="inputBufferIndex">The input buffer index.</param> - /// <param name="outputBufferIndex">The output buffer index.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateCopyMixBuffer(uint inputBufferIndex, uint outputBufferIndex, int nodeId) - { - CopyMixBufferCommand command = new CopyMixBufferCommand(inputBufferIndex, outputBufferIndex, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Generate a new <see cref="MixCommand"/>. - /// </summary> - /// <param name="inputBufferIndex">The input buffer index.</param> - /// <param name="outputBufferIndex">The output buffer index.</param> - /// <param name="nodeId">The node id associated to this command.</param> - /// <param name="volume">The mix volume.</param> - public void GenerateMix(uint inputBufferIndex, uint outputBufferIndex, int nodeId, float volume) - { - MixCommand command = new MixCommand(inputBufferIndex, outputBufferIndex, nodeId, volume); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Generate a new <see cref="ReverbCommand"/>. - /// </summary> - /// <param name="bufferOffset">The target buffer offset.</param> - /// <param name="parameter">The reverb parameter.</param> - /// <param name="state">The reverb state.</param> - /// <param name="isEnabled">Set to true if the effect should be active.</param> - /// <param name="workBuffer">The work buffer to use for processing.</param> - /// <param name="nodeId">The node id associated to this command.</param> - /// <param name="isLongSizePreDelaySupported">If set to true, the long size pre-delay is supported.</param> - public void GenerateReverbEffect(uint bufferOffset, ReverbParameter parameter, Memory<ReverbState> state, bool isEnabled, CpuAddress workBuffer, int nodeId, bool isLongSizePreDelaySupported) - { - if (parameter.IsChannelCountValid()) - { - ReverbCommand command = new ReverbCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, isLongSizePreDelaySupported); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - } - - /// <summary> - /// Generate a new <see cref="Reverb3dCommand"/>. - /// </summary> - /// <param name="bufferOffset">The target buffer offset.</param> - /// <param name="parameter">The reverb 3d parameter.</param> - /// <param name="state">The reverb 3d state.</param> - /// <param name="isEnabled">Set to true if the effect should be active.</param> - /// <param name="workBuffer">The work buffer to use for processing.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateReverb3dEffect(uint bufferOffset, Reverb3dParameter parameter, Memory<Reverb3dState> state, bool isEnabled, CpuAddress workBuffer, int nodeId) - { - if (parameter.IsChannelCountValid()) - { - Reverb3dCommand command = new Reverb3dCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - } - - - /// <summary> - /// Generate a new <see cref="DelayCommand"/>. - /// </summary> - /// <param name="bufferOffset">The target buffer offset.</param> - /// <param name="parameter">The delay parameter.</param> - /// <param name="state">The delay state.</param> - /// <param name="isEnabled">Set to true if the effect should be active.</param> - /// <param name="workBuffer">The work buffer to use for processing.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateDelayEffect(uint bufferOffset, DelayParameter parameter, Memory<DelayState> state, bool isEnabled, CpuAddress workBuffer, int nodeId) - { - if (parameter.IsChannelCountValid()) - { - DelayCommand command = new DelayCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - } - - /// <summary> - /// Generate a new <see cref="AuxiliaryBufferCommand"/>. - /// </summary> - /// <param name="bufferOffset">The target buffer offset.</param> - /// <param name="inputBufferOffset">The input buffer offset.</param> - /// <param name="outputBufferOffset">The output buffer offset.</param> - /// <param name="state">The aux state.</param> - /// <param name="isEnabled">Set to true if the effect should be active.</param> - /// <param name="countMax">The limit of the circular buffer.</param> - /// <param name="outputBuffer">The guest address of the output buffer.</param> - /// <param name="inputBuffer">The guest address of the input buffer.</param> - /// <param name="updateCount">The count to add on the offset after write/read operations.</param> - /// <param name="writeOffset">The write offset.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateAuxEffect(uint bufferOffset, byte inputBufferOffset, byte outputBufferOffset, ref AuxiliaryBufferAddresses state, bool isEnabled, uint countMax, CpuAddress outputBuffer, CpuAddress inputBuffer, uint updateCount, uint writeOffset, int nodeId) - { - if (state.SendBufferInfoBase != 0 && state.ReturnBufferInfoBase != 0) - { - AuxiliaryBufferCommand command = new AuxiliaryBufferCommand(bufferOffset, inputBufferOffset, outputBufferOffset, ref state, isEnabled, countMax, outputBuffer, inputBuffer, updateCount, writeOffset, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - } - - /// <summary> - /// Generate a new <see cref="VolumeCommand"/>. - /// </summary> - /// <param name="volume">The target volume to apply.</param> - /// <param name="bufferOffset">The offset of the mix buffer.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateVolume(float volume, uint bufferOffset, int nodeId) - { - VolumeCommand command = new VolumeCommand(volume, bufferOffset, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Create a new <see cref="CircularBufferSinkCommand"/>. - /// </summary> - /// <param name="bufferOffset">The offset of the mix buffer.</param> - /// <param name="sink">The <see cref="BaseSink"/> of the circular buffer.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateCircularBuffer(uint bufferOffset, CircularBufferSink sink, int nodeId) - { - CircularBufferSinkCommand command = new CircularBufferSinkCommand(bufferOffset, ref sink.Parameter, ref sink.CircularBufferAddressInfo, sink.CurrentWriteOffset, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Create a new <see cref="DownMixSurroundToStereoCommand"/>. - /// </summary> - /// <param name="bufferOffset">The offset of the mix buffer.</param> - /// <param name="inputBufferOffset">The input buffer offset.</param> - /// <param name="outputBufferOffset">The output buffer offset.</param> - /// <param name="downMixParameter">The downmixer parameters to use.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateDownMixSurroundToStereo(uint bufferOffset, Span<byte> inputBufferOffset, Span<byte> outputBufferOffset, ReadOnlySpan<float> downMixParameter, int nodeId) - { - DownMixSurroundToStereoCommand command = new DownMixSurroundToStereoCommand(bufferOffset, inputBufferOffset, outputBufferOffset, downMixParameter, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Create a new <see cref="UpsampleCommand"/>. - /// </summary> - /// <param name="bufferOffset">The offset of the mix buffer.</param> - /// <param name="upsampler">The <see cref="UpsamplerState"/> associated.</param> - /// <param name="inputCount">The total input count.</param> - /// <param name="inputBufferOffset">The input buffer mix offset.</param> - /// <param name="bufferCountPerSample">The buffer count per sample.</param> - /// <param name="sampleCount">The source sample count.</param> - /// <param name="sampleRate">The source sample rate.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateUpsample(uint bufferOffset, UpsamplerState upsampler, uint inputCount, Span<byte> inputBufferOffset, uint bufferCountPerSample, uint sampleCount, uint sampleRate, int nodeId) - { - UpsampleCommand command = new UpsampleCommand(bufferOffset, upsampler, inputCount, inputBufferOffset, bufferCountPerSample, sampleCount, sampleRate, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - - /// <summary> - /// Create a new <see cref="DeviceSinkCommand"/>. - /// </summary> - /// <param name="bufferOffset">The offset of the mix buffer.</param> - /// <param name="sink">The <see cref="BaseSink"/> of the device sink.</param> - /// <param name="sessionId">The current audio renderer session id.</param> - /// <param name="buffer">The mix buffer in use.</param> - /// <param name="nodeId">The node id associated to this command.</param> - public void GenerateDeviceSink(uint bufferOffset, DeviceSink sink, int sessionId, Memory<float> buffer, int nodeId) - { - DeviceSinkCommand command = new DeviceSinkCommand(bufferOffset, sink, sessionId, buffer, nodeId); - - command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); - - AddCommand(command); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/CommandGenerator.cs b/Ryujinx.Audio.Renderer/Server/CommandGenerator.cs deleted file mode 100644 index 36c438fe..00000000 --- a/Ryujinx.Audio.Renderer/Server/CommandGenerator.cs +++ /dev/null @@ -1,940 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.Command; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.Effect; -using Ryujinx.Audio.Renderer.Server.Mix; -using Ryujinx.Audio.Renderer.Server.Performance; -using Ryujinx.Audio.Renderer.Server.Sink; -using Ryujinx.Audio.Renderer.Server.Splitter; -using Ryujinx.Audio.Renderer.Server.Voice; -using Ryujinx.Audio.Renderer.Utils; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server -{ - public class CommandGenerator - { - private CommandBuffer _commandBuffer; - private RendererSystemContext _rendererContext; - private VoiceContext _voiceContext; - private MixContext _mixContext; - private EffectContext _effectContext; - private SinkContext _sinkContext; - private SplitterContext _splitterContext; - private PerformanceManager _performanceManager; - - public CommandGenerator(CommandBuffer commandBuffer, RendererSystemContext rendererContext, VoiceContext voiceContext, MixContext mixContext, EffectContext effectContext, SinkContext sinkContext, SplitterContext splitterContext, PerformanceManager performanceManager) - { - _commandBuffer = commandBuffer; - _rendererContext = rendererContext; - _voiceContext = voiceContext; - _mixContext = mixContext; - _effectContext = effectContext; - _sinkContext = sinkContext; - _splitterContext = splitterContext; - _performanceManager = performanceManager; - - _commandBuffer.GenerateClearMixBuffer(RendererConstants.InvalidNodeId); - } - - private void GenerateDataSource(ref VoiceState voiceState, Memory<VoiceUpdateState> dspState, int channelIndex) - { - if (voiceState.MixId != RendererConstants.UnusedMixId) - { - ref MixState mix = ref _mixContext.GetState(voiceState.MixId); - - _commandBuffer.GenerateDepopPrepare(dspState, - _rendererContext.DepopBuffer, - mix.BufferCount, - mix.BufferOffset, - voiceState.NodeId, - voiceState.WasPlaying); - } - else if (voiceState.SplitterId != RendererConstants.UnusedSplitterId) - { - int destinationId = 0; - - while (true) - { - Span<SplitterDestination> destinationSpan = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId++); - - if (destinationSpan.IsEmpty) - { - break; - } - - ref SplitterDestination destination = ref destinationSpan[0]; - - if (destination.IsConfigured()) - { - int mixId = destination.DestinationId; - - if (mixId < _mixContext.GetCount() && mixId != RendererConstants.UnusedSplitterIdInt) - { - ref MixState mix = ref _mixContext.GetState(mixId); - - _commandBuffer.GenerateDepopPrepare(dspState, - _rendererContext.DepopBuffer, - mix.BufferCount, - mix.BufferOffset, - voiceState.NodeId, - voiceState.WasPlaying); - - destination.MarkAsNeedToUpdateInternalState(); - } - } - } - } - - if (!voiceState.WasPlaying) - { - Debug.Assert(voiceState.SampleFormat != SampleFormat.Adpcm || channelIndex == 0); - - if (_rendererContext.BehaviourContext.IsWaveBufferVersion2Supported()) - { - _commandBuffer.GenerateDataSourceVersion2(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - (ushort)channelIndex, - voiceState.NodeId); - } - else - { - switch (voiceState.SampleFormat) - { - case SampleFormat.PcmInt16: - _commandBuffer.GeneratePcmInt16DataSourceVersion1(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - (ushort)channelIndex, - voiceState.NodeId); - break; - case SampleFormat.PcmFloat: - _commandBuffer.GeneratePcmFloatDataSourceVersion1(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - (ushort)channelIndex, - voiceState.NodeId); - break; - case SampleFormat.Adpcm: - _commandBuffer.GenerateAdpcmDataSourceVersion1(ref voiceState, - dspState, - (ushort)_rendererContext.MixBufferCount, - voiceState.NodeId); - break; - default: - throw new NotImplementedException($"Unsupported data source {voiceState.SampleFormat}"); - } - } - } - } - - private void GenerateBiquadFilterForVoice(ref VoiceState voiceState, Memory<VoiceUpdateState> state, int baseIndex, int bufferOffset, int nodeId) - { - for (int i = 0; i < voiceState.BiquadFilters.Length; i++) - { - ref BiquadFilterParameter filter = ref voiceState.BiquadFilters[i]; - - if (filter.Enable) - { - Memory<byte> biquadStateRawMemory = SpanMemoryManager<byte>.Cast(state).Slice(VoiceUpdateState.BiquadStateOffset, VoiceUpdateState.BiquadStateSize * RendererConstants.VoiceBiquadFilterCount); - - Memory<BiquadFilterState> stateMemory = SpanMemoryManager<BiquadFilterState>.Cast(biquadStateRawMemory); - - _commandBuffer.GenerateBiquadFilter(baseIndex, - ref filter, - stateMemory.Slice(i, 1), - bufferOffset, - bufferOffset, - !voiceState.BiquadFilterNeedInitialization[i], - nodeId); - } - } - } - - private void GenerateVoiceMix(Span<float> mixVolumes, Span<float> previousMixVolumes, Memory<VoiceUpdateState> state, uint bufferOffset, uint bufferCount, uint bufferIndex, int nodeId) - { - if (bufferCount > RendererConstants.VoiceChannelCountMax) - { - _commandBuffer.GenerateMixRampGrouped(bufferCount, - bufferIndex, - bufferOffset, - previousMixVolumes, - mixVolumes, - state, - nodeId); - } - else - { - for (int i = 0; i < bufferCount; i++) - { - float previousMixVolume = previousMixVolumes[i]; - float mixVolume = mixVolumes[i]; - - if (mixVolume != 0.0f || previousMixVolume != 0.0f) - { - _commandBuffer.GenerateMixRamp(previousMixVolume, - mixVolume, - bufferIndex, - bufferOffset + (uint)i, - i, - state, - nodeId); - } - } - } - } - - private void GenerateVoice(ref VoiceState voiceState) - { - int nodeId = voiceState.NodeId; - uint channelsCount = voiceState.ChannelsCount; - - for (int channelIndex = 0; channelIndex < channelsCount; channelIndex++) - { - Memory<VoiceUpdateState> dspStateMemory = _voiceContext.GetUpdateStateForDsp(voiceState.ChannelResourceIds[channelIndex]); - - ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(voiceState.ChannelResourceIds[channelIndex]); - - PerformanceDetailType dataSourceDetailType = PerformanceDetailType.Adpcm; - - if (voiceState.SampleFormat == SampleFormat.PcmInt16) - { - dataSourceDetailType = PerformanceDetailType.PcmInt16; - } - else if (voiceState.SampleFormat == SampleFormat.PcmFloat) - { - dataSourceDetailType = PerformanceDetailType.PcmFloat; - } - - bool performanceInitialized = false; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, dataSourceDetailType, PerformanceEntryType.Voice, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateDataSource(ref voiceState, dspStateMemory, channelIndex); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - - if (voiceState.WasPlaying) - { - voiceState.PreviousVolume = 0.0f; - } - else if (voiceState.HasAnyDestination()) - { - performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.BiquadFilter, PerformanceEntryType.Voice, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateBiquadFilterForVoice(ref voiceState, dspStateMemory, (int)_rendererContext.MixBufferCount, channelIndex, nodeId); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - - performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.VolumeRamp, PerformanceEntryType.Voice, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - _commandBuffer.GenerateVolumeRamp(voiceState.PreviousVolume, - voiceState.Volume, - _rendererContext.MixBufferCount + (uint)channelIndex, - nodeId); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - - voiceState.PreviousVolume = voiceState.Volume; - - if (voiceState.MixId == RendererConstants.UnusedMixId) - { - if (voiceState.SplitterId != RendererConstants.UnusedSplitterId) - { - int destinationId = channelIndex; - - while (true) - { - Span<SplitterDestination> destinationSpan = _splitterContext.GetDestination((int)voiceState.SplitterId, destinationId); - - if (destinationSpan.IsEmpty) - { - break; - } - - ref SplitterDestination destination = ref destinationSpan[0]; - - destinationId += (int)channelsCount; - - if (destination.IsConfigured()) - { - int mixId = destination.DestinationId; - - if (mixId < _mixContext.GetCount() && mixId != RendererConstants.UnusedSplitterIdInt) - { - ref MixState mix = ref _mixContext.GetState(mixId); - - GenerateVoiceMix(destination.MixBufferVolume, - destination.PreviousMixBufferVolume, - dspStateMemory, - mix.BufferOffset, - mix.BufferCount, - _rendererContext.MixBufferCount + (uint)channelIndex, - nodeId); - - destination.MarkAsNeedToUpdateInternalState(); - } - } - } - } - } - else - { - ref MixState mix = ref _mixContext.GetState(voiceState.MixId); - - performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.Mix, PerformanceEntryType.Voice, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateVoiceMix(channelResource.Mix.ToSpan(), - channelResource.PreviousMix.ToSpan(), - dspStateMemory, - mix.BufferOffset, - mix.BufferCount, - _rendererContext.MixBufferCount + (uint)channelIndex, - nodeId); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - - channelResource.UpdateState(); - } - - for (int i = 0; i < voiceState.BiquadFilterNeedInitialization.Length; i++) - { - voiceState.BiquadFilterNeedInitialization[i] = voiceState.BiquadFilters[i].Enable; - } - } - } - } - - public void GenerateVoices() - { - for (int i = 0; i < _voiceContext.GetCount(); i++) - { - ref VoiceState sortedState = ref _voiceContext.GetSortedState(i); - - if (!sortedState.ShouldSkip() && sortedState.UpdateForCommandGeneration(_voiceContext)) - { - int nodeId = sortedState.NodeId; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, PerformanceEntryType.Voice, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateVoice(ref sortedState); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - } - - _splitterContext.UpdateInternalState(); - } - - public void GeneratePerformance(ref PerformanceEntryAddresses performanceEntryAddresses, PerformanceCommand.Type type, int nodeId) - { - _commandBuffer.GeneratePerformance(ref performanceEntryAddresses, type, nodeId); - } - - private void GenerateBufferMixerEffect(int bufferOffset, BufferMixEffect effect, int nodeId) - { - Debug.Assert(effect.Type == EffectType.BufferMix); - - if (effect.IsEnabled) - { - for (int i = 0; i < effect.Parameter.MixesCount; i++) - { - if (effect.Parameter.Volumes[i] != 0.0f) - { - _commandBuffer.GenerateMix((uint)bufferOffset + effect.Parameter.Input[i], - (uint)bufferOffset + effect.Parameter.Output[i], - nodeId, - effect.Parameter.Volumes[i]); - } - } - } - } - - private void GenerateAuxEffect(uint bufferOffset, AuxiliaryBufferEffect effect, int nodeId) - { - Debug.Assert(effect.Type == EffectType.AuxiliaryBuffer); - - if (effect.IsEnabled) - { - effect.GetWorkBuffer(0); - effect.GetWorkBuffer(1); - } - - if (effect.State.SendBufferInfoBase != 0 && effect.State.ReturnBufferInfoBase != 0) - { - int i = 0; - uint writeOffset = 0; - for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--) - { - uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount; - - uint updateCount; - - if ((channelIndex - 1) != 0) - { - updateCount = 0; - } - else - { - updateCount = newUpdateCount; - } - - _commandBuffer.GenerateAuxEffect(bufferOffset, - effect.Parameter.Input[i], - effect.Parameter.Output[i], - ref effect.State, - effect.IsEnabled, - effect.Parameter.BufferStorageSize, - effect.State.SendBufferInfoBase, - effect.State.ReturnBufferInfoBase, - updateCount, - writeOffset, - nodeId); - - writeOffset = newUpdateCount; - - i++; - } - } - } - - private void GenerateDelayEffect(uint bufferOffset, DelayEffect effect, int nodeId) - { - Debug.Assert(effect.Type == EffectType.Delay); - - ulong workBuffer = effect.GetWorkBuffer(-1); - - _commandBuffer.GenerateDelayEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId); - } - - private void GenerateReverbEffect(uint bufferOffset, ReverbEffect effect, int nodeId, bool isLongSizePreDelaySupported) - { - Debug.Assert(effect.Type == EffectType.Reverb); - - ulong workBuffer = effect.GetWorkBuffer(-1); - - _commandBuffer.GenerateReverbEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId, isLongSizePreDelaySupported); - } - - private void GenerateReverb3dEffect(uint bufferOffset, Reverb3dEffect effect, int nodeId) - { - Debug.Assert(effect.Type == EffectType.Reverb3d); - - ulong workBuffer = effect.GetWorkBuffer(-1); - - _commandBuffer.GenerateReverb3dEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId); - } - - private void GenerateBiquadFilterEffect(uint bufferOffset, BiquadFilterEffect effect, int nodeId) - { - Debug.Assert(effect.Type == EffectType.BiquadFilter); - - if (effect.IsEnabled) - { - bool needInitialization = effect.Parameter.Status == UsageState.Invalid || - (effect.Parameter.Status == UsageState.New && !_rendererContext.BehaviourContext.IsBiquadFilterEffectStateClearBugFixed()); - - BiquadFilterParameter parameter = new BiquadFilterParameter(); - - parameter.Enable = true; - effect.Parameter.Denominator.ToSpan().CopyTo(parameter.Denominator.ToSpan()); - effect.Parameter.Numerator.ToSpan().CopyTo(parameter.Numerator.ToSpan()); - - for (int i = 0; i < effect.Parameter.ChannelCount; i++) - { - _commandBuffer.GenerateBiquadFilter((int)bufferOffset, ref parameter, effect.State.Slice(i, 1), - effect.Parameter.Input[i], - effect.Parameter.Output[i], - needInitialization, - nodeId); - } - } - else - { - for (int i = 0; i < effect.Parameter.ChannelCount; i++) - { - uint inputBufferIndex = bufferOffset + effect.Parameter.Input[i]; - uint outputBufferIndex = bufferOffset + effect.Parameter.Output[i]; - - // If the input and output isn't the same, generate a command. - if (inputBufferIndex != outputBufferIndex) - { - _commandBuffer.GenerateCopyMixBuffer(inputBufferIndex, outputBufferIndex, nodeId); - } - } - } - } - - private void GenerateEffect(ref MixState mix, BaseEffect effect) - { - int nodeId = mix.NodeId; - - bool isFinalMix = mix.MixId == RendererConstants.FinalMixId; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, effect.GetPerformanceDetailType(), - isFinalMix ? PerformanceEntryType.FinalMix : PerformanceEntryType.SubMix, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - switch (effect.Type) - { - case EffectType.BufferMix: - GenerateBufferMixerEffect((int)mix.BufferOffset, (BufferMixEffect)effect, nodeId); - break; - case EffectType.AuxiliaryBuffer: - GenerateAuxEffect(mix.BufferOffset, (AuxiliaryBufferEffect)effect, nodeId); - break; - case EffectType.Delay: - GenerateDelayEffect(mix.BufferOffset, (DelayEffect)effect, nodeId); - break; - case EffectType.Reverb: - GenerateReverbEffect(mix.BufferOffset, (ReverbEffect)effect, nodeId, mix.IsLongSizePreDelaySupported); - break; - case EffectType.Reverb3d: - GenerateReverb3dEffect(mix.BufferOffset, (Reverb3dEffect)effect, nodeId); - break; - case EffectType.BiquadFilter: - GenerateBiquadFilterEffect(mix.BufferOffset, (BiquadFilterEffect)effect, nodeId); - break; - default: - throw new NotImplementedException($"Unsupported effect type {effect.Type}"); - } - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - - effect.UpdateForCommandGeneration(); - } - - private void GenerateEffects(ref MixState mix) - { - ReadOnlySpan<int> effectProcessingOrderArray = mix.EffectProcessingOrderArray; - - Debug.Assert(_effectContext.GetCount() == 0 || !effectProcessingOrderArray.IsEmpty); - - for (int i = 0; i < _effectContext.GetCount(); i++) - { - int effectOrder = effectProcessingOrderArray[i]; - - if (effectOrder == RendererConstants.InvalidProcessingOrder) - { - break; - } - - // BaseEffect is a class, we don't need to pass it by ref - BaseEffect effect = _effectContext.GetEffect(effectOrder); - - Debug.Assert(effect.Type != EffectType.Invalid); - Debug.Assert(effect.MixId == mix.MixId); - - if (!effect.ShouldSkip()) - { - GenerateEffect(ref mix, effect); - } - } - } - - private void GenerateMix(ref MixState mix) - { - if (mix.HasAnyDestination()) - { - Debug.Assert(mix.DestinationMixId != RendererConstants.UnusedMixId || mix.DestinationSplitterId != RendererConstants.UnusedSplitterId); - - if (mix.DestinationMixId == RendererConstants.UnusedMixId) - { - if (mix.DestinationSplitterId != RendererConstants.UnusedSplitterId) - { - int destinationId = 0; - - while (true) - { - int destinationIndex = destinationId++; - - Span<SplitterDestination> destinationSpan = _splitterContext.GetDestination((int)mix.DestinationSplitterId, destinationIndex); - - if (destinationSpan.IsEmpty) - { - break; - } - - ref SplitterDestination destination = ref destinationSpan[0]; - - if (destination.IsConfigured()) - { - int mixId = destination.DestinationId; - - if (mixId < _mixContext.GetCount() && mixId != RendererConstants.UnusedSplitterIdInt) - { - ref MixState destinationMix = ref _mixContext.GetState(mixId); - - uint inputBufferIndex = mix.BufferOffset + ((uint)destinationIndex % mix.BufferCount); - - for (uint bufferDestinationIndex = 0; bufferDestinationIndex < destinationMix.BufferCount; bufferDestinationIndex++) - { - float volume = mix.Volume * destination.GetMixVolume((int)bufferDestinationIndex); - - if (volume != 0.0f) - { - _commandBuffer.GenerateMix(inputBufferIndex, - destinationMix.BufferOffset + bufferDestinationIndex, - mix.NodeId, - volume); - } - } - } - } - } - } - } - else - { - ref MixState destinationMix = ref _mixContext.GetState(mix.DestinationMixId); - - for (uint bufferIndex = 0; bufferIndex < mix.BufferCount; bufferIndex++) - { - for (uint bufferDestinationIndex = 0; bufferDestinationIndex < destinationMix.BufferCount; bufferDestinationIndex++) - { - float volume = mix.Volume * mix.GetMixBufferVolume((int)bufferIndex, (int)bufferDestinationIndex); - - if (volume != 0.0f) - { - _commandBuffer.GenerateMix(mix.BufferOffset + bufferIndex, - destinationMix.BufferOffset + bufferDestinationIndex, - mix.NodeId, - volume); - } - } - } - } - } - } - - private void GenerateSubMix(ref MixState subMix) - { - _commandBuffer.GenerateDepopForMixBuffersCommand(_rendererContext.DepopBuffer, - subMix.BufferOffset, - subMix.BufferCount, - subMix.NodeId, - subMix.SampleRate); - - GenerateEffects(ref subMix); - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - int nodeId = subMix.NodeId; - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.Mix, PerformanceEntryType.SubMix, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateMix(ref subMix); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - - public void GenerateSubMixes() - { - for (int id = 0; id < _mixContext.GetCount(); id++) - { - ref MixState sortedState = ref _mixContext.GetSortedState(id); - - if (sortedState.IsUsed && sortedState.MixId != RendererConstants.FinalMixId) - { - int nodeId = sortedState.NodeId; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, PerformanceEntryType.SubMix, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateSubMix(ref sortedState); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - } - } - - private void GenerateFinalMix() - { - ref MixState finalMix = ref _mixContext.GetFinalState(); - - _commandBuffer.GenerateDepopForMixBuffersCommand(_rendererContext.DepopBuffer, - finalMix.BufferOffset, - finalMix.BufferCount, - finalMix.NodeId, - finalMix.SampleRate); - - GenerateEffects(ref finalMix); - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - int nodeId = finalMix.NodeId; - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.Mix, PerformanceEntryType.FinalMix, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - // Only generate volume command if the volume isn't 100%. - if (finalMix.Volume != 1.0f) - { - for (uint bufferIndex = 0; bufferIndex < finalMix.BufferCount; bufferIndex++) - { - bool performanceSubInitialized = false; - - if (_performanceManager != null && _performanceManager.IsTargetNodeId(nodeId) && _performanceManager.GetNextEntry(out performanceEntry, PerformanceDetailType.VolumeRamp, PerformanceEntryType.FinalMix, nodeId)) - { - performanceSubInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - _commandBuffer.GenerateVolume(finalMix.Volume, - finalMix.BufferOffset + bufferIndex, - nodeId); - - if (performanceSubInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - } - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - - public void GenerateFinalMixes() - { - int nodeId = _mixContext.GetFinalState().NodeId; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - bool performanceInitialized = false; - - if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, PerformanceEntryType.FinalMix, nodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, nodeId); - } - - GenerateFinalMix(); - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, nodeId); - } - } - - private void GenerateCircularBuffer(CircularBufferSink sink, ref MixState finalMix) - { - _commandBuffer.GenerateCircularBuffer(finalMix.BufferOffset, sink, RendererConstants.InvalidNodeId); - } - - private void GenerateDevice(DeviceSink sink, ref MixState finalMix) - { - if (_commandBuffer.CommandList.SampleRate != 48000 && sink.UpsamplerState == null) - { - sink.UpsamplerState = _rendererContext.UpsamplerManager.Allocate(); - } - - bool useCustomDownMixingCommand = _rendererContext.ChannelCount == 2 && sink.Parameter.DownMixParameterEnabled; - - if (useCustomDownMixingCommand) - { - _commandBuffer.GenerateDownMixSurroundToStereo(finalMix.BufferOffset, - sink.Parameter.Input.ToSpan(), - sink.Parameter.Input.ToSpan(), - sink.DownMixCoefficients, - RendererConstants.InvalidNodeId); - } - // NOTE: we do the downmixing at the DSP level as right now the renderer interface doesn't use audout. - // TODO: Remove this when audout is rewritten. - else if (_rendererContext.ChannelCount == 2 && sink.Parameter.InputCount == 6) - { - _commandBuffer.GenerateDownMixSurroundToStereo(finalMix.BufferOffset, - sink.Parameter.Input.ToSpan(), - sink.Parameter.Input.ToSpan(), - RendererConstants.DefaultSurroundToStereoCoefficients, - RendererConstants.InvalidNodeId); - } - - CommandList commandList = _commandBuffer.CommandList; - - if (sink.UpsamplerState != null) - { - _commandBuffer.GenerateUpsample(finalMix.BufferOffset, - sink.UpsamplerState, - sink.Parameter.InputCount, - sink.Parameter.Input.ToSpan(), - commandList.BufferCount, - commandList.SampleCount, - commandList.SampleRate, - RendererConstants.InvalidNodeId); - } - - _commandBuffer.GenerateDeviceSink(finalMix.BufferOffset, - sink, - _rendererContext.SessionId, - commandList.Buffers, - RendererConstants.InvalidNodeId); - } - - private void GenerateSink(BaseSink sink, ref MixState finalMix) - { - bool performanceInitialized = false; - - PerformanceEntryAddresses performanceEntry = new PerformanceEntryAddresses(); - - if (_performanceManager != null && _performanceManager.GetNextEntry(out performanceEntry, PerformanceEntryType.Sink, sink.NodeId)) - { - performanceInitialized = true; - - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.Start, sink.NodeId); - } - - if (!sink.ShouldSkip) - { - switch (sink.Type) - { - case SinkType.CircularBuffer: - GenerateCircularBuffer((CircularBufferSink)sink, ref finalMix); - break; - case SinkType.Device: - GenerateDevice((DeviceSink)sink, ref finalMix); - break; - default: - throw new NotImplementedException($"Unsupported sink type {sink.Type}"); - } - - sink.UpdateForCommandGeneration(); - } - - if (performanceInitialized) - { - GeneratePerformance(ref performanceEntry, PerformanceCommand.Type.End, sink.NodeId); - } - } - - public void GenerateSinks() - { - ref MixState finalMix = ref _mixContext.GetFinalState(); - - for (int i = 0; i < _sinkContext.GetCount(); i++) - { - // BaseSink is a class, we don't need to pass it by ref - BaseSink sink = _sinkContext.GetSink(i); - - if (sink.IsUsed) - { - GenerateSink(sink, ref finalMix); - } - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs b/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs deleted file mode 100644 index 81d3b57b..00000000 --- a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion1.cs +++ /dev/null @@ -1,180 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp.Command; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// <summary> - /// <see cref="ICommandProcessingTimeEstimator"/> version 1. - /// </summary> - public class CommandProcessingTimeEstimatorVersion1 : ICommandProcessingTimeEstimator - { - private uint _sampleCount; - private uint _bufferCount; - - public CommandProcessingTimeEstimatorVersion1(uint sampleCount, uint bufferCount) - { - _sampleCount = sampleCount; - _bufferCount = bufferCount; - } - - public uint Estimate(PerformanceCommand command) - { - return 1454; - } - - public uint Estimate(ClearMixBufferCommand command) - { - return (uint)(_sampleCount * 0.83f * _bufferCount * 1.2f); - } - - public uint Estimate(BiquadFilterCommand command) - { - return (uint)(_sampleCount * 58.0f * 1.2f); - } - - public uint Estimate(MixRampGroupedCommand command) - { - int volumeCount = 0; - - for (int i = 0; i < command.MixBufferCount; i++) - { - if (command.Volume0[i] != 0.0f || command.Volume1[i] != 0.0f) - { - volumeCount++; - } - } - - return (uint)(_sampleCount * 14.4f * 1.2f * volumeCount); - } - - public uint Estimate(MixRampCommand command) - { - return (uint)(_sampleCount * 14.4f * 1.2f); - } - - public uint Estimate(DepopPrepareCommand command) - { - return 1080; - } - - public uint Estimate(VolumeRampCommand command) - { - return (uint)(_sampleCount * 9.8f * 1.2f); - } - - public uint Estimate(PcmInt16DataSourceCommandVersion1 command) - { - return (uint)(command.Pitch * 0.25f * 1.2f); - } - - public uint Estimate(AdpcmDataSourceCommandVersion1 command) - { - return (uint)(command.Pitch * 0.46f * 1.2f); - } - - public uint Estimate(DepopForMixBuffersCommand command) - { - return (uint)(_sampleCount * 8.9f * command.MixBufferCount); - } - - public uint Estimate(CopyMixBufferCommand command) - { - // NOTE: Nintendo returns 0 here for some reasons even if it will generate a command like that on version 1.. maybe a mistake? - return 0; - } - - public uint Estimate(MixCommand command) - { - return (uint)(_sampleCount * 10.0f * 1.2f); - } - - public uint Estimate(DelayCommand command) - { - return (uint)(_sampleCount * command.Parameter.ChannelCount * 202.5f); - } - - public uint Estimate(ReverbCommand command) - { - Debug.Assert(command.Parameter.IsChannelCountValid()); - - if (command.Enabled) - { - return (uint)(750 * _sampleCount * command.Parameter.ChannelCount * 1.2f); - } - - return 0; - } - - public uint Estimate(Reverb3dCommand command) - { - if (command.Enabled) - { - return (uint)(530 * _sampleCount * command.Parameter.ChannelCount * 1.2f); - } - - return 0; - } - - public uint Estimate(AuxiliaryBufferCommand command) - { - if (command.Enabled) - { - return 15956; - } - - return 3765; - } - - public uint Estimate(VolumeCommand command) - { - return (uint)(_sampleCount * 8.8f * 1.2f); - } - - public uint Estimate(CircularBufferSinkCommand command) - { - return 55; - } - - public uint Estimate(DownMixSurroundToStereoCommand command) - { - return 16108; - } - - public uint Estimate(UpsampleCommand command) - { - return 357915; - } - - public uint Estimate(DeviceSinkCommand command) - { - return 10042; - } - - public uint Estimate(PcmFloatDataSourceCommandVersion1 command) - { - return 0; - } - - public uint Estimate(DataSourceVersion2Command command) - { - return 0; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs b/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs deleted file mode 100644 index 0f4fe3c2..00000000 --- a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs +++ /dev/null @@ -1,544 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp.Command; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// <summary> - /// <see cref="ICommandProcessingTimeEstimator"/> version 2. (added with REV5) - /// </summary> - public class CommandProcessingTimeEstimatorVersion2 : ICommandProcessingTimeEstimator - { - private uint _sampleCount; - private uint _bufferCount; - - public CommandProcessingTimeEstimatorVersion2(uint sampleCount, uint bufferCount) - { - _sampleCount = sampleCount; - _bufferCount = bufferCount; - } - - public uint Estimate(PerformanceCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)489.35f; - } - - return (uint)491.18f; - } - - public uint Estimate(ClearMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 668.8f; - float baseCost = 193.2f; - - if (_sampleCount == 160) - { - costPerBuffer = 260.4f; - baseCost = 139.65f; - } - - return (uint)(baseCost + costPerBuffer * _bufferCount); - } - - public uint Estimate(BiquadFilterCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)4813.2f; - } - - return (uint)6915.4f; - } - - public uint Estimate(MixRampGroupedCommand command) - { - const float costPerSample = 7.245f; - - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - int volumeCount = 0; - - for (int i = 0; i < command.MixBufferCount; i++) - { - if (command.Volume0[i] != 0.0f || command.Volume1[i] != 0.0f) - { - volumeCount++; - } - } - - return (uint)(_sampleCount * costPerSample * volumeCount); - } - - public uint Estimate(MixRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1859.0f; - } - - return (uint)2286.1f; - } - - public uint Estimate(DepopPrepareCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)306.62f; - } - - return (uint)293.22f; - } - - public uint Estimate(VolumeRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1403.9f; - } - - return (uint)1884.3f; - } - - public uint Estimate(PcmInt16DataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 1195.5f; - float baseCost = 7797.0f; - - if (_sampleCount == 160) - { - costPerSample = 749.27f; - baseCost = 6138.9f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(AdpcmDataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3564.1f; - float baseCost = 6225.5f; - - if (_sampleCount == 160) - { - costPerSample = 2125.6f; - baseCost = 9039.5f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DepopForMixBuffersCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)762.96f; - } - - return (uint)726.96f; - } - - public uint Estimate(CopyMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)836.32f; - } - - return (uint)1000.9f; - } - - public uint Estimate(MixCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1342.2f; - } - - return (uint)1833.2f; - } - - public uint Estimate(DelayCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)41636.0f; - case 2: - return (uint)97861.0f; - case 4: - return (uint)192520.0f; - case 6: - return (uint)301760.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)578.53f; - case 2: - return (uint)663.06f; - case 4: - return (uint)703.98f; - case 6: - return (uint)760.03f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)8770.3f; - case 2: - return (uint)25741.0f; - case 4: - return (uint)47551.0f; - case 6: - return (uint)81629.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)521.28f; - case 2: - return (uint)585.4f; - case 4: - return (uint)629.88f; - case 6: - return (uint)713.57f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(ReverbCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)97192.0f; - case 2: - return (uint)103280.0f; - case 4: - return (uint)109580.0f; - case 6: - return (uint)115070.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)492.01f; - case 2: - return (uint)554.46f; - case 4: - return (uint)595.86f; - case 6: - return (uint)656.62f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)136460.0f; - case 2: - return (uint)145750.0f; - case 4: - return (uint)154800.0f; - case 6: - return (uint)161970.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)495.79f; - case 2: - return (uint)527.16f; - case 4: - return (uint)598.75f; - case 6: - return (uint)666.03f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(Reverb3dCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)138840.0f; - case 2: - return (uint)135430.0f; - case 4: - return (uint)199180.0f; - case 6: - return (uint)247350.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)718.7f; - case 2: - return (uint)751.3f; - case 4: - return (uint)797.46f; - case 6: - return (uint)867.43f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)199950.0f; - case 2: - return (uint)195200.0f; - case 4: - return (uint)290580.0f; - case 6: - return (uint)363490.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)534.24f; - case 2: - return (uint)570.87f; - case 4: - return (uint)660.93f; - case 6: - return (uint)694.6f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(AuxiliaryBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - return (uint)7177.9f; - } - - return (uint)489.16f; - } - - if (command.Enabled) - { - return (uint)9499.8f; - } - - return (uint)485.56f; - } - - public uint Estimate(VolumeCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1280.3f; - } - - return (uint)1737.8f; - } - - public uint Estimate(CircularBufferSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 1726.0f; - float baseCost = 1369.7f; - - if (_sampleCount == 160) - { - costPerBuffer = 853.63f; - baseCost = 1284.5f; - } - - return (uint)(baseCost + costPerBuffer * command.InputCount); - } - - public uint Estimate(DownMixSurroundToStereoCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)10009.0f; - } - - return (uint)14577.0f; - } - - public uint Estimate(UpsampleCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)292000.0f; - } - - return (uint)0.0f; - } - - public uint Estimate(DeviceSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - Debug.Assert(command.InputCount == 2 || command.InputCount == 6); - - if (command.InputCount == 2) - { - if (_sampleCount == 160) - { - return (uint)9261.5f; - } - - return (uint)9336.1f; - } - - if (_sampleCount == 160) - { - return (uint)9111.8f; - } - - return (uint)9566.7f; - } - - public uint Estimate(PcmFloatDataSourceCommandVersion1 command) - { - // NOTE: This was added between REV7 and REV8 and for some reasons the estimator v2 was changed... - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3490.9f; - float baseCost = 10091.0f; - - if (_sampleCount == 160) - { - costPerSample = 2310.4f; - baseCost = 7845.3f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DataSourceVersion2Command command) - { - return 0; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs b/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs deleted file mode 100644 index 8e15d642..00000000 --- a/Ryujinx.Audio.Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs +++ /dev/null @@ -1,635 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.Command; -using System; -using System.Diagnostics; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// <summary> - /// <see cref="ICommandProcessingTimeEstimator"/> version 3. (added with REV8) - /// </summary> - public class CommandProcessingTimeEstimatorVersion3 : ICommandProcessingTimeEstimator - { - private uint _sampleCount; - private uint _bufferCount; - - public CommandProcessingTimeEstimatorVersion3(uint sampleCount, uint bufferCount) - { - _sampleCount = sampleCount; - _bufferCount = bufferCount; - } - - public uint Estimate(PerformanceCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)498.17f; - } - - return (uint)489.42f; - } - - public uint Estimate(ClearMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 440.68f; - float baseCost = 0; - - if (_sampleCount == 160) - { - costPerBuffer = 266.65f; - } - - return (uint)(baseCost + costPerBuffer * _bufferCount); - } - - public uint Estimate(BiquadFilterCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)4173.2f; - } - - return (uint)5585.1f; - } - - public uint Estimate(MixRampGroupedCommand command) - { - float costPerSample = 6.4434f; - - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - costPerSample = 6.708f; - } - - int volumeCount = 0; - - for (int i = 0; i < command.MixBufferCount; i++) - { - if (command.Volume0[i] != 0.0f || command.Volume1[i] != 0.0f) - { - volumeCount++; - } - } - - return (uint)(_sampleCount * costPerSample * volumeCount); - } - - public uint Estimate(MixRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1968.7f; - } - - return (uint)2459.4f; - } - - public uint Estimate(DepopPrepareCommand command) - { - return 0; - } - - public uint Estimate(VolumeRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1425.3f; - } - - return (uint)1700.0f; - } - - public uint Estimate(PcmInt16DataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 710.143f; - float baseCost = 7853.286f; - - if (_sampleCount == 160) - { - costPerSample = 427.52f; - baseCost = 6329.442f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(AdpcmDataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3564.1f; - float baseCost = 9736.702f; - - if (_sampleCount == 160) - { - costPerSample = 2125.6f; - baseCost = 7913.808f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DepopForMixBuffersCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)739.64f; - } - - return (uint)910.97f; - } - - public uint Estimate(CopyMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)842.59f; - } - - return (uint)986.72f; - } - - public uint Estimate(MixCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1402.8f; - } - - return (uint)1853.2f; - } - - public uint Estimate(DelayCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)8929.04f; - case 2: - return (uint)25500.75f; - case 4: - return (uint)47759.62f; - case 6: - return (uint)82203.07f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)1295.20f; - case 2: - return (uint)1213.60f; - case 4: - return (uint)942.03f; - case 6: - return (uint)1001.55f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)11941.05f; - case 2: - return (uint)37197.37f; - case 4: - return (uint)69749.84f; - case 6: - return (uint)120042.40f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)997.67f; - case 2: - return (uint)977.63f; - case 4: - return (uint)792.30f; - case 6: - return (uint)875.43f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(ReverbCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)81475.05f; - case 2: - return (uint)84975.0f; - case 4: - return (uint)91625.15f; - case 6: - return (uint)95332.27f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)536.30f; - case 2: - return (uint)588.70f; - case 4: - return (uint)643.70f; - case 6: - return (uint)706.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)120174.47f; - case 2: - return (uint)25262.22f; - case 4: - return (uint)135751.23f; - case 6: - return (uint)141129.23f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)617.64f; - case 2: - return (uint)659.54f; - case 4: - return (uint)711.43f; - case 6: - return (uint)778.07f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(Reverb3dCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)116754.0f; - case 2: - return (uint)125912.05f; - case 4: - return (uint)146336.03f; - case 6: - return (uint)165812.66f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)734.0f; - case 2: - return (uint)766.62f; - case 4: - return (uint)797.46f; - case 6: - return (uint)867.43f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)170292.34f; - case 2: - return (uint)183875.63f; - case 4: - return (uint)214696.19f; - case 6: - return (uint)243846.77f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)508.47f; - case 2: - return (uint)582.45f; - case 4: - return (uint)626.42f; - case 6: - return (uint)682.47f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(AuxiliaryBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - return (uint)7182.14f; - } - - return (uint)472.11f; - } - - if (command.Enabled) - { - return (uint)9435.96f; - } - - return (uint)462.62f; - } - - public uint Estimate(VolumeCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1311.1f; - } - - return (uint)1713.6f; - } - - public uint Estimate(CircularBufferSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 770.26f; - float baseCost = 0f; - - if (_sampleCount == 160) - { - costPerBuffer = 531.07f; - } - - return (uint)(baseCost + costPerBuffer * command.InputCount); - } - - public uint Estimate(DownMixSurroundToStereoCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)9949.7f; - } - - return (uint)14679.0f; - } - - public uint Estimate(UpsampleCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)312990.0f; - } - - return (uint)0.0f; - } - - public uint Estimate(DeviceSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - Debug.Assert(command.InputCount == 2 || command.InputCount == 6); - - if (command.InputCount == 2) - { - if (_sampleCount == 160) - { - return (uint)8980.0f; - } - - return (uint)9221.9f; - } - - if (_sampleCount == 160) - { - return (uint)9177.9f; - } - - return (uint)9725.9f; - } - - public uint Estimate(PcmFloatDataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3490.9f; - float baseCost = 10090.9f; - - if (_sampleCount == 160) - { - costPerSample = 2310.4f; - baseCost = 7845.25f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DataSourceVersion2Command command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - (float baseCost, float costPerSample) = GetCostByFormat(_sampleCount, command.SampleFormat, command.SrcQuality); - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f) - 1.0f))); - } - - private static (float, float) GetCostByFormat(uint sampleCount, SampleFormat format, SampleRateConversionQuality quality) - { - Debug.Assert(sampleCount == 160 || sampleCount == 240); - - switch (format) - { - case SampleFormat.PcmInt16: - switch (quality) - { - case SampleRateConversionQuality.Default: - if (sampleCount == 160) - { - return (6329.44f, 427.52f); - } - - return (7853.28f, 710.14f); - case SampleRateConversionQuality.High: - if (sampleCount == 160) - { - return (8049.42f, 371.88f); - } - - return (10138.84f, 610.49f); - case SampleRateConversionQuality.Low: - if (sampleCount == 160) - { - return (5062.66f, 423.43f); - } - - return (5810.96f, 676.72f); - default: - throw new NotImplementedException($"{format} {quality}"); - } - case SampleFormat.PcmFloat: - switch (quality) - { - case SampleRateConversionQuality.Default: - if (sampleCount == 160) - { - return (7845.25f, 2310.4f); - } - - return (10090.9f, 3490.9f); - case SampleRateConversionQuality.High: - if (sampleCount == 160) - { - return (9446.36f, 2308.91f); - } - - return (12520.85f, 3480.61f); - case SampleRateConversionQuality.Low: - if (sampleCount == 160) - { - return (9446.36f, 2308.91f); - } - - return (12520.85f, 3480.61f); - default: - throw new NotImplementedException($"{format} {quality}"); - } - case SampleFormat.Adpcm: - switch (quality) - { - case SampleRateConversionQuality.Default: - if (sampleCount == 160) - { - return (7913.81f, 1827.66f); - } - - return (9736.70f, 2756.37f); - case SampleRateConversionQuality.High: - if (sampleCount == 160) - { - return (9607.81f, 1829.29f); - } - - return (12154.38f, 2731.31f); - case SampleRateConversionQuality.Low: - if (sampleCount == 160) - { - return (6517.48f, 1824.61f); - } - - return (7929.44f, 2732.15f); - default: - throw new NotImplementedException($"{format} {quality}"); - } - default: - throw new NotImplementedException($"{format}"); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/AuxiliaryBufferEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/AuxiliaryBufferEffect.cs deleted file mode 100644 index df82945b..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/AuxiliaryBufferEffect.cs +++ /dev/null @@ -1,92 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -using DspAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// <summary> - /// Server state for an auxiliary buffer effect. - /// </summary> - public class AuxiliaryBufferEffect : BaseEffect - { - /// <summary> - /// The auxiliary buffer parameter. - /// </summary> - public AuxiliaryBufferParameter Parameter; - - /// <summary> - /// Auxiliary buffer state. - /// </summary> - public AuxiliaryBufferAddresses State; - - public override EffectType TargetEffectType => EffectType.AuxiliaryBuffer; - - public override DspAddress GetWorkBuffer(int index) - { - return WorkBuffers[index].GetReference(true); - } - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - UpdateParameterBase(ref parameter); - - Parameter = MemoryMarshal.Cast<byte, AuxiliaryBufferParameter>(parameter.SpecificData)[0]; - IsEnabled = parameter.IsEnabled; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - - if (BufferUnmapped || parameter.IsNew) - { - ulong bufferSize = (ulong)Unsafe.SizeOf<int>() * Parameter.BufferStorageSize + (ulong)Unsafe.SizeOf<AuxiliaryBufferHeader>() * 2; - - bool sendBufferUnmapped = !mapper.TryAttachBuffer(out updateErrorInfo, ref WorkBuffers[0], Parameter.SendBufferInfoAddress, bufferSize); - bool returnBufferUnmapped = !mapper.TryAttachBuffer(out updateErrorInfo, ref WorkBuffers[1], Parameter.ReturnBufferInfoAddress, bufferSize); - - BufferUnmapped = sendBufferUnmapped && returnBufferUnmapped; - - if (!BufferUnmapped) - { - DspAddress sendDspAddress = WorkBuffers[0].GetReference(false); - DspAddress returnDspAddress = WorkBuffers[1].GetReference(false); - - State.SendBufferInfo = sendDspAddress + (uint)Unsafe.SizeOf<AuxiliaryBufferHeader>(); - State.SendBufferInfoBase = sendDspAddress + (uint)Unsafe.SizeOf<AuxiliaryBufferHeader>() * 2; - - State.ReturnBufferInfo = returnDspAddress + (uint)Unsafe.SizeOf<AuxiliaryBufferHeader>(); - State.ReturnBufferInfoBase = returnDspAddress + (uint)Unsafe.SizeOf<AuxiliaryBufferHeader>() * 2; - } - } - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/BaseEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/BaseEffect.cs deleted file mode 100644 index 7c491fd1..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/BaseEffect.cs +++ /dev/null @@ -1,257 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using Ryujinx.Audio.Renderer.Utils; -using System; -using System.Diagnostics; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; - -using DspAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// <summary> - /// Base class used as a server state for an effect. - /// </summary> - public class BaseEffect - { - /// <summary> - /// The <see cref="EffectType"/> of the effect. - /// </summary> - public EffectType Type; - - /// <summary> - /// Set to true if the effect must be active. - /// </summary> - public bool IsEnabled; - - /// <summary> - /// Set to true if the internal effect work buffers used wasn't mapped. - /// </summary> - public bool BufferUnmapped; - - /// <summary> - /// The current state of the effect. - /// </summary> - public UsageState UsageState; - - /// <summary> - /// The target mix id of the effect. - /// </summary> - public int MixId; - - /// <summary> - /// Position of the effect while processing effects. - /// </summary> - public uint ProcessingOrder; - - /// <summary> - /// Array of all the work buffer used by the effect. - /// </summary> - protected AddressInfo[] WorkBuffers; - - /// <summary> - /// Create a new <see cref="BaseEffect"/>. - /// </summary> - public BaseEffect() - { - Type = TargetEffectType; - UsageState = UsageState.Invalid; - - IsEnabled = false; - BufferUnmapped = false; - MixId = RendererConstants.UnusedMixId; - ProcessingOrder = uint.MaxValue; - - WorkBuffers = new AddressInfo[2]; - - foreach (ref AddressInfo info in WorkBuffers.AsSpan()) - { - info = AddressInfo.Create(); - } - } - - /// <summary> - /// The target <see cref="EffectType"/> handled by this <see cref="BaseEffect"/>. - /// </summary> - public virtual EffectType TargetEffectType => EffectType.Invalid; - - /// <summary> - /// Check if the <see cref="EffectType"/> sent by the user match the internal <see cref="EffectType"/>. - /// </summary> - /// <param name="parameter">The user parameter.</param> - /// <returns>Returns true if the <see cref="EffectType"/> sent by the user matches the internal <see cref="EffectType"/>.</returns> - public bool IsTypeValid(ref EffectInParameter parameter) - { - return parameter.Type == TargetEffectType; - } - - /// <summary> - /// Update the usage state during command generation. - /// </summary> - protected void UpdateUsageStateForCommandGeneration() - { - UsageState = IsEnabled ? UsageState.Enabled : UsageState.Disabled; - } - - /// <summary> - /// Update the internal common parameters from a user parameter. - /// </summary> - /// <param name="parameter">The user parameter.</param> - protected void UpdateParameterBase(ref EffectInParameter parameter) - { - MixId = parameter.MixId; - ProcessingOrder = parameter.ProcessingOrder; - } - - /// <summary> - /// Force unmap all the work buffers. - /// </summary> - /// <param name="mapper">The mapper to use.</param> - public void ForceUnmapBuffers(PoolMapper mapper) - { - foreach (ref AddressInfo info in WorkBuffers.AsSpan()) - { - if (info.GetReference(false) != 0) - { - mapper.ForceUnmap(ref info); - } - } - } - - /// <summary> - /// Check if the effect needs to be skipped. - /// </summary> - /// <returns>Returns true if the effect needs to be skipped.</returns> - public bool ShouldSkip() - { - return BufferUnmapped; - } - - /// <summary> - /// Update the <see cref="BaseEffect"/> state during command generation. - /// </summary> - public virtual void UpdateForCommandGeneration() - { - Debug.Assert(Type == TargetEffectType); - } - - /// <summary> - /// Update the internal state from a user parameter. - /// </summary> - /// <param name="updateErrorInfo">The possible <see cref="ErrorInfo"/> that was generated.</param> - /// <param name="parameter">The user parameter.</param> - /// <param name="mapper">The mapper to use.</param> - public virtual void Update(out ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - updateErrorInfo = new ErrorInfo(); - } - - /// <summary> - /// Get the work buffer DSP address at the given index. - /// </summary> - /// <param name="index">The index of the work buffer</param> - /// <returns>The work buffer DSP address at the given index.</returns> - public virtual DspAddress GetWorkBuffer(int index) - { - throw new InvalidOperationException(); - } - - /// <summary> - /// Get the first work buffer DSP address. - /// </summary> - /// <returns>The first work buffer DSP address.</returns> - protected DspAddress GetSingleBuffer() - { - if (IsEnabled) - { - return WorkBuffers[0].GetReference(true); - } - - if (UsageState != UsageState.Disabled) - { - DspAddress address = WorkBuffers[0].GetReference(false); - ulong size = WorkBuffers[0].Size; - - if (address != 0 && size != 0) - { - AudioProcessorMemoryManager.InvalidateDataCache(address, size); - } - } - - return 0; - } - - /// <summary> - /// Store the output status to the given user output. - /// </summary> - /// <param name="outStatus">The given user output.</param> - /// <param name="isAudioRendererActive">If set to true, the <see cref="AudioRenderSystem"/> is active.</param> - public void StoreStatus(ref EffectOutStatus outStatus, bool isAudioRendererActive) - { - if (isAudioRendererActive) - { - if (UsageState == UsageState.Disabled) - { - outStatus.State = EffectOutStatus.EffectState.Disabled; - } - else - { - outStatus.State = EffectOutStatus.EffectState.Enabled; - } - } - else if (UsageState == UsageState.New) - { - outStatus.State = EffectOutStatus.EffectState.Enabled; - } - else - { - outStatus.State = EffectOutStatus.EffectState.Disabled; - } - } - - /// <summary> - /// Get the <see cref="PerformanceDetailType"/> associated to the <see cref="Type"/> of this effect. - /// </summary> - /// <returns>The <see cref="PerformanceDetailType"/> associated to the <see cref="Type"/> of this effect.</returns> - public PerformanceDetailType GetPerformanceDetailType() - { - switch (Type) - { - case EffectType.BiquadFilter: - return PerformanceDetailType.BiquadFilter; - case EffectType.AuxiliaryBuffer: - return PerformanceDetailType.Aux; - case EffectType.Delay: - return PerformanceDetailType.Delay; - case EffectType.Reverb: - return PerformanceDetailType.Reverb; - case EffectType.Reverb3d: - return PerformanceDetailType.Reverb3d; - case EffectType.BufferMix: - return PerformanceDetailType.Mix; - default: - throw new NotImplementedException($"{Type}"); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/BiquadFilterEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/BiquadFilterEffect.cs deleted file mode 100644 index aadf2844..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/BiquadFilterEffect.cs +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// <summary> - /// Server state for a biquad filter effect. - /// </summary> - public class BiquadFilterEffect : BaseEffect - { - /// <summary> - /// The biquad filter parameter. - /// </summary> - public BiquadFilterEffectParameter Parameter; - - /// <summary> - /// The biquad filter state. - /// </summary> - public Memory<BiquadFilterState> State { get; } - - /// <summary> - /// Create a new <see cref="BiquadFilterEffect"/>. - /// </summary> - public BiquadFilterEffect() - { - Parameter = new BiquadFilterEffectParameter(); - State = new BiquadFilterState[RendererConstants.ChannelCountMax]; - } - - public override EffectType TargetEffectType => EffectType.BiquadFilter; - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - UpdateParameterBase(ref parameter); - - Parameter = MemoryMarshal.Cast<byte, BiquadFilterEffectParameter>(parameter.SpecificData)[0]; - IsEnabled = parameter.IsEnabled; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - - Parameter.Status = UsageState.Enabled; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/BufferMixEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/BufferMixEffect.cs deleted file mode 100644 index 14ed3950..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/BufferMixEffect.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// <summary> - /// Server state for a buffer mix effect. - /// </summary> - public class BufferMixEffect : BaseEffect - { - /// <summary> - /// The buffer mix parameter. - /// </summary> - public BufferMixParameter Parameter; - - public override EffectType TargetEffectType => EffectType.BufferMix; - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - UpdateParameterBase(ref parameter); - - Parameter = MemoryMarshal.Cast<byte, BufferMixParameter>(parameter.SpecificData)[0]; - IsEnabled = parameter.IsEnabled; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/DelayEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/DelayEffect.cs deleted file mode 100644 index df3e5ee7..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/DelayEffect.cs +++ /dev/null @@ -1,100 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using DspAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// <summary> - /// Server state for a delay effect. - /// </summary> - public class DelayEffect : BaseEffect - { - /// <summary> - /// The delay parameter. - /// </summary> - public DelayParameter Parameter; - - /// <summary> - /// The delay state. - /// </summary> - public Memory<DelayState> State { get; } - - public DelayEffect() - { - State = new DelayState[1]; - } - - public override EffectType TargetEffectType => EffectType.Delay; - - public override DspAddress GetWorkBuffer(int index) - { - return GetSingleBuffer(); - } - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - ref DelayParameter delayParameter = ref MemoryMarshal.Cast<byte, DelayParameter>(parameter.SpecificData)[0]; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - - if (delayParameter.IsChannelCountMaxValid()) - { - UpdateParameterBase(ref parameter); - - UsageState oldParameterStatus = Parameter.Status; - - Parameter = delayParameter; - - if (delayParameter.IsChannelCountValid()) - { - IsEnabled = parameter.IsEnabled; - - if (oldParameterStatus != UsageState.Enabled) - { - Parameter.Status = oldParameterStatus; - } - - if (BufferUnmapped || parameter.IsNew) - { - UsageState = UsageState.New; - Parameter.Status = UsageState.Invalid; - - BufferUnmapped = !mapper.TryAttachBuffer(out updateErrorInfo, ref WorkBuffers[0], parameter.BufferBase, parameter.BufferSize); - } - } - } - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - - Parameter.Status = UsageState.Enabled; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/EffectContext.cs b/Ryujinx.Audio.Renderer/Server/Effect/EffectContext.cs deleted file mode 100644 index ff6051ae..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/EffectContext.cs +++ /dev/null @@ -1,82 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// <summary> - /// Effect context. - /// </summary> - public class EffectContext - { - /// <summary> - /// Storage for <see cref="BaseEffect"/>. - /// </summary> - private BaseEffect[] _effects; - - /// <summary> - /// The total effect count. - /// </summary> - private uint _effectCount; - - /// <summary> - /// Create a new <see cref="EffectContext"/>. - /// </summary> - public EffectContext() - { - _effects = null; - _effectCount = 0; - } - - /// <summary> - /// Initialize the <see cref="EffectContext"/>. - /// </summary> - /// <param name="effectCount">The total effect count.</param> - public void Initialize(uint effectCount) - { - _effectCount = effectCount; - _effects = new BaseEffect[effectCount]; - - for (int i = 0; i < _effectCount; i++) - { - _effects[i] = new BaseEffect(); - } - } - - /// <summary> - /// Get the total effect count. - /// </summary> - /// <returns>The total effect count.</returns> - public uint GetCount() - { - return _effectCount; - } - - /// <summary> - /// Get a reference to a <see cref="BaseEffect"/> at the given <paramref name="index"/>. - /// </summary> - /// <param name="index">The index to use.</param> - /// <returns>A reference to a <see cref="BaseEffect"/> at the given <paramref name="index"/>.</returns> - public ref BaseEffect GetEffect(int index) - { - Debug.Assert(index >= 0 && index < _effectCount); - - return ref _effects[index]; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/Reverb3dEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/Reverb3dEffect.cs deleted file mode 100644 index d9f23799..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/Reverb3dEffect.cs +++ /dev/null @@ -1,99 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// <summary> - /// Server state for a 3D reverberation effect. - /// </summary> - public class Reverb3dEffect : BaseEffect - { - /// <summary> - /// The 3D reverberation parameter. - /// </summary> - public Reverb3dParameter Parameter; - - /// <summary> - /// The 3D reverberation state. - /// </summary> - public Memory<Reverb3dState> State { get; } - - public Reverb3dEffect() - { - State = new Reverb3dState[1]; - } - - public override EffectType TargetEffectType => EffectType.Reverb3d; - - public override ulong GetWorkBuffer(int index) - { - return GetSingleBuffer(); - } - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - ref Reverb3dParameter reverbParameter = ref MemoryMarshal.Cast<byte, Reverb3dParameter>(parameter.SpecificData)[0]; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - - if (reverbParameter.IsChannelCountMaxValid()) - { - UpdateParameterBase(ref parameter); - - UsageState oldParameterStatus = Parameter.ParameterStatus; - - Parameter = reverbParameter; - - if (reverbParameter.IsChannelCountValid()) - { - IsEnabled = parameter.IsEnabled; - - if (oldParameterStatus != UsageState.Enabled) - { - Parameter.ParameterStatus = oldParameterStatus; - } - - if (BufferUnmapped || parameter.IsNew) - { - UsageState = UsageState.New; - Parameter.ParameterStatus = UsageState.Invalid; - - BufferUnmapped = !mapper.TryAttachBuffer(out updateErrorInfo, ref WorkBuffers[0], parameter.BufferBase, parameter.BufferSize); - } - } - } - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - - Parameter.ParameterStatus = UsageState.Enabled; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/ReverbEffect.cs b/Ryujinx.Audio.Renderer/Server/Effect/ReverbEffect.cs deleted file mode 100644 index 4c81f729..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/ReverbEffect.cs +++ /dev/null @@ -1,102 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Dsp.State; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// <summary> - /// Server state for a reverberation effect. - /// </summary> - public class ReverbEffect : BaseEffect - { - /// <summary> - /// The reverberation parameter. - /// </summary> - public ReverbParameter Parameter; - - /// <summary> - /// The reverberation state. - /// </summary> - public Memory<ReverbState> State { get; } - - /// <summary> - /// Create a new <see cref="ReverbEffect"/>. - /// </summary> - public ReverbEffect() - { - State = new ReverbState[1]; - } - - public override EffectType TargetEffectType => EffectType.Reverb; - - public override ulong GetWorkBuffer(int index) - { - return GetSingleBuffer(); - } - - public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameter parameter, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - ref ReverbParameter reverbParameter = ref MemoryMarshal.Cast<byte, ReverbParameter>(parameter.SpecificData)[0]; - - updateErrorInfo = new BehaviourParameter.ErrorInfo(); - - if (reverbParameter.IsChannelCountMaxValid()) - { - UpdateParameterBase(ref parameter); - - UsageState oldParameterStatus = Parameter.Status; - - Parameter = reverbParameter; - - if (reverbParameter.IsChannelCountValid()) - { - IsEnabled = parameter.IsEnabled; - - if (oldParameterStatus != UsageState.Enabled) - { - Parameter.Status = oldParameterStatus; - } - - if (BufferUnmapped || parameter.IsNew) - { - UsageState = UsageState.New; - Parameter.Status = UsageState.Invalid; - - BufferUnmapped = !mapper.TryAttachBuffer(out updateErrorInfo, ref WorkBuffers[0], parameter.BufferBase, parameter.BufferSize); - } - } - } - } - - public override void UpdateForCommandGeneration() - { - UpdateUsageStateForCommandGeneration(); - - Parameter.Status = UsageState.Enabled; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Effect/UsageState.cs b/Ryujinx.Audio.Renderer/Server/Effect/UsageState.cs deleted file mode 100644 index a519acd4..00000000 --- a/Ryujinx.Audio.Renderer/Server/Effect/UsageState.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Server.Effect -{ - /// <summary> - /// The usage state of an effect. - /// </summary> - public enum UsageState : byte - { - /// <summary> - /// The effect is in an invalid state. - /// </summary> - Invalid, - - /// <summary> - /// The effect is new. - /// </summary> - New, - - /// <summary> - /// The effect is enabled. - /// </summary> - Enabled, - - /// <summary> - /// The effect is disabled. - /// </summary> - Disabled - } -} diff --git a/Ryujinx.Audio.Renderer/Server/ICommandProcessingTimeEstimator.cs b/Ryujinx.Audio.Renderer/Server/ICommandProcessingTimeEstimator.cs deleted file mode 100644 index 119ec907..00000000 --- a/Ryujinx.Audio.Renderer/Server/ICommandProcessingTimeEstimator.cs +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Dsp.Command; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// <summary> - /// Estimate the time that a <see cref="ICommand"/> should take. - /// </summary> - /// <remarks>This is used for voice dropping.</remarks> - public interface ICommandProcessingTimeEstimator - { - uint Estimate(AuxiliaryBufferCommand command); - uint Estimate(BiquadFilterCommand command); - uint Estimate(ClearMixBufferCommand command); - uint Estimate(DelayCommand command); - uint Estimate(Reverb3dCommand command); - uint Estimate(ReverbCommand command); - uint Estimate(DepopPrepareCommand command); - uint Estimate(DepopForMixBuffersCommand command); - uint Estimate(MixCommand command); - uint Estimate(MixRampCommand command); - uint Estimate(MixRampGroupedCommand command); - uint Estimate(CopyMixBufferCommand command); - uint Estimate(PerformanceCommand command); - uint Estimate(VolumeCommand command); - uint Estimate(VolumeRampCommand command); - uint Estimate(PcmInt16DataSourceCommandVersion1 command); - uint Estimate(PcmFloatDataSourceCommandVersion1 command); - uint Estimate(AdpcmDataSourceCommandVersion1 command); - uint Estimate(DataSourceVersion2Command command); - uint Estimate(CircularBufferSinkCommand command); - uint Estimate(DeviceSinkCommand command); - uint Estimate(DownMixSurroundToStereoCommand command); - uint Estimate(UpsampleCommand command); - } -} diff --git a/Ryujinx.Audio.Renderer/Server/MemoryPool/AddressInfo.cs b/Ryujinx.Audio.Renderer/Server/MemoryPool/AddressInfo.cs deleted file mode 100644 index 2b625d06..00000000 --- a/Ryujinx.Audio.Renderer/Server/MemoryPool/AddressInfo.cs +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Runtime.InteropServices; - -using DspAddress = System.UInt64; -using CpuAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.MemoryPool -{ - /// <summary> - /// Represents the information of a region shared between the CPU and DSP. - /// </summary> - public struct AddressInfo - { - /// <summary> - /// The target CPU address of the region. - /// </summary> - public CpuAddress CpuAddress; - - /// <summary> - /// The size of the region. - /// </summary> - public ulong Size; - - private unsafe MemoryPoolState* _memoryPools; - - /// <summary> - /// The forced DSP address of the region. - /// </summary> - public DspAddress ForceMappedDspAddress; - - private unsafe ref MemoryPoolState MemoryPoolState => ref *_memoryPools; - - public unsafe bool HasMemoryPoolState => (IntPtr)_memoryPools != IntPtr.Zero; - - /// <summary> - /// Create an new empty <see cref="AddressInfo"/>. - /// </summary> - /// <returns>A new empty <see cref="AddressInfo"/>.</returns> - public static AddressInfo Create() - { - return Create(0, 0); - } - - /// <summary> - /// Create a new <see cref="AddressInfo"/>. - /// </summary> - /// <param name="cpuAddress">The target <see cref="CpuAddress"/> of the region.</param> - /// <param name="size">The target size of the region.</param> - /// <returns>A new <see cref="AddressInfo"/>.</returns> - public static AddressInfo Create(CpuAddress cpuAddress, ulong size) - { - unsafe - { - return new AddressInfo - { - CpuAddress = cpuAddress, - _memoryPools = MemoryPoolState.Null, - Size = size, - ForceMappedDspAddress = 0 - }; - } - } - - /// <summary> - /// Setup the CPU address and size of the <see cref="AddressInfo"/>. - /// </summary> - /// <param name="cpuAddress">The target <see cref="CpuAddress"/> of the region.</param> - /// <param name="size">The size of the region.</param> - public void Setup(CpuAddress cpuAddress, ulong size) - { - CpuAddress = cpuAddress; - Size = size; - ForceMappedDspAddress = 0; - - unsafe - { - _memoryPools = MemoryPoolState.Null; - } - } - - /// <summary> - /// Set the <see cref="MemoryPoolState"/> associated. - /// </summary> - /// <param name="memoryPoolState">The <see cref="MemoryPoolState"/> associated.</param> - public void SetupMemoryPool(Span<MemoryPoolState> memoryPoolState) - { - unsafe - { - fixed (MemoryPoolState* ptr = &MemoryMarshal.GetReference(memoryPoolState)) - { - SetupMemoryPool(ptr); - } - } - } - - /// <summary> - /// Set the <see cref="MemoryPoolState"/> associated. - /// </summary> - /// <param name="memoryPoolState">The <see cref="MemoryPoolState"/> associated.</param> - public unsafe void SetupMemoryPool(MemoryPoolState* memoryPoolState) - { - _memoryPools = memoryPoolState; - } - - /// <summary> - /// Check if the <see cref="MemoryPoolState"/> is mapped. - /// </summary> - /// <returns>Returns true if the <see cref="MemoryPoolState"/> is mapped.</returns> - public bool HasMappedMemoryPool() - { - return HasMemoryPoolState && MemoryPoolState.IsMapped(); - } - - /// <summary> - /// Get the DSP address associated to the <see cref="AddressInfo"/>. - /// </summary> - /// <param name="markUsed">If true, mark the <see cref="MemoryPoolState"/> as used.</param> - /// <returns>Returns the DSP address associated to the <see cref="AddressInfo"/>.</returns> - public DspAddress GetReference(bool markUsed) - { - if (!HasMappedMemoryPool()) - { - return ForceMappedDspAddress; - } - - if (markUsed) - { - MemoryPoolState.IsUsed = true; - } - - return MemoryPoolState.Translate(CpuAddress, Size); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/MemoryPool/MemoryPoolState.cs b/Ryujinx.Audio.Renderer/Server/MemoryPool/MemoryPoolState.cs deleted file mode 100644 index ebde1403..00000000 --- a/Ryujinx.Audio.Renderer/Server/MemoryPool/MemoryPoolState.cs +++ /dev/null @@ -1,148 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Runtime.InteropServices; - -using DspAddress = System.UInt64; -using CpuAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.MemoryPool -{ - /// <summary> - /// Server state for a memory pool. - /// </summary> - [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = Alignment)] - public struct MemoryPoolState - { - public const int Alignment = 0x10; - - /// <summary> - /// The location of the <see cref="MemoryPoolState"/>. - /// </summary> - public enum LocationType : uint - { - /// <summary> - /// <see cref="MemoryPoolState"/> located on the CPU side for user use. - /// </summary> - Cpu, - - /// <summary> - /// <see cref="MemoryPoolState"/> located on the DSP side for system use. - /// </summary> - Dsp - } - - /// <summary> - /// The CPU address associated to the <see cref="MemoryPoolState"/>. - /// </summary> - public CpuAddress CpuAddress; - - /// <summary> - /// The DSP address associated to the <see cref="MemoryPoolState"/>. - /// </summary> - public DspAddress DspAddress; - - /// <summary> - /// The size associated to the <see cref="MemoryPoolState"/>. - /// </summary> - public ulong Size; - - /// <summary> - /// The <see cref="LocationType"/> associated to the <see cref="MemoryPoolState"/>. - /// </summary> - public LocationType Location; - - /// <summary> - /// Set to true if the <see cref="MemoryPoolState"/> is used. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool IsUsed; - - public static unsafe MemoryPoolState* Null => (MemoryPoolState*)IntPtr.Zero.ToPointer(); - - /// <summary> - /// Create a new <see cref="MemoryPoolState"/> with the given <see cref="LocationType"/>. - /// </summary> - /// <param name="location">The location type to use.</param> - /// <returns>A new <see cref="MemoryPoolState"/> with the given <see cref="LocationType"/>.</returns> - public static MemoryPoolState Create(LocationType location) - { - return new MemoryPoolState - { - CpuAddress = 0, - DspAddress = 0, - Size = 0, - Location = location - }; - } - - /// <summary> - /// Set the <see cref="CpuAddress"/> and size of the <see cref="MemoryPoolState"/>. - /// </summary> - /// <param name="cpuAddress">The <see cref="CpuAddress"/>.</param> - /// <param name="size">The size.</param> - public void SetCpuAddress(CpuAddress cpuAddress, ulong size) - { - CpuAddress = cpuAddress; - Size = size; - } - - /// <summary> - /// Check if the given <see cref="CpuAddress"/> and size is contains in the <see cref="MemoryPoolState"/>. - /// </summary> - /// <param name="targetCpuAddress">The <see cref="CpuAddress"/>.</param> - /// <param name="size">The size.</param> - /// <returns>True if the <see cref="CpuAddress"/> is contained inside the <see cref="MemoryPoolState"/>.</returns> - public bool Contains(CpuAddress targetCpuAddress, ulong size) - { - if (CpuAddress <= targetCpuAddress && size + targetCpuAddress <= Size + CpuAddress) - { - return true; - } - - return false; - } - - /// <summary> - /// Translate the given CPU address to a DSP address. - /// </summary> - /// <param name="targetCpuAddress">The <see cref="CpuAddress"/>.</param> - /// <param name="size">The size.</param> - /// <returns>the target DSP address.</returns> - public DspAddress Translate(CpuAddress targetCpuAddress, ulong size) - { - if (Contains(targetCpuAddress, size) && IsMapped()) - { - ulong offset = targetCpuAddress - CpuAddress; - - return DspAddress + offset; - } - - return 0; - } - - /// <summary> - /// Is the <see cref="MemoryPoolState"/> mapped on the DSP? - /// </summary> - /// <returns>Returns true if the <see cref="MemoryPoolState"/> is mapped on the DSP.</returns> - public bool IsMapped() - { - return DspAddress != 0; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/MemoryPool/PoolMapper.cs b/Ryujinx.Audio.Renderer/Server/MemoryPool/PoolMapper.cs deleted file mode 100644 index b255960c..00000000 --- a/Ryujinx.Audio.Renderer/Server/MemoryPool/PoolMapper.cs +++ /dev/null @@ -1,383 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Utils; -using Ryujinx.Common.Logging; -using System; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; - -using CpuAddress = System.UInt64; -using DspAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Server.MemoryPool -{ - /// <summary> - /// Memory pool mapping helper. - /// </summary> - public class PoolMapper - { - const uint CurrentProcessPseudoHandle = 0xFFFF8001; - - /// <summary> - /// The result of <see cref="Update(ref MemoryPoolState, ref MemoryPoolInParameter, ref MemoryPoolOutStatus)"/>. - /// </summary> - public enum UpdateResult : uint - { - /// <summary> - /// No error reported. - /// </summary> - Success = 0, - - /// <summary> - /// The user parameters were invalid. - /// </summary> - InvalidParameter = 1, - - /// <summary> - /// <see cref="Dsp.AudioProcessor"/> mapping failed. - /// </summary> - MapError = 2, - - /// <summary> - /// <see cref="Dsp.AudioProcessor"/> unmapping failed. - /// </summary> - UnmapError = 3 - } - - /// <summary> - /// The handle of the process owning the CPU memory manipulated. - /// </summary> - private uint _processHandle; - - /// <summary> - /// The <see cref="Memory{MemoryPoolState}"/> that will be manipulated. - /// </summary> - private Memory<MemoryPoolState> _memoryPools; - - /// <summary> - /// If set to true, this will try to force map memory pool even if their state are considered invalid. - /// </summary> - private bool _isForceMapEnabled; - - /// <summary> - /// Create a new <see cref="PoolMapper"/> used for system mapping. - /// </summary> - /// <param name="processHandle">The handle of the process owning the CPU memory manipulated.</param> - /// <param name="isForceMapEnabled">If set to true, this will try to force map memory pool even if their state are considered invalid.</param> - public PoolMapper(uint processHandle, bool isForceMapEnabled) - { - _processHandle = processHandle; - _isForceMapEnabled = isForceMapEnabled; - _memoryPools = Memory<MemoryPoolState>.Empty; - } - - /// <summary> - /// Create a new <see cref="PoolMapper"/> used for user mapping. - /// </summary> - /// <param name="processHandle">The handle of the process owning the CPU memory manipulated.</param> - /// <param name="memoryPool">The user memory pools.</param> - /// <param name="isForceMapEnabled">If set to true, this will try to force map memory pool even if their state are considered invalid.</param> - public PoolMapper(uint processHandle, Memory<MemoryPoolState> memoryPool, bool isForceMapEnabled) - { - _processHandle = processHandle; - _memoryPools = memoryPool; - _isForceMapEnabled = isForceMapEnabled; - } - - /// <summary> - /// Initialize the <see cref="MemoryPoolState"/> for system use. - /// </summary> - /// <param name="memoryPool">The <see cref="MemoryPoolState"/> for system use.</param> - /// <param name="cpuAddress">The <see cref="CpuAddress"/> to assign.</param> - /// <param name="size">The size to assign.</param> - /// <returns>Returns true if mapping on the <see cref="Dsp.AudioProcessor"/> succeeded.</returns> - public bool InitializeSystemPool(ref MemoryPoolState memoryPool, CpuAddress cpuAddress, ulong size) - { - if (memoryPool.Location != MemoryPoolState.LocationType.Dsp) - { - return false; - } - - return InitializePool(ref memoryPool, cpuAddress, size); - } - - /// <summary> - /// Initialize the <see cref="MemoryPoolState"/>. - /// </summary> - /// <param name="memoryPool">The <see cref="MemoryPoolState"/>.</param> - /// <param name="cpuAddress">The <see cref="CpuAddress"/> to assign.</param> - /// <param name="size">The size to assign.</param> - /// <returns>Returns true if mapping on the <see cref="Dsp.AudioProcessor"/> succeeded.</returns> - public bool InitializePool(ref MemoryPoolState memoryPool, CpuAddress cpuAddress, ulong size) - { - memoryPool.SetCpuAddress(cpuAddress, size); - - return Map(ref memoryPool) != 0; - } - - /// <summary> - /// Get the process handle associated to the <see cref="MemoryPoolState"/>. - /// </summary> - /// <param name="memoryPool">The <see cref="MemoryPoolState"/>.</param> - /// <returns>Returns the process handle associated to the <see cref="MemoryPoolState"/>.</returns> - public uint GetProcessHandle(ref MemoryPoolState memoryPool) - { - if (memoryPool.Location == MemoryPoolState.LocationType.Cpu) - { - return CurrentProcessPseudoHandle; - } - else if (memoryPool.Location == MemoryPoolState.LocationType.Dsp) - { - return _processHandle; - } - - return 0; - } - - /// <summary> - /// Map the <see cref="MemoryPoolState"/> on the <see cref="Dsp.AudioProcessor"/>. - /// </summary> - /// <param name="memoryPool">The <see cref="MemoryPoolState"/> to map.</param> - /// <returns>Returns the DSP address mapped.</returns> - public DspAddress Map(ref MemoryPoolState memoryPool) - { - DspAddress result = AudioProcessorMemoryManager.Map(GetProcessHandle(ref memoryPool), memoryPool.CpuAddress, memoryPool.Size); - - if (result != 0) - { - memoryPool.DspAddress = result; - } - - return result; - } - - /// <summary> - /// Unmap the <see cref="MemoryPoolState"/> from the <see cref="Dsp.AudioProcessor"/>. - /// </summary> - /// <param name="memoryPool">The <see cref="MemoryPoolState"/> to unmap.</param> - /// <returns>Returns true if unmapped.</returns> - public bool Unmap(ref MemoryPoolState memoryPool) - { - if (memoryPool.IsUsed) - { - return false; - } - - AudioProcessorMemoryManager.Unmap(GetProcessHandle(ref memoryPool), memoryPool.CpuAddress, memoryPool.Size); - - memoryPool.SetCpuAddress(0, 0); - memoryPool.DspAddress = 0; - - return true; - } - - /// <summary> - /// Find a <see cref="MemoryPoolState"/> associated to the region given. - /// </summary> - /// <param name="cpuAddress">The region <see cref="CpuAddress"/>.</param> - /// <param name="size">The region size.</param> - /// <returns>Returns the <see cref="MemoryPoolState"/> found or <see cref="Memory{MemoryPoolState}.Empty"/> if not found.</returns> - private Span<MemoryPoolState> FindMemoryPool(CpuAddress cpuAddress, ulong size) - { - if (!_memoryPools.IsEmpty && _memoryPools.Length > 0) - { - for (int i = 0; i < _memoryPools.Length; i++) - { - if (_memoryPools.Span[i].Contains(cpuAddress, size)) - { - return _memoryPools.Span.Slice(i, 1); - } - } - } - - return Span<MemoryPoolState>.Empty; - } - - /// <summary> - /// Force unmap the given <see cref="AddressInfo"/>. - /// </summary> - /// <param name="addressInfo">The <see cref="AddressInfo"/> to force unmap</param> - public void ForceUnmap(ref AddressInfo addressInfo) - { - if (_isForceMapEnabled) - { - Span<MemoryPoolState> memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size); - - if (!memoryPool.IsEmpty) - { - AudioProcessorMemoryManager.Unmap(_processHandle, memoryPool[0].CpuAddress, memoryPool[0].Size); - - return; - } - - AudioProcessorMemoryManager.Unmap(_processHandle, addressInfo.CpuAddress, 0); - } - } - - /// <summary> - /// Try to attach the given region to the <see cref="AddressInfo"/>. - /// </summary> - /// <param name="errorInfo">The error information if an error was generated.</param> - /// <param name="addressInfo">The <see cref="AddressInfo"/> to attach the region to.</param> - /// <param name="cpuAddress">The region <see cref="CpuAddress"/>.</param> - /// <param name="size">The region size.</param> - /// <returns>Returns true if mapping was performed.</returns> - public bool TryAttachBuffer(out ErrorInfo errorInfo, ref AddressInfo addressInfo, CpuAddress cpuAddress, ulong size) - { - errorInfo = new ErrorInfo(); - - addressInfo.Setup(cpuAddress, size); - - if (AssignDspAddress(ref addressInfo)) - { - errorInfo.ErrorCode = 0x0; - errorInfo.ExtraErrorInfo = 0x0; - - return true; - } - else - { - errorInfo.ErrorCode = ResultCode.InvalidAddressInfo; - errorInfo.ExtraErrorInfo = addressInfo.CpuAddress; - - return _isForceMapEnabled; - } - } - - /// <summary> - /// Update a <see cref="MemoryPoolState"/> using user parameters. - /// </summary> - /// <param name="memoryPool">The <see cref="MemoryPoolState"/> to update.</param> - /// <param name="inParameter">Input user parameter.</param> - /// <param name="outStatus">Output user parameter.</param> - /// <returns>Returns the <see cref="UpdateResult"/> of the operations performed.</returns> - public UpdateResult Update(ref MemoryPoolState memoryPool, ref MemoryPoolInParameter inParameter, ref MemoryPoolOutStatus outStatus) - { - MemoryPoolUserState inputState = inParameter.State; - - MemoryPoolUserState outputState; - - const uint pageSize = 0x1000; - - if (inputState != MemoryPoolUserState.RequestAttach && inputState != MemoryPoolUserState.RequestDetach) - { - return UpdateResult.Success; - } - - if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress & (pageSize - 1)) != 0) - { - return UpdateResult.InvalidParameter; - } - - if (inParameter.Size == 0 || (inParameter.Size & (pageSize - 1)) != 0) - { - return UpdateResult.InvalidParameter; - } - - if (inputState == MemoryPoolUserState.RequestAttach) - { - bool initializeSuccess = InitializePool(ref memoryPool, inParameter.CpuAddress, inParameter.Size); - - if (!initializeSuccess) - { - memoryPool.SetCpuAddress(0, 0); - - Logger.Error?.Print(LogClass.AudioRenderer, $"Map of memory pool (address: 0x{inParameter.CpuAddress:x}, size 0x{inParameter.Size:x}) failed!"); - return UpdateResult.MapError; - } - - outputState = MemoryPoolUserState.Attached; - } - else - { - if (memoryPool.CpuAddress != inParameter.CpuAddress || memoryPool.Size != inParameter.Size) - { - return UpdateResult.InvalidParameter; - } - - if (!Unmap(ref memoryPool)) - { - Logger.Error?.Print(LogClass.AudioRenderer, $"Unmap of memory pool (address: 0x{memoryPool.CpuAddress:x}, size 0x{memoryPool.Size:x}) failed!"); - return UpdateResult.UnmapError; - } - - outputState = MemoryPoolUserState.Detached; - } - - outStatus.State = outputState; - - return UpdateResult.Success; - } - - /// <summary> - /// Map the <see cref="AddressInfo"/> to the <see cref="Dsp.AudioProcessor"/>. - /// </summary> - /// <param name="addressInfo">The <see cref="AddressInfo"/> to map.</param> - /// <returns>Returns true if mapping was performed.</returns> - private bool AssignDspAddress(ref AddressInfo addressInfo) - { - if (addressInfo.CpuAddress == 0) - { - return false; - } - - if (_memoryPools.Length > 0) - { - Span<MemoryPoolState> memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size); - - if (!memoryPool.IsEmpty) - { - addressInfo.SetupMemoryPool(memoryPool); - - return true; - } - } - - if (_isForceMapEnabled) - { - DspAddress dspAddress = AudioProcessorMemoryManager.Map(_processHandle, addressInfo.CpuAddress, addressInfo.Size); - - addressInfo.ForceMappedDspAddress = dspAddress; - - AudioProcessorMemoryManager.Map(_processHandle, addressInfo.CpuAddress, addressInfo.Size); - } - else - { - unsafe - { - addressInfo.SetupMemoryPool(MemoryPoolState.Null); - } - } - - return false; - } - - /// <summary> - /// Remove the usage flag from all the <see cref="MemoryPoolState"/>. - /// </summary> - /// <param name="memoryPool">The <see cref="Memory{MemoryPoolState}"/> to reset.</param> - public static void ClearUsageState(Memory<MemoryPoolState> memoryPool) - { - foreach (ref MemoryPoolState info in memoryPool.Span) - { - info.IsUsed = false; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Mix/MixContext.cs b/Ryujinx.Audio.Renderer/Server/Mix/MixContext.cs deleted file mode 100644 index 5a3c3a63..00000000 --- a/Ryujinx.Audio.Renderer/Server/Mix/MixContext.cs +++ /dev/null @@ -1,276 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Server.Splitter; -using Ryujinx.Audio.Renderer.Utils; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server.Mix -{ - /// <summary> - /// Mix context. - /// </summary> - public class MixContext - { - /// <summary> - /// The total mix count. - /// </summary> - private uint _mixesCount; - - /// <summary> - /// Storage for <see cref="MixState"/>. - /// </summary> - private Memory<MixState> _mixes; - - /// <summary> - /// Storage of the sorted indices to <see cref="MixState"/>. - /// </summary> - private Memory<int> _sortedMixes; - - /// <summary> - /// Graph state. - /// </summary> - public NodeStates NodeStates { get; } - - /// <summary> - /// The instance of the adjacent matrix. - /// </summary> - public EdgeMatrix EdgeMatrix { get; } - - /// <summary> - /// Create a new instance of <see cref="MixContext"/>. - /// </summary> - public MixContext() - { - NodeStates = new NodeStates(); - EdgeMatrix = new EdgeMatrix(); - } - - /// <summary> - /// Initialize the <see cref="MixContext"/>. - /// </summary> - /// <param name="sortedMixes">The storage for sorted indices.</param> - /// <param name="mixes">The storage of <see cref="MixState"/>.</param> - /// <param name="nodeStatesWorkBuffer">The storage used for the <see cref="NodeStates"/>.</param> - /// <param name="edgeMatrixWorkBuffer">The storage used for the <see cref="EdgeMatrix"/>.</param> - public void Initialize(Memory<int> sortedMixes, Memory<MixState> mixes, Memory<byte> nodeStatesWorkBuffer, Memory<byte> edgeMatrixWorkBuffer) - { - _mixesCount = (uint)mixes.Length; - _mixes = mixes; - _sortedMixes = sortedMixes; - - if (!nodeStatesWorkBuffer.IsEmpty && !edgeMatrixWorkBuffer.IsEmpty) - { - NodeStates.Initialize(nodeStatesWorkBuffer, mixes.Length); - EdgeMatrix.Initialize(edgeMatrixWorkBuffer, mixes.Length); - } - - int sortedId = 0; - for (int i = 0; i < _mixes.Length; i++) - { - SetSortedState(sortedId++, i); - } - } - - /// <summary> - /// Associate the given <paramref name="targetIndex"/> to a given <paramref cref="id"/>. - /// </summary> - /// <param name="id">The sorted id.</param> - /// <param name="targetIndex">The index to associate.</param> - private void SetSortedState(int id, int targetIndex) - { - _sortedMixes.Span[id] = targetIndex; - } - - /// <summary> - /// Get a reference to the final <see cref="MixState"/>. - /// </summary> - /// <returns>A reference to the final <see cref="MixState"/>.</returns> - public ref MixState GetFinalState() - { - return ref GetState(RendererConstants.FinalMixId); - } - - /// <summary> - /// Get a reference to a <see cref="MixState"/> at the given <paramref name="id"/>. - /// </summary> - /// <param name="id">The index to use.</param> - /// <returns>A reference to a <see cref="MixState"/> at the given <paramref name="id"/>.</returns> - public ref MixState GetState(int id) - { - return ref SpanIOHelper.GetFromMemory(_mixes, id, _mixesCount); - } - - /// <summary> - /// Get a reference to a <see cref="MixState"/> at the given <paramref name="id"/> of the sorted mix info. - /// </summary> - /// <param name="id">The index to use.</param> - /// <returns>A reference to a <see cref="MixState"/> at the given <paramref name="id"/>.</returns> - public ref MixState GetSortedState(int id) - { - Debug.Assert(id >= 0 && id < _mixesCount); - - return ref GetState(_sortedMixes.Span[id]); - } - - /// <summary> - /// Get the total mix count. - /// </summary> - /// <returns>The total mix count.</returns> - public uint GetCount() - { - return _mixesCount; - } - - /// <summary> - /// Update the internal distance from the final mix value of every <see cref="MixState"/>. - /// </summary> - private void UpdateDistancesFromFinalMix() - { - foreach (ref MixState mix in _mixes.Span) - { - mix.ClearDistanceFromFinalMix(); - } - - for (int i = 0; i < GetCount(); i++) - { - ref MixState mix = ref GetState(i); - - SetSortedState(i, i); - - if (mix.IsUsed) - { - uint distance; - - if (mix.MixId != RendererConstants.FinalMixId) - { - int mixId = mix.MixId; - - for (distance = 0; distance < GetCount(); distance++) - { - if (mixId == RendererConstants.UnusedMixId) - { - distance = MixState.InvalidDistanceFromFinalMix; - break; - } - - ref MixState distanceMix = ref GetState(mixId); - - if (distanceMix.DistanceFromFinalMix != MixState.InvalidDistanceFromFinalMix) - { - distance = distanceMix.DistanceFromFinalMix + 1; - break; - } - - mixId = distanceMix.DestinationMixId; - - if (mixId == RendererConstants.FinalMixId) - { - break; - } - } - - if (distance > GetCount()) - { - distance = MixState.InvalidDistanceFromFinalMix; - } - } - else - { - distance = MixState.InvalidDistanceFromFinalMix; - } - - mix.DistanceFromFinalMix = distance; - } - } - } - - /// <summary> - /// Update the internal mix buffer offset of all <see cref="MixState"/>. - /// </summary> - private void UpdateMixBufferOffset() - { - uint offset = 0; - - foreach (ref MixState mix in _mixes.Span) - { - mix.BufferOffset = offset; - - offset += mix.BufferCount; - } - } - - /// <summary> - /// Sort the mixes using distance from the final mix. - /// </summary> - public void Sort() - { - UpdateDistancesFromFinalMix(); - - int[] sortedMixesTemp = _sortedMixes.Slice(0, (int)GetCount()).ToArray(); - - Array.Sort(sortedMixesTemp, (a, b) => - { - ref MixState stateA = ref GetState(a); - ref MixState stateB = ref GetState(b); - - return stateB.DistanceFromFinalMix.CompareTo(stateA.DistanceFromFinalMix); - }); - - sortedMixesTemp.AsSpan().CopyTo(_sortedMixes.Span); - - UpdateMixBufferOffset(); - } - - /// <summary> - /// Sort the mixes and splitters using an adjacency matrix. - /// </summary> - /// <param name="splitterContext">The <see cref="SplitterContext"/> used.</param> - /// <returns>Return true, if no errors in the graph were detected.</returns> - public bool Sort(SplitterContext splitterContext) - { - if (splitterContext.UsingSplitter()) - { - bool isValid = NodeStates.Sort(EdgeMatrix); - - if (isValid) - { - ReadOnlySpan<int> sortedMixesIndex = NodeStates.GetTsortResult(); - - int id = 0; - - for (int i = sortedMixesIndex.Length - 1; i >= 0; i--) - { - SetSortedState(id++, sortedMixesIndex[i]); - } - - UpdateMixBufferOffset(); - } - - return isValid; - } - else - { - UpdateMixBufferOffset(); - - return true; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Mix/MixState.cs b/Ryujinx.Audio.Renderer/Server/Mix/MixState.cs deleted file mode 100644 index d697488a..00000000 --- a/Ryujinx.Audio.Renderer/Server/Mix/MixState.cs +++ /dev/null @@ -1,330 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.Effect; -using Ryujinx.Audio.Renderer.Server.Splitter; -using Ryujinx.Common.Utilities; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -using static Ryujinx.Audio.Renderer.RendererConstants; - -namespace Ryujinx.Audio.Renderer.Server.Mix -{ - /// <summary> - /// Server state for a mix. - /// </summary> - [StructLayout(LayoutKind.Sequential, Size = 0x940, Pack = Alignment)] - public struct MixState - { - public const uint InvalidDistanceFromFinalMix = 0x80000000; - - public const int Alignment = 0x10; - - /// <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> - /// The id of the mix. - /// </summary> - public int MixId; - - /// <summary> - /// The mix node id. - /// </summary> - public int NodeId; - - /// <summary> - /// the buffer offset to use for command generation. - /// </summary> - public uint BufferOffset; - - /// <summary> - /// The distance of the mix from the final mix. - /// </summary> - public uint DistanceFromFinalMix; - - /// <summary> - /// The effect processing order storage. - /// </summary> - private IntPtr _effectProcessingOrderArrayPointer; - - /// <summary> - /// The max element count that can be found in the effect processing order storage. - /// </summary> - public uint EffectProcessingOrderArrayMaxCount; - - /// <summary> - /// The mix to output the result of this mix. - /// </summary> - public int DestinationMixId; - - /// <summary> - /// Mix buffer volumes storage. - /// </summary> - private MixVolumeArray _mixVolumeArray; - - /// <summary> - /// The splitter to output the result of this mix. - /// </summary> - public uint DestinationSplitterId; - - /// <summary> - /// If set to true, the long size pre-delay is supported on the reverb command. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool IsLongSizePreDelaySupported; - - [StructLayout(LayoutKind.Sequential, Size = Size, Pack = 1)] - private struct MixVolumeArray - { - private const int Size = 4 * MixBufferCountMax * MixBufferCountMax; - } - - /// <summary> - /// Mix buffer volumes. - /// </summary> - /// <remarks>Used when no splitter id is specified.</remarks> - public Span<float> MixBufferVolume => SpanHelpers.AsSpan<MixVolumeArray, float>(ref _mixVolumeArray); - - /// <summary> - /// Get the volume for a given connection destination. - /// </summary> - /// <param name="sourceIndex">The source node index.</param> - /// <param name="destinationIndex">The destination node index</param> - /// <returns>The volume for the given connection destination.</returns> - public float GetMixBufferVolume(int sourceIndex, int destinationIndex) - { - return MixBufferVolume[sourceIndex * MixBufferCountMax + destinationIndex]; - } - - /// <summary> - /// The array used to order effects associated to this mix. - /// </summary> - public Span<int> EffectProcessingOrderArray - { - get - { - if (_effectProcessingOrderArrayPointer == IntPtr.Zero) - { - return Span<int>.Empty; - } - - unsafe - { - return new Span<int>((void*)_effectProcessingOrderArrayPointer, (int)EffectProcessingOrderArrayMaxCount); - } - } - } - - /// <summary> - /// Create a new <see cref="MixState"/> - /// </summary> - /// <param name="effectProcessingOrderArray"></param> - /// <param name="behaviourContext"></param> - public MixState(Memory<int> effectProcessingOrderArray, ref BehaviourContext behaviourContext) : this() - { - MixId = UnusedMixId; - - DistanceFromFinalMix = InvalidDistanceFromFinalMix; - - DestinationMixId = UnusedMixId; - - DestinationSplitterId = UnusedSplitterId; - - unsafe - { - // SAFETY: safe as effectProcessingOrderArray comes from the work buffer memory that is pinned. - _effectProcessingOrderArrayPointer = (IntPtr)Unsafe.AsPointer(ref MemoryMarshal.GetReference(effectProcessingOrderArray.Span)); - } - - EffectProcessingOrderArrayMaxCount = (uint)effectProcessingOrderArray.Length; - - IsLongSizePreDelaySupported = behaviourContext.IsLongSizePreDelaySupported(); - - ClearEffectProcessingOrder(); - } - - /// <summary> - /// Clear the <see cref="DistanceFromFinalMix"/> value to its default state. - /// </summary> - public void ClearDistanceFromFinalMix() - { - DistanceFromFinalMix = InvalidDistanceFromFinalMix; - } - - /// <summary> - /// Clear the <see cref="EffectProcessingOrderArray"/> to its default state. - /// </summary> - public void ClearEffectProcessingOrder() - { - EffectProcessingOrderArray.Fill(-1); - } - - /// <summary> - /// Return true if the mix has any destinations. - /// </summary> - /// <returns>True if the mix has any destinations.</returns> - public bool HasAnyDestination() - { - return DestinationMixId != UnusedMixId || DestinationSplitterId != UnusedSplitterId; - } - - /// <summary> - /// Update the mix connection on the adjacency matrix. - /// </summary> - /// <param name="edgeMatrix">The adjacency matrix.</param> - /// <param name="parameter">The input parameter of the mix.</param> - /// <param name="splitterContext">The splitter context.</param> - /// <returns>Return true, new connections were done on the adjacency matrix.</returns> - private bool UpdateConnection(EdgeMatrix edgeMatrix, ref MixParameter parameter, ref SplitterContext splitterContext) - { - bool hasNewConnections; - - if (DestinationSplitterId == UnusedSplitterId) - { - hasNewConnections = false; - } - else - { - ref SplitterState splitter = ref splitterContext.GetState((int)DestinationSplitterId); - - hasNewConnections = splitter.HasNewConnection; - } - - if (DestinationMixId == parameter.DestinationMixId && DestinationSplitterId == parameter.DestinationSplitterId && !hasNewConnections) - { - return false; - } - - edgeMatrix.RemoveEdges(MixId); - - if (parameter.DestinationMixId == UnusedMixId) - { - if (parameter.DestinationSplitterId != UnusedSplitterId) - { - ref SplitterState splitter = ref splitterContext.GetState((int)parameter.DestinationSplitterId); - - for (int i = 0; i < splitter.DestinationCount; i++) - { - Span<SplitterDestination> destination = splitter.GetData(i); - - if (!destination.IsEmpty) - { - int destinationMixId = destination[0].DestinationId; - - if (destinationMixId != UnusedMixId) - { - edgeMatrix.Connect(MixId, destinationMixId); - } - } - } - } - } - else - { - edgeMatrix.Connect(MixId, parameter.DestinationMixId); - } - - DestinationMixId = parameter.DestinationMixId; - DestinationSplitterId = parameter.DestinationSplitterId; - - return true; - } - - /// <summary> - /// Update the mix from user information. - /// </summary> - /// <param name="edgeMatrix">The adjacency matrix.</param> - /// <param name="parameter">The input parameter of the mix.</param> - /// <param name="effectContext">The effect context.</param> - /// <param name="splitterContext">The splitter context.</param> - /// <param name="behaviourContext">The behaviour context.</param> - /// <returns>Return true if the mix was changed.</returns> - public bool Update(EdgeMatrix edgeMatrix, ref MixParameter parameter, EffectContext effectContext, SplitterContext splitterContext, BehaviourContext behaviourContext) - { - bool isDirty; - - Volume = parameter.Volume; - SampleRate = parameter.SampleRate; - BufferCount = parameter.BufferCount; - IsUsed = parameter.IsUsed; - MixId = parameter.MixId; - NodeId = parameter.NodeId; - parameter.MixBufferVolume.CopyTo(MixBufferVolume); - - if (behaviourContext.IsSplitterSupported()) - { - isDirty = UpdateConnection(edgeMatrix, ref parameter, ref splitterContext); - } - else - { - isDirty = DestinationMixId != parameter.DestinationMixId; - - if (DestinationMixId != parameter.DestinationMixId) - { - DestinationMixId = parameter.DestinationMixId; - } - - DestinationSplitterId = UnusedSplitterId; - } - - ClearEffectProcessingOrder(); - - for (int i = 0; i < effectContext.GetCount(); i++) - { - ref BaseEffect effect = ref effectContext.GetEffect(i); - - if (effect.MixId == MixId) - { - Debug.Assert(effect.ProcessingOrder <= EffectProcessingOrderArrayMaxCount); - - if (effect.ProcessingOrder > EffectProcessingOrderArrayMaxCount) - { - return isDirty; - } - - EffectProcessingOrderArray[(int)effect.ProcessingOrder] = i; - } - } - - return isDirty; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceDetailEntry.cs b/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceDetailEntry.cs deleted file mode 100644 index 893cc008..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceDetailEntry.cs +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// <summary> - /// Represents a detailed entry in a performance frame. - /// </summary> - public interface IPerformanceDetailEntry - { - /// <summary> - /// Get the start time of this entry event (in microseconds). - /// </summary> - /// <returns>The start time of this entry event (in microseconds).</returns> - int GetStartTime(); - - /// <summary> - /// Get the start time offset in this structure. - /// </summary> - /// <returns>The start time offset in this structure.</returns> - int GetStartTimeOffset(); - - /// <summary> - /// Get the processing time of this entry event (in microseconds). - /// </summary> - /// <returns>The processing time of this entry event (in microseconds).</returns> - int GetProcessingTime(); - - /// <summary> - /// Get the processing time offset in this structure. - /// </summary> - /// <returns>The processing time offset in this structure.</returns> - int GetProcessingTimeOffset(); - - /// <summary> - /// Set the <paramref name="nodeId"/> of this entry. - /// </summary> - /// <param name="nodeId">The node id of this entry.</param> - void SetNodeId(int nodeId); - - /// <summary> - /// Set the <see cref="PerformanceEntryType"/> of this entry. - /// </summary> - /// <param name="type">The type to use.</param> - void SetEntryType(PerformanceEntryType type); - - /// <summary> - /// Set the <see cref="PerformanceDetailType"/> of this entry. - /// </summary> - /// <param name="detailType">The type to use.</param> - void SetDetailType(PerformanceDetailType detailType); - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceEntry.cs b/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceEntry.cs deleted file mode 100644 index 2a2fa9cc..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceEntry.cs +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// <summary> - /// Represents an entry in a performance frame. - /// </summary> - public interface IPerformanceEntry - { - /// <summary> - /// Get the start time of this entry event (in microseconds). - /// </summary> - /// <returns>The start time of this entry event (in microseconds).</returns> - int GetStartTime(); - - /// <summary> - /// Get the start time offset in this structure. - /// </summary> - /// <returns>The start time offset in this structure.</returns> - int GetStartTimeOffset(); - - /// <summary> - /// Get the processing time of this entry event (in microseconds). - /// </summary> - /// <returns>The processing time of this entry event (in microseconds).</returns> - int GetProcessingTime(); - - /// <summary> - /// Get the processing time offset in this structure. - /// </summary> - /// <returns>The processing time offset in this structure.</returns> - int GetProcessingTimeOffset(); - - /// <summary> - /// Set the <paramref name="nodeId"/> of this entry. - /// </summary> - /// <param name="nodeId">The node id of this entry.</param> - void SetNodeId(int nodeId); - - /// <summary> - /// Set the <see cref="PerformanceEntryType"/> of this entry. - /// </summary> - /// <param name="type">The type to use.</param> - void SetEntryType(PerformanceEntryType type); - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceHeader.cs b/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceHeader.cs deleted file mode 100644 index 5a26754d..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/IPerformanceHeader.cs +++ /dev/null @@ -1,97 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// <summary> - /// The header of a performance frame. - /// </summary> - public interface IPerformanceHeader - { - /// <summary> - /// Get the entry count offset in this structure. - /// </summary> - /// <returns>The entry count offset in this structure.</returns> - int GetEntryCountOffset(); - - /// <summary> - /// Set the DSP running behind flag. - /// </summary> - /// <param name="isRunningBehind">The flag.</param> - void SetDspRunningBehind(bool isRunningBehind); - - /// <summary> - /// Set the count of voices that were dropped. - /// </summary> - /// <param name="voiceCount">The count of voices that were dropped.</param> - void SetVoiceDropCount(uint voiceCount); - - /// <summary> - /// Set the start ticks of the <see cref="Dsp.AudioProcessor"/>. (before sending commands) - /// </summary> - /// <param name="startTicks">The start ticks of the <see cref="Dsp.AudioProcessor"/>. (before sending commands)</param> - void SetStartRenderingTicks(ulong startTicks); - - /// <summary> - /// Set the header magic. - /// </summary> - /// <param name="magic">The header magic.</param> - void SetMagic(uint magic); - - /// <summary> - /// Set the offset of the next performance header. - /// </summary> - /// <param name="nextOffset">The offset of the next performance header.</param> - void SetNextOffset(int nextOffset); - - /// <summary> - /// Set the total time taken by all the commands profiled. - /// </summary> - /// <param name="totalProcessingTime">The total time taken by all the commands profiled.</param> - void SetTotalProcessingTime(int totalProcessingTime); - - /// <summary> - /// Set the index of this performance frame. - /// </summary> - /// <param name="index">The index of this performance frame.</param> - void SetIndex(uint index); - - /// <summary> - /// Get the total count of entries in this frame. - /// </summary> - /// <returns>The total count of entries in this frame.</returns> - int GetEntryCount(); - - /// <summary> - /// Get the total count of detailed entries in this frame. - /// </summary> - /// <returns>The total count of detailed entries in this frame.</returns> - int GetEntryDetailCount(); - - /// <summary> - /// Set the total count of entries in this frame. - /// </summary> - /// <param name="entryCount">The total count of entries in this frame.</param> - void SetEntryCount(int entryCount); - - /// <summary> - /// Set the total count of detailed entries in this frame. - /// </summary> - /// <param name="entryDetailCount">The total count of detailed entries in this frame.</param> - void SetEntryDetailCount(int entryDetailCount); - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion1.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion1.cs deleted file mode 100644 index b7df7f28..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion1.cs +++ /dev/null @@ -1,89 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// <summary> - /// Implementation of <see cref="IPerformanceDetailEntry"/> for performance metrics version 1. - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] - public struct PerformanceDetailVersion1 : IPerformanceDetailEntry - { - /// <summary> - /// The node id associated to this detailed entry. - /// </summary> - public int NodeId; - - /// <summary> - /// The start time (in microseconds) associated to this detailed entry. - /// </summary> - public int StartTime; - - /// <summary> - /// The processing time (in microseconds) associated to this detailed entry. - /// </summary> - public int ProcessingTime; - - /// <summary> - /// The detailed entry type associated to this detailed entry. - /// </summary> - public PerformanceDetailType DetailType; - - /// <summary> - /// The entry type associated to this detailed entry. - /// </summary> - public PerformanceEntryType EntryType; - - public int GetProcessingTime() - { - return ProcessingTime; - } - - public int GetProcessingTimeOffset() - { - return 8; - } - - public int GetStartTime() - { - return StartTime; - } - - public int GetStartTimeOffset() - { - return 4; - } - - public void SetDetailType(PerformanceDetailType detailType) - { - DetailType = detailType; - } - - public void SetEntryType(PerformanceEntryType type) - { - EntryType = type; - } - - public void SetNodeId(int nodeId) - { - NodeId = nodeId; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion2.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion2.cs deleted file mode 100644 index da898b29..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceDetailVersion2.cs +++ /dev/null @@ -1,89 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// <summary> - /// Implementation of <see cref="IPerformanceDetailEntry"/> for performance metrics version 2. - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x18)] - public struct PerformanceDetailVersion2 : IPerformanceDetailEntry - { - /// <summary> - /// The node id associated to this detailed entry. - /// </summary> - public int NodeId; - - /// <summary> - /// The start time (in microseconds) associated to this detailed entry. - /// </summary> - public int StartTime; - - /// <summary> - /// The processing time (in microseconds) associated to this detailed entry. - /// </summary> - public int ProcessingTime; - - /// <summary> - /// The detailed entry type associated to this detailed entry. - /// </summary> - public PerformanceDetailType DetailType; - - /// <summary> - /// The entry type associated to this detailed entry. - /// </summary> - public PerformanceEntryType EntryType; - - public int GetProcessingTime() - { - return ProcessingTime; - } - - public int GetProcessingTimeOffset() - { - return 8; - } - - public int GetStartTime() - { - return StartTime; - } - - public int GetStartTimeOffset() - { - return 4; - } - - public void SetDetailType(PerformanceDetailType detailType) - { - DetailType = detailType; - } - - public void SetEntryType(PerformanceEntryType type) - { - EntryType = type; - } - - public void SetNodeId(int nodeId) - { - NodeId = nodeId; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryAddresses.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryAddresses.cs deleted file mode 100644 index ad99867f..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryAddresses.cs +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// <summary> - /// Information used by the performance command to store informations in the performance entry. - /// </summary> - public class PerformanceEntryAddresses - { - /// <summary> - /// The memory storing the performance entry. - /// </summary> - public Memory<int> BaseMemory; - - /// <summary> - /// The offset to the start time field. - /// </summary> - public uint StartTimeOffset; - - /// <summary> - /// The offset to the entry count field. - /// </summary> - public uint EntryCountOffset; - - /// <summary> - /// The offset to the processing time field. - /// </summary> - public uint ProcessingTimeOffset; - - /// <summary> - /// Increment the entry count. - /// </summary> - public void IncrementEntryCount() - { - BaseMemory.Span[(int)EntryCountOffset / 4]++; - } - - /// <summary> - /// Set the start time in the entry. - /// </summary> - /// <param name="startTimeNano">The start time in nanoseconds.</param> - public void SetStartTime(ulong startTimeNano) - { - BaseMemory.Span[(int)StartTimeOffset / 4] = (int)(startTimeNano / 1000); - } - - /// <summary> - /// Set the processing time in the entry. - /// </summary> - /// <param name="endTimeNano">The end time in nanoseconds.</param> - public void SetProcessingTime(ulong endTimeNano) - { - BaseMemory.Span[(int)ProcessingTimeOffset / 4] = (int)(endTimeNano / 1000) - BaseMemory.Span[(int)StartTimeOffset / 4]; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion1.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion1.cs deleted file mode 100644 index ac91ca19..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion1.cs +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// <summary> - /// Implementation of <see cref="IPerformanceEntry"/> for performance metrics version 1. - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] - public struct PerformanceEntryVersion1 : IPerformanceEntry - { - /// <summary> - /// The node id associated to this entry. - /// </summary> - public int NodeId; - - /// <summary> - /// The start time (in microseconds) associated to this entry. - /// </summary> - public int StartTime; - - /// <summary> - /// The processing time (in microseconds) associated to this entry. - /// </summary> - public int ProcessingTime; - - /// <summary> - /// The entry type associated to this entry. - /// </summary> - public PerformanceEntryType EntryType; - - public int GetProcessingTime() - { - return ProcessingTime; - } - - public int GetProcessingTimeOffset() - { - return 8; - } - - public int GetStartTime() - { - return StartTime; - } - - public int GetStartTimeOffset() - { - return 4; - } - - public void SetEntryType(PerformanceEntryType type) - { - EntryType = type; - } - - public void SetNodeId(int nodeId) - { - NodeId = nodeId; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion2.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion2.cs deleted file mode 100644 index 84ee5bc9..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceEntryVersion2.cs +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// <summary> - /// Implementation of <see cref="IPerformanceEntry"/> for performance metrics version 2. - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x18)] - public struct PerformanceEntryVersion2 : IPerformanceEntry - { - /// <summary> - /// The node id associated to this entry. - /// </summary> - public int NodeId; - - /// <summary> - /// The start time (in microseconds) associated to this entry. - /// </summary> - public int StartTime; - - /// <summary> - /// The processing time (in microseconds) associated to this entry. - /// </summary> - public int ProcessingTime; - - /// <summary> - /// The entry type associated to this entry. - /// </summary> - public PerformanceEntryType EntryType; - - public int GetProcessingTime() - { - return ProcessingTime; - } - - public int GetProcessingTimeOffset() - { - return 8; - } - - public int GetStartTime() - { - return StartTime; - } - - public int GetStartTimeOffset() - { - return 4; - } - - public void SetEntryType(PerformanceEntryType type) - { - EntryType = type; - } - - public void SetNodeId(int nodeId) - { - NodeId = nodeId; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion1.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion1.cs deleted file mode 100644 index b0757b37..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion1.cs +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// <summary> - /// Implementation of <see cref="IPerformanceHeader"/> for performance metrics version 1. - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x18)] - public struct PerformanceFrameHeaderVersion1 : IPerformanceHeader - { - /// <summary> - /// The magic of the performance header. - /// </summary> - public uint Magic; - - /// <summary> - /// The total count of entries in this frame. - /// </summary> - public int EntryCount; - - /// <summary> - /// The total count of detailed entries in this frame. - /// </summary> - public int EntryDetailCount; - - /// <summary> - /// The offset of the next performance header. - /// </summary> - public int NextOffset; - - /// <summary> - /// The total time taken by all the commands profiled. - /// </summary> - public int TotalProcessingTime; - - /// <summary> - /// The count of voices that were dropped. - /// </summary> - public uint VoiceDropCount; - - public int GetEntryCount() - { - return EntryCount; - } - - public int GetEntryCountOffset() - { - return 4; - } - - public int GetEntryDetailCount() - { - return EntryDetailCount; - } - - public void SetDspRunningBehind(bool isRunningBehind) - { - // NOTE: Not present in version 1 - } - - public void SetEntryCount(int entryCount) - { - EntryCount = entryCount; - } - - public void SetEntryDetailCount(int entryDetailCount) - { - EntryDetailCount = entryDetailCount; - } - - public void SetIndex(uint index) - { - // NOTE: Not present in version 1 - } - - public void SetMagic(uint magic) - { - Magic = magic; - } - - public void SetNextOffset(int nextOffset) - { - NextOffset = nextOffset; - } - - public void SetStartRenderingTicks(ulong startTicks) - { - // NOTE: not present in version 1 - } - - public void SetTotalProcessingTime(int totalProcessingTime) - { - TotalProcessingTime = totalProcessingTime; - } - - public void SetVoiceDropCount(uint voiceCount) - { - VoiceDropCount = voiceCount; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion2.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion2.cs deleted file mode 100644 index ba873239..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceFrameHeaderVersion2.cs +++ /dev/null @@ -1,134 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// <summary> - /// Implementation of <see cref="IPerformanceHeader"/> for performance metrics version 2. - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x30)] - public struct PerformanceFrameHeaderVersion2 : IPerformanceHeader - { - /// <summary> - /// The magic of the performance header. - /// </summary> - public uint Magic; - - /// <summary> - /// The total count of entries in this frame. - /// </summary> - public int EntryCount; - - /// <summary> - /// The total count of detailed entries in this frame. - /// </summary> - public int EntryDetailCount; - - /// <summary> - /// The offset of the next performance header. - /// </summary> - public int NextOffset; - - /// <summary> - /// The total time taken by all the commands profiled. - /// </summary> - public int TotalProcessingTime; - - /// <summary> - /// The count of voices that were dropped. - /// </summary> - public uint VoiceDropCount; - - /// <summary> - /// The start ticks of the <see cref="Dsp.AudioProcessor"/>. (before sending commands) - /// </summary> - public ulong StartRenderingTicks; - - /// <summary> - /// The index of this performance frame. - /// </summary> - public uint Index; - - /// <summary> - /// If set to true, the DSP is running behind. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool IsDspRunningBehind; - - public int GetEntryCount() - { - return EntryCount; - } - - public int GetEntryCountOffset() - { - return 4; - } - - public int GetEntryDetailCount() - { - return EntryDetailCount; - } - - public void SetDspRunningBehind(bool isRunningBehind) - { - IsDspRunningBehind = isRunningBehind; - } - - public void SetEntryCount(int entryCount) - { - EntryCount = entryCount; - } - - public void SetEntryDetailCount(int entryDetailCount) - { - EntryDetailCount = entryDetailCount; - } - - public void SetIndex(uint index) - { - Index = index; - } - - public void SetMagic(uint magic) - { - Magic = magic; - } - - public void SetNextOffset(int nextOffset) - { - NextOffset = nextOffset; - } - - public void SetStartRenderingTicks(ulong startTicks) - { - StartRenderingTicks = startTicks; - } - - public void SetTotalProcessingTime(int totalProcessingTime) - { - TotalProcessingTime = totalProcessingTime; - } - - public void SetVoiceDropCount(uint voiceCount) - { - VoiceDropCount = voiceCount; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManager.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManager.cs deleted file mode 100644 index 3a336af3..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManager.cs +++ /dev/null @@ -1,124 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using System; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - public abstract class PerformanceManager - { - /// <summary> - /// Get the required size for a single performance frame. - /// </summary> - /// <param name="parameter">The audio renderer configuration.</param> - /// <param name="behaviourContext">The behaviour context.</param> - /// <returns>The required size for a single performance frame.</returns> - public static ulong GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref AudioRendererConfiguration parameter, ref BehaviourContext behaviourContext) - { - uint version = behaviourContext.GetPerformanceMetricsDataFormat(); - - if (version == 2) - { - return (ulong)PerformanceManagerGeneric<PerformanceFrameHeaderVersion2, - PerformanceEntryVersion2, - PerformanceDetailVersion2>.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); - } - else if (version == 1) - { - return (ulong)PerformanceManagerGeneric<PerformanceFrameHeaderVersion1, - PerformanceEntryVersion1, - PerformanceDetailVersion1>.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); - } - - throw new NotImplementedException($"Unknown Performance metrics data format version {version}"); - } - - /// <summary> - /// Copy the performance frame history to the supplied user buffer and returns the size copied. - /// </summary> - /// <param name="performanceOutput">The supplied user buffer to store the performance frame into.</param> - /// <returns>The size copied to the supplied buffer.</returns> - public abstract uint CopyHistories(Span<byte> performanceOutput); - - /// <summary> - /// Set the target node id to profile. - /// </summary> - /// <param name="target">The target node id to profile.</param> - public abstract void SetTargetNodeId(int target); - - /// <summary> - /// Check if the given target node id is profiled. - /// </summary> - /// <param name="target">The target node id to check.</param> - /// <returns>Return true, if the given target node id is profiled.</returns> - public abstract bool IsTargetNodeId(int target); - - /// <summary> - /// Get the next buffer to store a performance entry. - /// </summary> - /// <param name="performanceEntry">The output <see cref="PerformanceEntryAddresses"/>.</param> - /// <param name="entryType">The <see cref="PerformanceEntryType"/> info.</param> - /// <param name="nodeId">The node id of the entry.</param> - /// <returns>Return true, if a valid <see cref="PerformanceEntryAddresses"/> was returned.</returns> - public abstract bool GetNextEntry(out PerformanceEntryAddresses performanceEntry, PerformanceEntryType entryType, int nodeId); - - /// <summary> - /// Get the next buffer to store a performance detailed entry. - /// </summary> - /// <param name="performanceEntry">The output <see cref="PerformanceEntryAddresses"/>.</param> - /// <param name="detailType">The <see cref="PerformanceDetailType"/> info.</param> - /// <param name="entryType">The <see cref="PerformanceEntryType"/> info.</param> - /// <param name="nodeId">The node id of the entry.</param> - /// <returns>Return true, if a valid <see cref="PerformanceEntryAddresses"/> was returned.</returns> - public abstract bool GetNextEntry(out PerformanceEntryAddresses performanceEntry, PerformanceDetailType detailType, PerformanceEntryType entryType, int nodeId); - - /// <summary> - /// Finalize the current performance frame. - /// </summary> - /// <param name="dspRunningBehind">Indicate if the DSP is running behind.</param> - /// <param name="voiceDropCount">The count of voices that were dropped.</param> - /// <param name="startRenderingTicks">The start ticks of the audio rendering.</param> - public abstract void TapFrame(bool dspRunningBehind, uint voiceDropCount, ulong startRenderingTicks); - - /// <summary> - /// Create a new <see cref="PerformanceManager"/>. - /// </summary> - /// <param name="performanceBuffer">The backing memory available for use by the manager.</param> - /// <param name="parameter">The audio renderer configuration.</param> - /// <param name="behaviourContext">The behaviour context;</param> - /// <returns>A new <see cref="PerformanceManager"/>.</returns> - public static PerformanceManager Create(Memory<byte> performanceBuffer, ref AudioRendererConfiguration parameter, BehaviourContext behaviourContext) - { - uint version = behaviourContext.GetPerformanceMetricsDataFormat(); - - switch (version) - { - case 1: - return new PerformanceManagerGeneric<PerformanceFrameHeaderVersion1, PerformanceEntryVersion1, PerformanceDetailVersion1>(performanceBuffer, - ref parameter); - case 2: - return new PerformanceManagerGeneric<PerformanceFrameHeaderVersion2, PerformanceEntryVersion2, PerformanceDetailVersion2>(performanceBuffer, - ref parameter); - default: - throw new NotImplementedException($"Unknown Performance metrics data format version {version}"); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManagerGeneric.cs b/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManagerGeneric.cs deleted file mode 100644 index b17e6f3f..00000000 --- a/Ryujinx.Audio.Renderer/Server/Performance/PerformanceManagerGeneric.cs +++ /dev/null @@ -1,311 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Utils; -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Performance -{ - /// <summary> - /// A Generic implementation of <see cref="PerformanceManager"/>. - /// </summary> - /// <typeparam name="THeader">The header implementation of the performance frame.</typeparam> - /// <typeparam name="TEntry">The entry implementation of the performance frame.</typeparam> - /// <typeparam name="TEntryDetail">A detailed implementation of the performance frame.</typeparam> - public class PerformanceManagerGeneric<THeader, TEntry, TEntryDetail> : PerformanceManager where THeader: unmanaged, IPerformanceHeader where TEntry : unmanaged, IPerformanceEntry where TEntryDetail: unmanaged, IPerformanceDetailEntry - { - /// <summary> - /// The magic used for the <see cref="THeader"/>. - /// </summary> - private const uint MagicPerformanceBuffer = 0x46524550; - - /// <summary> - /// The fixed amount of <see cref="TEntryDetail"/> that can be stored in a frame. - /// </summary> - private const int MaxFrameDetailCount = 100; - - private Memory<byte> _buffer; - private Memory<byte> _historyBuffer; - - private Memory<byte> CurrentBuffer => _buffer.Slice(0, _frameSize); - private Memory<byte> CurrentBufferData => CurrentBuffer.Slice(Unsafe.SizeOf<THeader>()); - - private ref THeader CurrentHeader => ref MemoryMarshal.Cast<byte, THeader>(CurrentBuffer.Span)[0]; - - private Span<TEntry> Entries => MemoryMarshal.Cast<byte, TEntry>(CurrentBufferData.Span.Slice(0, GetEntriesSize())); - private Span<TEntryDetail> EntriesDetail => MemoryMarshal.Cast<byte, TEntryDetail>(CurrentBufferData.Span.Slice(GetEntriesSize(), GetEntriesDetailSize())); - - private int _frameSize; - private int _availableFrameCount; - private int _entryCountPerFrame; - private int _detailTarget; - private int _entryIndex; - private int _entryDetailIndex; - private int _indexHistoryWrite; - private int _indexHistoryRead; - private uint _historyFrameIndex; - - public PerformanceManagerGeneric(Memory<byte> buffer, ref AudioRendererConfiguration parameter) - { - _buffer = buffer; - _frameSize = GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); - - _entryCountPerFrame = (int)GetEntryCount(ref parameter); - _availableFrameCount = buffer.Length / _frameSize - 1; - - _historyFrameIndex = 0; - - _historyBuffer = _buffer.Slice(_frameSize); - - SetupNewHeader(); - } - - private Span<byte> GetBufferFromIndex(Span<byte> data, int index) - { - return data.Slice(index * _frameSize, _frameSize); - } - - private ref THeader GetHeaderFromBuffer(Span<byte> data, int index) - { - return ref MemoryMarshal.Cast<byte, THeader>(GetBufferFromIndex(data, index))[0]; - } - - private Span<TEntry> GetEntriesFromBuffer(Span<byte> data, int index) - { - return MemoryMarshal.Cast<byte, TEntry>(GetBufferFromIndex(data, index).Slice(Unsafe.SizeOf<THeader>(), GetEntriesSize())); - } - - private Span<TEntryDetail> GetEntriesDetailFromBuffer(Span<byte> data, int index) - { - return MemoryMarshal.Cast<byte, TEntryDetail>(GetBufferFromIndex(data, index).Slice(Unsafe.SizeOf<THeader>() + GetEntriesSize(), GetEntriesDetailSize())); - } - - private void SetupNewHeader() - { - _entryIndex = 0; - _entryDetailIndex = 0; - - CurrentHeader.SetEntryCount(0); - CurrentHeader.SetEntryDetailCount(0); - } - - public static uint GetEntryCount(ref AudioRendererConfiguration parameter) - { - return parameter.VoiceCount + parameter.EffectCount + parameter.SubMixBufferCount + parameter.SinkCount + 1; - } - - public int GetEntriesSize() - { - return Unsafe.SizeOf<TEntry>() * _entryCountPerFrame; - } - - public static int GetEntriesDetailSize() - { - return Unsafe.SizeOf<TEntryDetail>() * MaxFrameDetailCount; - } - - public static int GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref AudioRendererConfiguration parameter) - { - return Unsafe.SizeOf<TEntry>() * (int)GetEntryCount(ref parameter) + GetEntriesDetailSize() + Unsafe.SizeOf<THeader>(); - } - - public override uint CopyHistories(Span<byte> performanceOutput) - { - if (performanceOutput.IsEmpty) - { - return 0; - } - - int nextOffset = 0; - - while (_indexHistoryRead != _indexHistoryWrite) - { - if (nextOffset >= performanceOutput.Length) - { - break; - } - - ref THeader inputHeader = ref GetHeaderFromBuffer(_historyBuffer.Span, _indexHistoryRead); - Span<TEntry> inputEntries = GetEntriesFromBuffer(_historyBuffer.Span, _indexHistoryRead); - Span<TEntryDetail> inputEntriesDetail = GetEntriesDetailFromBuffer(_historyBuffer.Span, _indexHistoryRead); - - Span<byte> targetSpan = performanceOutput.Slice(nextOffset); - - ref THeader outputHeader = ref MemoryMarshal.Cast<byte, THeader>(targetSpan)[0]; - - nextOffset += Unsafe.SizeOf<THeader>(); - - Span<TEntry> outputEntries = MemoryMarshal.Cast<byte, TEntry>(targetSpan.Slice(nextOffset)); - - int totalProcessingTime = 0; - - int effectiveEntryCount = 0; - - for (int entryIndex = 0; entryIndex < inputHeader.GetEntryCount(); entryIndex++) - { - ref TEntry input = ref inputEntries[entryIndex]; - - if (input.GetProcessingTime() != 0 || input.GetStartTime() != 0) - { - ref TEntry output = ref outputEntries[effectiveEntryCount++]; - - output = input; - - nextOffset += Unsafe.SizeOf<TEntry>(); - - totalProcessingTime += input.GetProcessingTime(); - } - } - - Span<TEntryDetail> outputEntriesDetail = MemoryMarshal.Cast<byte, TEntryDetail>(targetSpan.Slice(nextOffset)); - - int effectiveEntryDetailCount = 0; - - for (int entryDetailIndex = 0; entryDetailIndex < inputHeader.GetEntryDetailCount(); entryDetailIndex++) - { - ref TEntryDetail input = ref inputEntriesDetail[entryDetailIndex]; - - if (input.GetProcessingTime() != 0 || input.GetStartTime() != 0) - { - ref TEntryDetail output = ref outputEntriesDetail[effectiveEntryDetailCount++]; - - output = input; - - nextOffset += Unsafe.SizeOf<TEntryDetail>(); - } - } - - outputHeader = inputHeader; - outputHeader.SetMagic(MagicPerformanceBuffer); - outputHeader.SetTotalProcessingTime(totalProcessingTime); - outputHeader.SetNextOffset(nextOffset); - outputHeader.SetEntryCount(effectiveEntryCount); - outputHeader.SetEntryDetailCount(effectiveEntryDetailCount); - - _indexHistoryRead = (_indexHistoryRead + 1) % _availableFrameCount; - } - - if (nextOffset < performanceOutput.Length && (performanceOutput.Length - nextOffset) >= Unsafe.SizeOf<THeader>()) - { - ref THeader outputHeader = ref MemoryMarshal.Cast<byte, THeader>(performanceOutput.Slice(nextOffset))[0]; - - outputHeader = default; - } - - return (uint)nextOffset; - } - - public override bool GetNextEntry(out PerformanceEntryAddresses performanceEntry, PerformanceEntryType entryType, int nodeId) - { - performanceEntry = new PerformanceEntryAddresses(); - performanceEntry.BaseMemory = SpanMemoryManager<int>.Cast(CurrentBuffer); - performanceEntry.EntryCountOffset = (uint)CurrentHeader.GetEntryCountOffset(); - - uint baseEntryOffset = (uint)(Unsafe.SizeOf<THeader>() + Unsafe.SizeOf<TEntry>() * _entryIndex); - - ref TEntry entry = ref Entries[_entryIndex]; - - performanceEntry.StartTimeOffset = baseEntryOffset + (uint)entry.GetStartTimeOffset(); - performanceEntry.ProcessingTimeOffset = baseEntryOffset + (uint)entry.GetProcessingTimeOffset(); - - entry = default; - entry.SetEntryType(entryType); - entry.SetNodeId(nodeId); - - _entryIndex++; - - return true; - } - - public override bool GetNextEntry(out PerformanceEntryAddresses performanceEntry, PerformanceDetailType detailType, PerformanceEntryType entryType, int nodeId) - { - performanceEntry = null; - - if (_entryDetailIndex > MaxFrameDetailCount) - { - return false; - } - - performanceEntry = new PerformanceEntryAddresses(); - performanceEntry.BaseMemory = SpanMemoryManager<int>.Cast(CurrentBuffer); - performanceEntry.EntryCountOffset = (uint)CurrentHeader.GetEntryCountOffset(); - - uint baseEntryOffset = (uint)(Unsafe.SizeOf<THeader>() + GetEntriesSize() + Unsafe.SizeOf<IPerformanceDetailEntry>() * _entryDetailIndex); - - ref TEntryDetail entryDetail = ref EntriesDetail[_entryDetailIndex]; - - performanceEntry.StartTimeOffset = baseEntryOffset + (uint)entryDetail.GetStartTimeOffset(); - performanceEntry.ProcessingTimeOffset = baseEntryOffset + (uint)entryDetail.GetProcessingTimeOffset(); - - entryDetail = default; - entryDetail.SetDetailType(detailType); - entryDetail.SetEntryType(entryType); - entryDetail.SetNodeId(nodeId); - - _entryDetailIndex++; - - return true; - } - - public override bool IsTargetNodeId(int target) - { - return _detailTarget == target; - } - - public override void SetTargetNodeId(int target) - { - _detailTarget = target; - } - - public override void TapFrame(bool dspRunningBehind, uint voiceDropCount, ulong startRenderingTicks) - { - if (_availableFrameCount > 0) - { - int targetIndexForHistory = _indexHistoryWrite; - - _indexHistoryWrite = (_indexHistoryWrite + 1) % _availableFrameCount; - - ref THeader targetHeader = ref GetHeaderFromBuffer(_historyBuffer.Span, targetIndexForHistory); - - CurrentBuffer.Span.CopyTo(GetBufferFromIndex(_historyBuffer.Span, targetIndexForHistory)); - - uint targetHistoryFrameIndex = _historyFrameIndex; - - if (_historyFrameIndex == uint.MaxValue) - { - _historyFrameIndex = 0; - } - else - { - _historyFrameIndex++; - } - - targetHeader.SetDspRunningBehind(dspRunningBehind); - targetHeader.SetVoiceDropCount(voiceDropCount); - targetHeader.SetStartRenderingTicks(startRenderingTicks); - targetHeader.SetIndex(targetHistoryFrameIndex); - - // Finally setup the new header - SetupNewHeader(); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/RendererSystemContext.cs b/Ryujinx.Audio.Renderer/Server/RendererSystemContext.cs deleted file mode 100644 index a89a8a60..00000000 --- a/Ryujinx.Audio.Renderer/Server/RendererSystemContext.cs +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Server.Upsampler; -using System; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// <summary> - /// Represents a lite version of <see cref="AudioRenderSystem"/> used by the <see cref="Dsp.AudioProcessor"/> - /// </summary> - /// <remarks> - /// This also allows to reduce dependencies on the <see cref="AudioRenderSystem"/> for unit testing. - /// </remarks> - public sealed class RendererSystemContext - { - /// <summary> - /// The session id of the current renderer. - /// </summary> - public int SessionId; - - /// <summary> - /// The target channel count for sink. - /// </summary> - /// <remarks>See <see cref="CommandGenerator.GenerateDevice(Sink.DeviceSink, ref Mix.MixState)"/> for usage.</remarks> - public uint ChannelCount; - - /// <summary> - /// The total count of mix buffer. - /// </summary> - public uint MixBufferCount; - - /// <summary> - /// Instance of the <see cref="BehaviourContext"/> used to derive bug fixes and features of the current audio renderer revision. - /// </summary> - public BehaviourContext BehaviourContext; - - /// <summary> - /// Instance of the <see cref="UpsamplerManager"/> used for upsampling (see <see cref="UpsamplerState"/>) - /// </summary> - public UpsamplerManager UpsamplerManager; - - /// <summary> - /// The memory to use for depop processing. - /// </summary> - /// <remarks> - /// See <see cref="Dsp.Command.DepopForMixBuffersCommand"/> and <see cref="Dsp.Command.DepopPrepareCommand"/> - /// </remarks> - public Memory<float> DepopBuffer; - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Sink/BaseSink.cs b/Ryujinx.Audio.Renderer/Server/Sink/BaseSink.cs deleted file mode 100644 index 949e3971..00000000 --- a/Ryujinx.Audio.Renderer/Server/Sink/BaseSink.cs +++ /dev/null @@ -1,119 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System.Diagnostics; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; - -namespace Ryujinx.Audio.Renderer.Server.Sink -{ - /// <summary> - /// Base class used for server information of a sink. - /// </summary> - public class BaseSink - { - /// <summary> - /// The type of this <see cref="BaseSink"/>. - /// </summary> - public SinkType Type; - - /// <summary> - /// Set to true if the sink is used. - /// </summary> - public bool IsUsed; - - /// <summary> - /// Set to true if the sink need to be skipped because of invalid state. - /// </summary> - public bool ShouldSkip; - - /// <summary> - /// The node id of the sink. - /// </summary> - public int NodeId; - - /// <summary> - /// Create a new <see cref="BaseSink"/>. - /// </summary> - public BaseSink() - { - CleanUp(); - } - - /// <summary> - /// Clean up the internal state of the <see cref="BaseSink"/>. - /// </summary> - public virtual void CleanUp() - { - Type = TargetSinkType; - IsUsed = false; - ShouldSkip = false; - } - - /// <summary> - /// The target <see cref="SinkType"/> handled by this <see cref="BaseSink"/>. - /// </summary> - public virtual SinkType TargetSinkType => SinkType.Invalid; - - /// <summary> - /// Check if the <see cref="SinkType"/> sent by the user match the internal <see cref="SinkType"/>. - /// </summary> - /// <param name="parameter">The user parameter.</param> - /// <returns>Return true, if the <see cref="SinkType"/> sent by the user match the internal <see cref="SinkType"/>.</returns> - public bool IsTypeValid(ref SinkInParameter parameter) - { - return parameter.Type == TargetSinkType; - } - - /// <summary> - /// Update the <see cref="BaseSink"/> state during command generation. - /// </summary> - public virtual void UpdateForCommandGeneration() - { - Debug.Assert(Type == TargetSinkType); - } - - /// <summary> - /// Update the internal common parameters from user parameter. - /// </summary> - /// <param name="parameter">The user parameter.</param> - protected void UpdateStandardParameter(ref SinkInParameter parameter) - { - if (IsUsed != parameter.IsUsed) - { - IsUsed = parameter.IsUsed; - NodeId = parameter.NodeId; - } - } - - /// <summary> - /// Update the internal state from user parameter. - /// </summary> - /// <param name="errorInfo">The possible <see cref="ErrorInfo"/> that was generated.</param> - /// <param name="parameter">The user parameter.</param> - /// <param name="outStatus">The user output status.</param> - /// <param name="mapper">The mapper to use.</param> - public virtual void Update(out ErrorInfo errorInfo, ref SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - errorInfo = new ErrorInfo(); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Sink/CircularBufferSink.cs b/Ryujinx.Audio.Renderer/Server/Sink/CircularBufferSink.cs deleted file mode 100644 index 16d25a65..00000000 --- a/Ryujinx.Audio.Renderer/Server/Sink/CircularBufferSink.cs +++ /dev/null @@ -1,126 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Sink; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Sink -{ - /// <summary> - /// Server information for a circular buffer sink. - /// </summary> - public class CircularBufferSink : BaseSink - { - /// <summary> - /// The circular buffer parameter. - /// </summary> - public CircularBufferParameter Parameter; - - /// <summary> - /// The last written data offset on the circular buffer. - /// </summary> - private uint _lastWrittenOffset; - - /// <summary> - /// THe previous written offset of the circular buffer. - /// </summary> - private uint _oldWrittenOffset; - - /// <summary> - /// The current offset to write data on the circular buffer. - /// </summary> - public uint CurrentWriteOffset { get; private set; } - - /// <summary> - /// The <see cref="AddressInfo"/> of the circular buffer. - /// </summary> - public AddressInfo CircularBufferAddressInfo; - - public CircularBufferSink() - { - CircularBufferAddressInfo = AddressInfo.Create(); - } - - public override SinkType TargetSinkType => SinkType.CircularBuffer; - - public override void Update(out BehaviourParameter.ErrorInfo errorInfo, ref SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) - { - errorInfo = new BehaviourParameter.ErrorInfo(); - outStatus = new SinkOutStatus(); - - Debug.Assert(IsTypeValid(ref parameter)); - - ref CircularBufferParameter inputDeviceParameter = ref MemoryMarshal.Cast<byte, CircularBufferParameter>(parameter.SpecificData)[0]; - - if (parameter.IsUsed != IsUsed || ShouldSkip) - { - UpdateStandardParameter(ref parameter); - - if (parameter.IsUsed) - { - Debug.Assert(CircularBufferAddressInfo.CpuAddress == 0); - Debug.Assert(CircularBufferAddressInfo.GetReference(false) == 0); - - ShouldSkip = !mapper.TryAttachBuffer(out errorInfo, ref CircularBufferAddressInfo, inputDeviceParameter.BufferAddress, inputDeviceParameter.BufferSize); - } - else - { - Debug.Assert(CircularBufferAddressInfo.CpuAddress != 0); - Debug.Assert(CircularBufferAddressInfo.GetReference(false) != 0); - } - - Parameter = inputDeviceParameter; - } - - outStatus.LastWrittenOffset = _lastWrittenOffset; - } - - public override void UpdateForCommandGeneration() - { - Debug.Assert(Type == TargetSinkType); - - if (IsUsed) - { - uint frameSize = RendererConstants.TargetSampleSize * Parameter.SampleCount * Parameter.InputCount; - - _lastWrittenOffset = _oldWrittenOffset; - - _oldWrittenOffset = CurrentWriteOffset; - - CurrentWriteOffset += frameSize; - - if (Parameter.BufferSize > 0) - { - CurrentWriteOffset %= Parameter.BufferSize; - } - } - } - - public override void CleanUp() - { - CircularBufferAddressInfo = AddressInfo.Create(); - _lastWrittenOffset = 0; - _oldWrittenOffset = 0; - CurrentWriteOffset = 0; - base.CleanUp(); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Sink/DeviceSink.cs b/Ryujinx.Audio.Renderer/Server/Sink/DeviceSink.cs deleted file mode 100644 index 79af05f7..00000000 --- a/Ryujinx.Audio.Renderer/Server/Sink/DeviceSink.cs +++ /dev/null @@ -1,92 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Sink; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using Ryujinx.Audio.Renderer.Server.Upsampler; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Sink -{ - /// <summary> - /// Server information for a device sink. - /// </summary> - public class DeviceSink : BaseSink - { - /// <summary> - /// The downmix coefficients. - /// </summary> - public float[] DownMixCoefficients; - - /// <summary> - /// The device parameters. - /// </summary> - public DeviceParameter Parameter; - - /// <summary> - /// The upsampler instance used by this sink. - /// </summary> - /// <remarks>Null if no upsampling is needed.</remarks> - public UpsamplerState UpsamplerState; - - /// <summary> - /// Create a new <see cref="DeviceSink"/>. - /// </summary> - public DeviceSink() - { - DownMixCoefficients = new float[4]; - } - - public override void CleanUp() - { - UpsamplerState?.Release(); - - UpsamplerState = null; - - base.CleanUp(); - } - - public override SinkType TargetSinkType => SinkType.Device; - - public override void Update(out BehaviourParameter.ErrorInfo errorInfo, ref SinkInParameter parameter, ref SinkOutStatus outStatus, PoolMapper mapper) - { - Debug.Assert(IsTypeValid(ref parameter)); - - ref DeviceParameter inputDeviceParameter = ref MemoryMarshal.Cast<byte, DeviceParameter>(parameter.SpecificData)[0]; - - if (parameter.IsUsed != IsUsed) - { - UpdateStandardParameter(ref parameter); - Parameter = inputDeviceParameter; - } - else - { - Parameter.DownMixParameterEnabled = inputDeviceParameter.DownMixParameterEnabled; - inputDeviceParameter.DownMixParameter.ToSpan().CopyTo(Parameter.DownMixParameter.ToSpan()); - } - - Parameter.DownMixParameter.ToSpan().CopyTo(DownMixCoefficients.AsSpan()); - - errorInfo = new BehaviourParameter.ErrorInfo(); - outStatus = new SinkOutStatus(); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Sink/SinkContext.cs b/Ryujinx.Audio.Renderer/Server/Sink/SinkContext.cs deleted file mode 100644 index b57dbde9..00000000 --- a/Ryujinx.Audio.Renderer/Server/Sink/SinkContext.cs +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server.Sink -{ - /// <summary> - /// Sink context. - /// </summary> - public class SinkContext - { - /// <summary> - /// Storage for <see cref="BaseSink"/>. - /// </summary> - private BaseSink[] _sinks; - - /// <summary> - /// The total sink count. - /// </summary> - private uint _sinkCount; - - /// <summary> - /// Initialize the <see cref="SinkContext"/>. - /// </summary> - /// <param name="sinksCount">The total sink count.</param> - public void Initialize(uint sinksCount) - { - _sinkCount = sinksCount; - _sinks = new BaseSink[_sinkCount]; - - for (int i = 0; i < _sinkCount; i++) - { - _sinks[i] = new BaseSink(); - } - } - - /// <summary> - /// Get the total sink count. - /// </summary> - /// <returns>The total sink count.</returns> - public uint GetCount() - { - return _sinkCount; - } - - /// <summary> - /// Get a reference to a <see cref="BaseSink"/> at the given <paramref name="id"/>. - /// </summary> - /// <param name="id">The index to use.</param> - /// <returns>A reference to a <see cref="BaseSink"/> at the given <paramref name="id"/>.</returns> - public ref BaseSink GetSink(int id) - { - Debug.Assert(id >= 0 && id < _sinkCount); - - return ref _sinks[id]; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterContext.cs b/Ryujinx.Audio.Renderer/Server/Splitter/SplitterContext.cs deleted file mode 100644 index 0e107a53..00000000 --- a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterContext.cs +++ /dev/null @@ -1,320 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Utils; -using Ryujinx.Common; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Splitter -{ - /// <summary> - /// Splitter context. - /// </summary> - public class SplitterContext - { - /// <summary> - /// Storage for <see cref="SplitterState"/>. - /// </summary> - private Memory<SplitterState> _splitters; - - /// <summary> - /// Storage for <see cref="SplitterDestination"/>. - /// </summary> - private Memory<SplitterDestination> _splitterDestinations; - - /// <summary> - /// If set to true, trust the user destination count in <see cref="SplitterState.Update(SplitterContext, ref SplitterInParameter, ReadOnlySpan{byte})"/>. - /// </summary> - public bool IsBugFixed { get; private set; } - - /// <summary> - /// Initialize <see cref="SplitterContext"/>. - /// </summary> - /// <param name="behaviourContext">The behaviour context.</param> - /// <param name="parameter">The audio renderer configuration.</param> - /// <param name="workBufferAllocator">The <see cref="WorkBufferAllocator"/>.</param> - /// <returns>Return true if the initialization was successful.</returns> - public bool Initialize(ref BehaviourContext behaviourContext, ref AudioRendererConfiguration parameter, WorkBufferAllocator workBufferAllocator) - { - if (!behaviourContext.IsSplitterSupported() || parameter.SplitterCount <= 0 || parameter.SplitterDestinationCount <= 0) - { - Setup(Memory<SplitterState>.Empty, Memory<SplitterDestination>.Empty, false); - - return true; - } - - Memory<SplitterState> splitters = workBufferAllocator.Allocate<SplitterState>(parameter.SplitterCount, SplitterState.Alignment); - - if (splitters.IsEmpty) - { - return false; - } - - int splitterId = 0; - - foreach (ref SplitterState splitter in splitters.Span) - { - splitter = new SplitterState(splitterId++); - } - - Memory<SplitterDestination> splitterDestinations = workBufferAllocator.Allocate<SplitterDestination>(parameter.SplitterDestinationCount, - SplitterDestination.Alignment); - - if (splitterDestinations.IsEmpty) - { - return false; - } - - int splitterDestinationId = 0; - foreach (ref SplitterDestination data in splitterDestinations.Span) - { - data = new SplitterDestination(splitterDestinationId++); - } - - SplitterState.InitializeSplitters(splitters.Span); - - Setup(splitters, splitterDestinations, behaviourContext.IsSplitterBugFixed()); - - return true; - } - - /// <summary> - /// Get the work buffer size while adding the size needed for splitter to operate. - /// </summary> - /// <param name="size">The current size.</param> - /// <param name="behaviourContext">The behaviour context.</param> - /// <param name="parameter">The renderer configuration.</param> - /// <returns>Return the new size taking splitter into account.</returns> - public static ulong GetWorkBufferSize(ulong size, ref BehaviourContext behaviourContext, ref AudioRendererConfiguration parameter) - { - if (behaviourContext.IsSplitterSupported()) - { - size = WorkBufferAllocator.GetTargetSize<SplitterState>(size, parameter.SplitterCount, SplitterState.Alignment); - size = WorkBufferAllocator.GetTargetSize<SplitterDestination>(size, parameter.SplitterDestinationCount, SplitterDestination.Alignment); - - if (behaviourContext.IsSplitterBugFixed()) - { - size = WorkBufferAllocator.GetTargetSize<int>(size, parameter.SplitterDestinationCount, 0x10); - } - - return size; - } - else - { - return size; - } - } - - /// <summary> - /// Setup the <see cref="SplitterContext"/> instance. - /// </summary> - /// <param name="splitters">The <see cref="SplitterState"/> storage.</param> - /// <param name="splitterDestinations">The <see cref="SplitterDestination"/> storage.</param> - /// <param name="isBugFixed">If set to true, trust the user destination count in <see cref="SplitterState.Update(SplitterContext, ref SplitterInParameter, ReadOnlySpan{byte})"/>.</param> - private void Setup(Memory<SplitterState> splitters, Memory<SplitterDestination> splitterDestinations, bool isBugFixed) - { - _splitters = splitters; - _splitterDestinations = splitterDestinations; - IsBugFixed = isBugFixed; - } - - /// <summary> - /// Clear the new connection flag. - /// </summary> - private void ClearAllNewConnectionFlag() - { - foreach (ref SplitterState splitter in _splitters.Span) - { - splitter.ClearNewConnectionFlag(); - } - } - - /// <summary> - /// Get the destination count using the count of splitter. - /// </summary> - /// <returns>The destination count using the count of splitter.</returns> - public int GetDestinationCountPerStateForCompatibility() - { - if (_splitters.IsEmpty) - { - return 0; - } - - return _splitterDestinations.Length / _splitters.Length; - } - - /// <summary> - /// Update one or multiple <see cref="SplitterState"/> from user parameters. - /// </summary> - /// <param name="inputHeader">The splitter header.</param> - /// <param name="input">The raw data after the splitter header.</param> - private void UpdateState(ref SplitterInParameterHeader inputHeader, ref ReadOnlySpan<byte> input) - { - for (int i = 0; i < inputHeader.SplitterCount; i++) - { - SplitterInParameter parameter = MemoryMarshal.Read<SplitterInParameter>(input); - - Debug.Assert(parameter.IsMagicValid()); - - if (parameter.IsMagicValid()) - { - if (parameter.Id >= 0 && parameter.Id < _splitters.Length) - { - ref SplitterState splitter = ref GetState(parameter.Id); - - splitter.Update(this, ref parameter, input.Slice(Unsafe.SizeOf<SplitterInParameter>())); - } - - input = input.Slice(0x1C + (int)parameter.DestinationCount * 4); - } - } - } - - /// <summary> - /// Update one or multiple <see cref="SplitterDestination"/> from user parameters. - /// </summary> - /// <param name="inputHeader">The splitter header.</param> - /// <param name="input">The raw data after the splitter header.</param> - private void UpdateData(ref SplitterInParameterHeader inputHeader, ref ReadOnlySpan<byte> input) - { - for (int i = 0; i < inputHeader.SplitterDestinationCount; i++) - { - SplitterDestinationInParameter parameter = MemoryMarshal.Read<SplitterDestinationInParameter>(input); - - Debug.Assert(parameter.IsMagicValid()); - - if (parameter.IsMagicValid()) - { - if (parameter.Id >= 0 && parameter.Id < _splitterDestinations.Length) - { - ref SplitterDestination destination = ref GetDestination(parameter.Id); - - destination.Update(parameter); - } - - input = input.Slice(Unsafe.SizeOf<SplitterDestinationInParameter>()); - } - } - } - - /// <summary> - /// Update splitter from user parameters. - /// </summary> - /// <param name="input">The input raw user data.</param> - /// <param name="consumedSize">The total consumed size.</param> - /// <returns>Return true if the update was successful.</returns> - public bool Update(ReadOnlySpan<byte> input, out int consumedSize) - { - if (_splitterDestinations.IsEmpty || _splitters.IsEmpty) - { - consumedSize = 0; - - return true; - } - - int originalSize = input.Length; - - SplitterInParameterHeader header = SpanIOHelper.Read<SplitterInParameterHeader>(ref input); - - if (header.IsMagicValid()) - { - ClearAllNewConnectionFlag(); - - UpdateState(ref header, ref input); - UpdateData(ref header, ref input); - - consumedSize = BitUtils.AlignUp(originalSize - input.Length, 0x10); - - return true; - } - else - { - consumedSize = 0; - - return false; - } - } - - /// <summary> - /// Get a reference to a <see cref="SplitterState"/> at the given <paramref name="id"/>. - /// </summary> - /// <param name="id">The index to use.</param> - /// <returns>A reference to a <see cref="SplitterState"/> at the given <paramref name="id"/>.</returns> - public ref SplitterState GetState(int id) - { - return ref SpanIOHelper.GetFromMemory(_splitters, id, (uint)_splitters.Length); - } - - /// <summary> - /// Get a reference to a <see cref="SplitterDestination"/> at the given <paramref name="id"/>. - /// </summary> - /// <param name="id">The index to use.</param> - /// <returns>A reference to a <see cref="SplitterDestination"/> at the given <paramref name="id"/>.</returns> - public ref SplitterDestination GetDestination(int id) - { - return ref SpanIOHelper.GetFromMemory(_splitterDestinations, id, (uint)_splitterDestinations.Length); - } - - /// <summary> - /// Get a <see cref="Memory{SplitterDestination}"/> at the given <paramref name="id"/>. - /// </summary> - /// <param name="id">The index to use.</param> - /// <returns>A <see cref="Memory{SplitterDestination}"/> at the given <paramref name="id"/>.</returns> - public Memory<SplitterDestination> GetDestinationMemory(int id) - { - return SpanIOHelper.GetMemory(_splitterDestinations, id, (uint)_splitterDestinations.Length); - } - - /// <summary> - /// Get a <see cref="Span{SplitterDestination}"/> in the <see cref="SplitterState"/> at <paramref name="id"/> and pass <paramref name="destinationId"/> to <see cref="SplitterState.GetData(int)"/>. - /// </summary> - /// <param name="id">The index to use to get the <see cref="SplitterState"/>.</param> - /// <param name="destinationId">The index of the <see cref="SplitterDestination"/>.</param> - /// <returns>A <see cref="Span{SplitterDestination}"/>.</returns> - public Span<SplitterDestination> GetDestination(int id, int destinationId) - { - ref SplitterState splitter = ref GetState(id); - - return splitter.GetData(destinationId); - } - - /// <summary> - /// Return true if the audio renderer has any splitters. - /// </summary> - /// <returns>True if the audio renderer has any splitters.</returns> - public bool UsingSplitter() - { - return !_splitters.IsEmpty && !_splitterDestinations.IsEmpty; - } - - /// <summary> - /// Update the internal state of all splitters. - /// </summary> - public void UpdateInternalState() - { - foreach (ref SplitterState splitter in _splitters.Span) - { - splitter.UpdateInternalState(); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterDestination.cs b/Ryujinx.Audio.Renderer/Server/Splitter/SplitterDestination.cs deleted file mode 100644 index 6d273e45..00000000 --- a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterDestination.cs +++ /dev/null @@ -1,210 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Common.Utilities; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -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 const int Alignment = 0x10; - - /// <summary> - /// The unique id of this <see cref="SplitterDestination"/>. - /// </summary> - public int Id; - - /// <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. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool IsUsed; - - /// <summary> - /// Set to true if the internal state need to be updated. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool NeedToUpdateInternalState; - - [StructLayout(LayoutKind.Sequential, Size = 4 * RendererConstants.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 _mix); - - /// <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); - - /// <summary> - /// Get the <see cref="Span{SplitterDestination}"/> of the next element or <see cref="Span{SplitterDestination}.Empty"/> if not present. - /// </summary> - public Span<SplitterDestination> Next - { - get - { - unsafe - { - return _next != null ? new Span<SplitterDestination>(_next, 1) : Span<SplitterDestination>.Empty; - } - } - } - - /// <summary> - /// Create a new <see cref="SplitterDestination"/>. - /// </summary> - /// <param name="id">The unique id of this <see cref="SplitterDestination"/>.</param> - public SplitterDestination(int id) : this() - { - Id = id; - DestinationId = RendererConstants.UnusedMixId; - - ClearVolumes(); - } - - /// <summary> - /// Update the <see cref="SplitterDestination"/> from user parameter. - /// </summary> - /// <param name="parameter">The user parameter.</param> - public void Update(SplitterDestinationInParameter parameter) - { - 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); - - NeedToUpdateInternalState = false; - } - - IsUsed = parameter.IsUsed; - } - } - - /// <summary> - /// Update the internal state of the instance. - /// </summary> - public void UpdateInternalState() - { - if (IsUsed && NeedToUpdateInternalState) - { - MixBufferVolume.CopyTo(PreviousMixBufferVolume); - } - - NeedToUpdateInternalState = false; - } - - /// <summary> - /// Set the update internal state marker. - /// </summary> - public void MarkAsNeedToUpdateInternalState() - { - NeedToUpdateInternalState = true; - } - - /// <summary> - /// Return true if the <see cref="SplitterDestination"/> is used and has a destination. - /// </summary> - /// <returns>True if the <see cref="SplitterDestination"/> is used and has a destination.</returns> - public bool IsConfigured() - { - return IsUsed && DestinationId != RendererConstants.UnusedMixId; - } - - /// <summary> - /// Get the 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 GetMixVolume(int destinationIndex) - { - Debug.Assert(destinationIndex >= 0 && destinationIndex < RendererConstants.MixBufferCountMax); - - return MixBufferVolume[destinationIndex]; - } - - /// <summary> - /// Clear the volumes. - /// </summary> - public void ClearVolumes() - { - MixBufferVolume.Fill(0); - PreviousMixBufferVolume.Fill(0); - } - - /// <summary> - /// Link the next element to the given <see cref="SplitterDestination"/>. - /// </summary> - /// <param name="next">The given <see cref="SplitterDestination"/> to link.</param> - public void Link(ref SplitterDestination next) - { - unsafe - { - fixed (SplitterDestination *nextPtr = &next) - { - _next = nextPtr; - } - } - } - - /// <summary> - /// Remove the link to the next element. - /// </summary> - public void Unlink() - { - unsafe - { - _next = null; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterState.cs b/Ryujinx.Audio.Renderer/Server/Splitter/SplitterState.cs deleted file mode 100644 index c928ec53..00000000 --- a/Ryujinx.Audio.Renderer/Server/Splitter/SplitterState.cs +++ /dev/null @@ -1,237 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// -using Ryujinx.Audio.Renderer.Parameter; -using System; -using System.Buffers; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Splitter -{ - /// <summary> - /// Server state for a splitter. - /// </summary> - [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = Alignment)] - public struct SplitterState - { - public const int Alignment = 0x10; - - /// <summary> - /// The unique id of this <see cref="SplitterState"/>. - /// </summary> - public int Id; - - /// <summary> - /// Target sample rate to use on the splitter. - /// </summary> - public uint SampleRate; - - /// <summary> - /// Count of splitter destinations (<see cref="SplitterDestination"/>). - /// </summary> - public int DestinationCount; - - /// <summary> - /// Set to true if the splitter has a new connection. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool HasNewConnection; - - /// <summary> - /// Linked list of <see cref="SplitterDestination"/>. - /// </summary> - private unsafe SplitterDestination* _destinationsData; - - /// <summary> - /// Span to the first element of the linked list of <see cref="SplitterDestination"/>. - /// </summary> - public Span<SplitterDestination> Destinations - { - get - { - unsafe - { - return (IntPtr)_destinationsData != IntPtr.Zero ? new Span<SplitterDestination>(_destinationsData, 1) : Span<SplitterDestination>.Empty; - } - } - } - - /// <summary> - /// Create a new <see cref="SplitterState"/>. - /// </summary> - /// <param name="id">The unique id of this <see cref="SplitterState"/>.</param> - public SplitterState(int id) : this() - { - Id = id; - } - - public Span<SplitterDestination> GetData(int index) - { - int i = 0; - - Span<SplitterDestination> result = Destinations; - - while (i < index) - { - if (result.IsEmpty) - { - break; - } - - result = result[0].Next; - i++; - } - - return result; - } - - /// <summary> - /// Clear the new connection flag. - /// </summary> - public void ClearNewConnectionFlag() - { - HasNewConnection = false; - } - - /// <summary> - /// Utility function to apply a given <see cref="SpanAction{T, TArg}"/> to all <see cref="Destinations"/>. - /// </summary> - /// <param name="action">The action to execute on each elements.</param> - private void ForEachDestination(SpanAction<SplitterDestination, int> action) - { - Span<SplitterDestination> temp = Destinations; - - int i = 0; - - while (true) - { - if (temp.IsEmpty) - { - break; - } - - Span<SplitterDestination> next = temp[0].Next; - - action.Invoke(temp, i++); - - temp = next; - } - } - - /// <summary> - /// Update the <see cref="SplitterState"/> from user parameter. - /// </summary> - /// <param name="context">The splitter context.</param> - /// <param name="parameter">The user parameter.</param> - /// <param name="input">The raw input data after the <paramref name="parameter"/>.</param> - public void Update(SplitterContext context, ref SplitterInParameter parameter, ReadOnlySpan<byte> input) - { - ClearLinks(); - - int destinationCount; - - if (context.IsBugFixed) - { - destinationCount = parameter.DestinationCount; - } - else - { - destinationCount = Math.Min(context.GetDestinationCountPerStateForCompatibility(), parameter.DestinationCount); - } - - if (destinationCount > 0) - { - ReadOnlySpan<int> destinationIds = MemoryMarshal.Cast<byte, int>(input); - - Memory<SplitterDestination> destination = context.GetDestinationMemory(destinationIds[0]); - - SetDestination(ref destination.Span[0]); - - DestinationCount = destinationCount; - - for (int i = 1; i < destinationCount; i++) - { - Memory<SplitterDestination> nextDestination = context.GetDestinationMemory(destinationIds[i]); - - destination.Span[0].Link(ref nextDestination.Span[0]); - destination = nextDestination; - } - } - - Debug.Assert(parameter.Id == Id); - - if (parameter.Id == Id) - { - SampleRate = parameter.SampleRate; - HasNewConnection = true; - } - } - - /// <summary> - /// Set the head of the linked list of <see cref="Destinations"/>. - /// </summary> - /// <param name="newValue">A reference to a <see cref="SplitterDestination"/>.</param> - public void SetDestination(ref SplitterDestination newValue) - { - unsafe - { - fixed (SplitterDestination* newValuePtr = &newValue) - { - _destinationsData = newValuePtr; - } - } - } - - /// <summary> - /// Update the internal state of this instance. - /// </summary> - public void UpdateInternalState() - { - ForEachDestination((destination, _) => destination[0].UpdateInternalState()); - } - - /// <summary> - /// Clear all links from the <see cref="Destinations"/>. - /// </summary> - public void ClearLinks() - { - ForEachDestination((destination, _) => destination[0].Unlink()); - - unsafe - { - _destinationsData = (SplitterDestination*)IntPtr.Zero; - } - } - - /// <summary> - /// Initialize a given <see cref="Span{SplitterState}"/>. - /// </summary> - /// <param name="splitters">All the <see cref="SplitterState"/> to initialize.</param> - public static void InitializeSplitters(Span<SplitterState> splitters) - { - foreach (ref SplitterState splitter in splitters) - { - unsafe - { - splitter._destinationsData = (SplitterDestination*)IntPtr.Zero; - } - - splitter.DestinationCount = 0; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/StateUpdater.cs b/Ryujinx.Audio.Renderer/Server/StateUpdater.cs deleted file mode 100644 index b26e2721..00000000 --- a/Ryujinx.Audio.Renderer/Server/StateUpdater.cs +++ /dev/null @@ -1,575 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Performance; -using Ryujinx.Audio.Renderer.Server.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using Ryujinx.Audio.Renderer.Server.Mix; -using Ryujinx.Audio.Renderer.Server.Performance; -using Ryujinx.Audio.Renderer.Server.Sink; -using Ryujinx.Audio.Renderer.Server.Splitter; -using Ryujinx.Audio.Renderer.Server.Voice; -using Ryujinx.Audio.Renderer.Utils; -using Ryujinx.Common.Logging; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; - -namespace Ryujinx.Audio.Renderer.Server -{ - public class StateUpdater - { - private readonly ReadOnlyMemory<byte> _inputOrigin; - private ReadOnlyMemory <byte> _outputOrigin; - private ReadOnlyMemory<byte> _input; - - private Memory<byte> _output; - private uint _processHandle; - private BehaviourContext _behaviourContext; - - private UpdateDataHeader _inputHeader; - private Memory<UpdateDataHeader> _outputHeader; - - private ref UpdateDataHeader OutputHeader => ref _outputHeader.Span[0]; - - public StateUpdater(ReadOnlyMemory<byte> input, Memory<byte> output, uint processHandle, BehaviourContext behaviourContext) - { - _input = input; - _inputOrigin = _input; - _output = output; - _outputOrigin = _output; - _processHandle = processHandle; - _behaviourContext = behaviourContext; - - _inputHeader = SpanIOHelper.Read<UpdateDataHeader>(ref _input); - - _outputHeader = SpanMemoryManager<UpdateDataHeader>.Cast(_output.Slice(0, Unsafe.SizeOf<UpdateDataHeader>())); - OutputHeader.Initialize(_behaviourContext.UserRevision); - _output = _output.Slice(Unsafe.SizeOf<UpdateDataHeader>()); - } - - public ResultCode UpdateBehaviourContext() - { - BehaviourParameter parameter = SpanIOHelper.Read<BehaviourParameter>(ref _input); - - if (!BehaviourContext.CheckValidRevision(parameter.UserRevision) || parameter.UserRevision != _behaviourContext.UserRevision) - { - return ResultCode.InvalidUpdateInfo; - } - - _behaviourContext.ClearError(); - _behaviourContext.UpdateFlags(parameter.Flags); - - if (_inputHeader.BehaviourSize != Unsafe.SizeOf<BehaviourParameter>()) - { - return ResultCode.InvalidUpdateInfo; - } - - return ResultCode.Success; - } - - public ResultCode UpdateMemoryPools(Span<MemoryPoolState> memoryPools) - { - PoolMapper mapper = new PoolMapper(_processHandle, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - if (memoryPools.Length * Unsafe.SizeOf<MemoryPoolInParameter>() != _inputHeader.MemoryPoolsSize) - { - return ResultCode.InvalidUpdateInfo; - } - - foreach (ref MemoryPoolState memoryPool in memoryPools) - { - MemoryPoolInParameter parameter = SpanIOHelper.Read<MemoryPoolInParameter>(ref _input); - - ref MemoryPoolOutStatus outStatus = ref SpanIOHelper.GetWriteRef<MemoryPoolOutStatus>(ref _output)[0]; - - PoolMapper.UpdateResult updateResult = mapper.Update(ref memoryPool, ref parameter, ref outStatus); - - if (updateResult != PoolMapper.UpdateResult.Success && - updateResult != PoolMapper.UpdateResult.MapError && - updateResult != PoolMapper.UpdateResult.UnmapError) - { - if (updateResult != PoolMapper.UpdateResult.InvalidParameter) - { - throw new InvalidOperationException($"{updateResult}"); - } - - return ResultCode.InvalidUpdateInfo; - } - } - - OutputHeader.MemoryPoolsSize = (uint)(Unsafe.SizeOf<MemoryPoolOutStatus>() * memoryPools.Length); - OutputHeader.TotalSize += OutputHeader.MemoryPoolsSize; - - return ResultCode.Success; - } - - public ResultCode UpdateVoiceChannelResources(VoiceContext context) - { - if (context.GetCount() * Unsafe.SizeOf<VoiceChannelResourceInParameter>() != _inputHeader.VoiceResourcesSize) - { - return ResultCode.InvalidUpdateInfo; - } - - for (int i = 0; i < context.GetCount(); i++) - { - VoiceChannelResourceInParameter parameter = SpanIOHelper.Read<VoiceChannelResourceInParameter>(ref _input); - - ref VoiceChannelResource resource = ref context.GetChannelResource(i); - - resource.Id = parameter.Id; - parameter.Mix.ToSpan().CopyTo(resource.Mix.ToSpan()); - resource.IsUsed = parameter.IsUsed; - } - - return ResultCode.Success; - } - - public ResultCode UpdateVoices(VoiceContext context, Memory<MemoryPoolState> memoryPools) - { - if (context.GetCount() * Unsafe.SizeOf<VoiceInParameter>() != _inputHeader.VoicesSize) - { - return ResultCode.InvalidUpdateInfo; - } - - int initialOutputSize = _output.Length; - - ReadOnlySpan<VoiceInParameter> parameters = MemoryMarshal.Cast<byte, VoiceInParameter>(_input.Slice(0, (int)_inputHeader.VoicesSize).Span); - - _input = _input.Slice((int)_inputHeader.VoicesSize); - - PoolMapper mapper = new PoolMapper(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - // First make everything not in use. - for (int i = 0; i < context.GetCount(); i++) - { - ref VoiceState state = ref context.GetState(i); - - state.InUse = false; - } - - // Start processing - for (int i = 0; i < context.GetCount(); i++) - { - VoiceInParameter parameter = parameters[i]; - - Memory<VoiceUpdateState>[] voiceUpdateStates = new Memory<VoiceUpdateState>[RendererConstants.VoiceChannelCountMax]; - - ref VoiceOutStatus outStatus = ref SpanIOHelper.GetWriteRef<VoiceOutStatus>(ref _output)[0]; - - if (parameter.InUse) - { - ref VoiceState currentVoiceState = ref context.GetState(i); - - for (int channelResourceIndex = 0; channelResourceIndex < parameter.ChannelCount; channelResourceIndex++) - { - int channelId = parameter.ChannelResourceIds[channelResourceIndex]; - - Debug.Assert(channelId >= 0 && channelId < context.GetCount()); - - voiceUpdateStates[channelResourceIndex] = context.GetUpdateStateForCpu(channelId); - } - - if (parameter.IsNew) - { - currentVoiceState.Initialize(); - } - - currentVoiceState.UpdateParameters(out ErrorInfo updateParameterError, ref parameter, ref mapper, ref _behaviourContext); - - if (updateParameterError.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref updateParameterError); - } - - currentVoiceState.UpdateWaveBuffers(out ErrorInfo[] waveBufferUpdateErrorInfos, ref parameter, voiceUpdateStates, ref mapper, ref _behaviourContext); - - foreach (ref ErrorInfo errorInfo in waveBufferUpdateErrorInfos.AsSpan()) - { - if (errorInfo.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref errorInfo); - } - } - - currentVoiceState.WriteOutStatus(ref outStatus, ref parameter, voiceUpdateStates); - } - } - - int currentOutputSize = _output.Length; - - OutputHeader.VoicesSize = (uint)(Unsafe.SizeOf<VoiceOutStatus>() * context.GetCount()); - OutputHeader.TotalSize += OutputHeader.VoicesSize; - - Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.VoicesSize); - - return ResultCode.Success; - } - - private static void ResetEffect(ref BaseEffect effect, ref EffectInParameter parameter, PoolMapper mapper) - { - effect.ForceUnmapBuffers(mapper); - - switch (parameter.Type) - { - case EffectType.Invalid: - effect = new BaseEffect(); - break; - case EffectType.BufferMix: - effect = new BufferMixEffect(); - break; - case EffectType.AuxiliaryBuffer: - effect = new AuxiliaryBufferEffect(); - break; - case EffectType.Delay: - effect = new DelayEffect(); - break; - case EffectType.Reverb: - effect = new ReverbEffect(); - break; - case EffectType.Reverb3d: - effect = new Reverb3dEffect(); - break; - case EffectType.BiquadFilter: - effect = new BiquadFilterEffect(); - break; - default: - throw new NotImplementedException($"EffectType {parameter.Type} not implemented!"); - } - } - - public ResultCode UpdateEffects(EffectContext context, bool isAudioRendererActive, Memory<MemoryPoolState> memoryPools) - { - if (context.GetCount() * Unsafe.SizeOf<EffectInParameter>() != _inputHeader.EffectsSize) - { - return ResultCode.InvalidUpdateInfo; - } - - int initialOutputSize = _output.Length; - - ReadOnlySpan<EffectInParameter> parameters = MemoryMarshal.Cast<byte, EffectInParameter>(_input.Slice(0, (int)_inputHeader.EffectsSize).Span); - - _input = _input.Slice((int)_inputHeader.EffectsSize); - - PoolMapper mapper = new PoolMapper(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - for (int i = 0; i < context.GetCount(); i++) - { - EffectInParameter parameter = parameters[i]; - - ref EffectOutStatus outStatus = ref SpanIOHelper.GetWriteRef<EffectOutStatus>(ref _output)[0]; - - ref BaseEffect effect = ref context.GetEffect(i); - - if (!effect.IsTypeValid(ref parameter)) - { - ResetEffect(ref effect, ref parameter, mapper); - } - - effect.Update(out ErrorInfo updateErrorInfo, ref parameter, mapper); - - if (updateErrorInfo.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref updateErrorInfo); - } - - effect.StoreStatus(ref outStatus, isAudioRendererActive); - } - - int currentOutputSize = _output.Length; - - OutputHeader.EffectsSize = (uint)(Unsafe.SizeOf<EffectOutStatus>() * context.GetCount()); - OutputHeader.TotalSize += OutputHeader.EffectsSize; - - Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.EffectsSize); - - return ResultCode.Success; - } - - public ResultCode UpdateSplitter(SplitterContext context) - { - if (context.Update(_input.Span, out int consumedSize)) - { - _input = _input.Slice(consumedSize); - - return ResultCode.Success; - } - else - { - return ResultCode.InvalidUpdateInfo; - } - } - - private bool CheckMixParametersValidity(MixContext mixContext, uint mixBufferCount, uint inputMixCount, ReadOnlySpan<MixParameter> parameters) - { - uint maxMixStateCount = mixContext.GetCount(); - uint totalRequiredMixBufferCount = 0; - - for (int i = 0; i < inputMixCount; i++) - { - if (parameters[i].IsUsed) - { - if (parameters[i].DestinationMixId != RendererConstants.UnusedMixId && - parameters[i].DestinationMixId > maxMixStateCount && - parameters[i].MixId != RendererConstants.FinalMixId) - { - return true; - } - - totalRequiredMixBufferCount += parameters[i].BufferCount; - } - } - - return totalRequiredMixBufferCount > mixBufferCount; - } - - public ResultCode UpdateMixes(MixContext mixContext, uint mixBufferCount, EffectContext effectContext, SplitterContext splitterContext) - { - uint mixCount; - uint inputMixSize; - uint inputSize = 0; - - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) - { - MixInParameterDirtyOnlyUpdate parameter = MemoryMarshal.Cast<byte, MixInParameterDirtyOnlyUpdate>(_input.Span)[0]; - - mixCount = parameter.MixCount; - - inputSize += (uint)Unsafe.SizeOf<MixInParameterDirtyOnlyUpdate>(); - } - else - { - mixCount = mixContext.GetCount(); - } - - inputMixSize = mixCount * (uint)Unsafe.SizeOf<MixParameter>(); - - inputSize += inputMixSize; - - if (inputSize != _inputHeader.MixesSize) - { - return ResultCode.InvalidUpdateInfo; - } - - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) - { - _input = _input.Slice(Unsafe.SizeOf<MixInParameterDirtyOnlyUpdate>()); - } - - ReadOnlySpan<MixParameter> parameters = MemoryMarshal.Cast<byte, MixParameter>(_input.Span.Slice(0, (int)inputMixSize)); - - _input = _input.Slice((int)inputMixSize); - - if (CheckMixParametersValidity(mixContext, mixBufferCount, mixCount, parameters)) - { - return ResultCode.InvalidUpdateInfo; - } - - bool isMixContextDirty = false; - - for (int i = 0; i < parameters.Length; i++) - { - MixParameter parameter = parameters[i]; - - int mixId = i; - - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) - { - mixId = parameter.MixId; - } - - ref MixState mix = ref mixContext.GetState(mixId); - - if (parameter.IsUsed != mix.IsUsed) - { - mix.IsUsed = parameter.IsUsed; - - if (parameter.IsUsed) - { - mix.ClearEffectProcessingOrder(); - } - - isMixContextDirty = true; - } - - if (mix.IsUsed) - { - isMixContextDirty |= mix.Update(mixContext.EdgeMatrix, ref parameter, effectContext, splitterContext, _behaviourContext); - } - } - - if (isMixContextDirty) - { - if (_behaviourContext.IsSplitterSupported() && splitterContext.UsingSplitter()) - { - if (!mixContext.Sort(splitterContext)) - { - return ResultCode.InvalidMixSorting; - } - } - else - { - mixContext.Sort(); - } - } - - return ResultCode.Success; - } - - private static void ResetSink(ref BaseSink sink, ref SinkInParameter parameter) - { - sink.CleanUp(); - - switch (parameter.Type) - { - case SinkType.Invalid: - sink = new BaseSink(); - break; - case SinkType.CircularBuffer: - sink = new CircularBufferSink(); - break; - case SinkType.Device: - sink = new DeviceSink(); - break; - default: - throw new NotImplementedException($"SinkType {parameter.Type} not implemented!"); - } - } - - public ResultCode UpdateSinks(SinkContext context, Memory<MemoryPoolState> memoryPools) - { - PoolMapper mapper = new PoolMapper(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - if (context.GetCount() * Unsafe.SizeOf<SinkInParameter>() != _inputHeader.SinksSize) - { - return ResultCode.InvalidUpdateInfo; - } - - int initialOutputSize = _output.Length; - - ReadOnlySpan<SinkInParameter> parameters = MemoryMarshal.Cast<byte, SinkInParameter>(_input.Slice(0, (int)_inputHeader.SinksSize).Span); - - _input = _input.Slice((int)_inputHeader.SinksSize); - - for (int i = 0; i < context.GetCount(); i++) - { - SinkInParameter parameter = parameters[i]; - ref SinkOutStatus outStatus = ref SpanIOHelper.GetWriteRef<SinkOutStatus>(ref _output)[0]; - ref BaseSink sink = ref context.GetSink(i); - - if (!sink.IsTypeValid(ref parameter)) - { - ResetSink(ref sink, ref parameter); - } - - sink.Update(out ErrorInfo updateErrorInfo, ref parameter, ref outStatus, mapper); - - if (updateErrorInfo.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref updateErrorInfo); - } - } - - int currentOutputSize = _output.Length; - - OutputHeader.SinksSize = (uint)(Unsafe.SizeOf<SinkOutStatus>() * context.GetCount()); - OutputHeader.TotalSize += OutputHeader.SinksSize; - - Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.SinksSize); - - return ResultCode.Success; - } - - public ResultCode UpdatePerformanceBuffer(PerformanceManager manager, Span<byte> performanceOutput) - { - if (Unsafe.SizeOf<PerformanceInParameter>() != _inputHeader.PerformanceBufferSize) - { - return ResultCode.InvalidUpdateInfo; - } - - PerformanceInParameter parameter = SpanIOHelper.Read<PerformanceInParameter>(ref _input); - - ref PerformanceOutStatus outStatus = ref SpanIOHelper.GetWriteRef<PerformanceOutStatus>(ref _output)[0]; - - if (manager != null) - { - outStatus.HistorySize = manager.CopyHistories(performanceOutput); - - manager.SetTargetNodeId(parameter.TargetNodeId); - } - else - { - outStatus.HistorySize = 0; - } - - OutputHeader.PerformanceBufferSize = (uint)Unsafe.SizeOf<PerformanceOutStatus>(); - OutputHeader.TotalSize += OutputHeader.PerformanceBufferSize; - - return ResultCode.Success; - } - - public ResultCode UpdateErrorInfo() - { - ref BehaviourErrorInfoOutStatus outStatus = ref SpanIOHelper.GetWriteRef<BehaviourErrorInfoOutStatus>(ref _output)[0]; - - _behaviourContext.CopyErrorInfo(outStatus.ErrorInfos.ToSpan(), out outStatus.ErrorInfosCount); - - OutputHeader.BehaviourSize = (uint)Unsafe.SizeOf<BehaviourErrorInfoOutStatus>(); - OutputHeader.TotalSize += OutputHeader.BehaviourSize; - - return ResultCode.Success; - } - - public ResultCode UpdateRendererInfo(ulong elapsedFrameCount) - { - ref RendererInfoOutStatus outStatus = ref SpanIOHelper.GetWriteRef<RendererInfoOutStatus>(ref _output)[0]; - - outStatus.ElapsedFrameCount = elapsedFrameCount; - - OutputHeader.RenderInfoSize = (uint)Unsafe.SizeOf<RendererInfoOutStatus>(); - OutputHeader.TotalSize += OutputHeader.RenderInfoSize; - - return ResultCode.Success; - } - - public ResultCode CheckConsumedSize() - { - int consumedInputSize = _inputOrigin.Length - _input.Length; - int consumedOutputSize = _outputOrigin.Length - _output.Length; - - if (consumedInputSize != _inputHeader.TotalSize) - { - Logger.Error?.Print(LogClass.AudioRenderer, $"Consumed input size mismatch (got {consumedInputSize} expected {_inputHeader.TotalSize})"); - - return ResultCode.InvalidUpdateInfo; - } - - if (consumedOutputSize != OutputHeader.TotalSize) - { - Logger.Error?.Print(LogClass.AudioRenderer, $"Consumed output size mismatch (got {consumedOutputSize} expected {OutputHeader.TotalSize})"); - - return ResultCode.InvalidUpdateInfo; - } - - return ResultCode.Success; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Types/AudioRendererExecutionMode.cs b/Ryujinx.Audio.Renderer/Server/Types/AudioRendererExecutionMode.cs deleted file mode 100644 index 7bb0507c..00000000 --- a/Ryujinx.Audio.Renderer/Server/Types/AudioRendererExecutionMode.cs +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Server.Types -{ - /// <summary> - /// The execution mode of an <see cref="AudioRenderSystem"/>. - /// </summary> - public enum AudioRendererExecutionMode : byte - { - /// <summary> - /// Automatically send commands to the DSP at a fixed rate (see <see cref="AudioRenderSystem.SendCommands"/> - /// </summary> - Auto, - - /// <summary> - /// Audio renderer operation needs to be done manually via ExecuteAudioRenderer. - /// </summary> - /// <remarks>This is not supported on the DSP and is as such stubbed.</remarks> - Manual - } -}
\ No newline at end of file diff --git a/Ryujinx.Audio.Renderer/Server/Types/AudioRendererRenderingDevice.cs b/Ryujinx.Audio.Renderer/Server/Types/AudioRendererRenderingDevice.cs deleted file mode 100644 index f89086f6..00000000 --- a/Ryujinx.Audio.Renderer/Server/Types/AudioRendererRenderingDevice.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Server.Types -{ - /// <summary> - /// The rendering device of an <see cref="AudioRenderSystem"/>. - /// </summary> - public enum AudioRendererRenderingDevice : byte - { - /// <summary> - /// Rendering is performed on the DSP. - /// </summary> - /// <remarks> - /// Only supports <see cref="AudioRendererExecutionMode.Auto"/>. - /// </remarks> - Dsp, - - /// <summary> - /// Rendering is performed on the CPU. - /// </summary> - /// <remarks> - /// Only supports <see cref="AudioRendererExecutionMode.Manual"/>. - /// </remarks> - Cpu - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Types/PlayState.cs b/Ryujinx.Audio.Renderer/Server/Types/PlayState.cs deleted file mode 100644 index 7f8895c9..00000000 --- a/Ryujinx.Audio.Renderer/Server/Types/PlayState.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -namespace Ryujinx.Audio.Renderer.Server.Types -{ - /// <summary> - /// The internal play state of a <see cref="Voice.VoiceState"/> - /// </summary> - public enum PlayState - { - /// <summary> - /// The voice has been started and is playing. - /// </summary> - Started, - - /// <summary> - /// The voice has been stopped. - /// </summary> - /// <remarks> - /// This cannot be directly set by user. - /// See <see cref="Stopping"/> for correct usage. - /// </remarks> - Stopped, - - /// <summary> - /// The user asked the voice to be stopped. - /// </summary> - /// <remarks> - /// This is changed to the <see cref="Stopped"/> state after command generation. - /// <seealso cref="Voice.VoiceState.UpdateForCommandGeneration(Voice.VoiceContext)"/> - /// </remarks> - Stopping, - - /// <summary> - /// The voice has been paused by user request. - /// </summary> - /// <remarks> - /// The user can resume to the <see cref="Started"/> state. - /// </remarks> - Paused - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerManager.cs b/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerManager.cs deleted file mode 100644 index fd396d9f..00000000 --- a/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerManager.cs +++ /dev/null @@ -1,101 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server.Upsampler -{ - /// <summary> - /// Upsampler manager. - /// </summary> - public class UpsamplerManager - { - /// <summary> - /// Work buffer for upsampler. - /// </summary> - private Memory<float> _upSamplerWorkBuffer; - - /// <summary> - /// Global lock of the object. - /// </summary> - private object Lock = new object(); - - /// <summary> - /// The upsamplers instances. - /// </summary> - private UpsamplerState[] _upsamplers; - - /// <summary> - /// The count of upsamplers. - /// </summary> - private uint _count; - - /// <summary> - /// Create a new <see cref="UpsamplerManager"/>. - /// </summary> - /// <param name="upSamplerWorkBuffer">Work buffer for upsampler.</param> - /// <param name="count">The count of upsamplers.</param> - public UpsamplerManager(Memory<float> upSamplerWorkBuffer, uint count) - { - _upSamplerWorkBuffer = upSamplerWorkBuffer; - _count = count; - - _upsamplers = new UpsamplerState[_count]; - } - - /// <summary> - /// Allocate a new <see cref="UpsamplerState"/>. - /// </summary> - /// <returns>A new <see cref="UpsamplerState"/> or null if out of memory.</returns> - public UpsamplerState Allocate() - { - int workBufferOffset = 0; - - lock (Lock) - { - for (int i = 0; i < _count; i++) - { - if (_upsamplers[i] == null) - { - _upsamplers[i] = new UpsamplerState(this, i, _upSamplerWorkBuffer.Slice(workBufferOffset, RendererConstants.UpSampleEntrySize), RendererConstants.TargetSampleCount); - - return _upsamplers[i]; - } - - workBufferOffset += RendererConstants.UpSampleEntrySize; - } - } - - return null; - } - - /// <summary> - /// Free a <see cref="UpsamplerState"/> at the given index. - /// </summary> - /// <param name="index">The index of the <see cref="UpsamplerState"/> to free.</param> - public void Free(int index) - { - lock (Lock) - { - Debug.Assert(_upsamplers[index] != null); - - _upsamplers[index] = null; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerState.cs b/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerState.cs deleted file mode 100644 index 8ea55384..00000000 --- a/Ryujinx.Audio.Renderer/Server/Upsampler/UpsamplerState.cs +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; - -namespace Ryujinx.Audio.Renderer.Server.Upsampler -{ - /// <summary> - /// Server state for a upsampling. - /// </summary> - public class UpsamplerState - { - /// <summary> - /// The output buffer containing the target samples. - /// </summary> - public Memory<float> OutputBuffer { get; } - - /// <summary> - /// The target sample count. - /// </summary> - public uint SampleCount { get; } - - /// <summary> - /// The index of the <see cref="UpsamplerState"/>. (used to free it) - /// </summary> - private int _index; - - /// <summary> - /// The <see cref="UpsamplerManager"/>. - /// </summary> - private UpsamplerManager _manager; - - /// <summary> - /// The source sample count. - /// </summary> - public uint SourceSampleCount; - - /// <summary> - /// The input buffer indices of the buffers holding the samples that need upsampling. - /// </summary> - public ushort[] InputBufferIndices; - - /// <summary> - /// Create a new <see cref="UpsamplerState"/>. - /// </summary> - /// <param name="manager">The upsampler manager.</param> - /// <param name="index">The index of the <see cref="UpsamplerState"/>. (used to free it)</param> - /// <param name="outputBuffer">The output buffer used to contain the target samples.</param> - /// <param name="sampleCount">The target sample count.</param> - public UpsamplerState(UpsamplerManager manager, int index, Memory<float> outputBuffer, uint sampleCount) - { - _manager = manager; - _index = index; - OutputBuffer = outputBuffer; - SampleCount = sampleCount; - } - - /// <summary> - /// Release the <see cref="UpsamplerState"/>. - /// </summary> - public void Release() - { - _manager.Free(_index); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Voice/VoiceChannelResource.cs b/Ryujinx.Audio.Renderer/Server/Voice/VoiceChannelResource.cs deleted file mode 100644 index 00520cfc..00000000 --- a/Ryujinx.Audio.Renderer/Server/Voice/VoiceChannelResource.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Voice -{ - /// <summary> - /// Server state for a voice channel resource. - /// </summary> - [StructLayout(LayoutKind.Sequential, Size = 0xD0, Pack = Alignment)] - public struct VoiceChannelResource - { - public const int Alignment = 0x10; - - /// <summary> - /// Mix volumes for the resource. - /// </summary> - public Array24<float> Mix; - - /// <summary> - /// Previous mix volumes for resource. - /// </summary> - public Array24<float> PreviousMix; - - /// <summary> - /// The id of the resource. - /// </summary> - public uint Id; - - /// <summary> - /// Indicate if the resource is used. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool IsUsed; - - public void UpdateState() - { - Mix.ToSpan().CopyTo(PreviousMix.ToSpan()); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Voice/VoiceContext.cs b/Ryujinx.Audio.Renderer/Server/Voice/VoiceContext.cs deleted file mode 100644 index 0dfaa4d5..00000000 --- a/Ryujinx.Audio.Renderer/Server/Voice/VoiceContext.cs +++ /dev/null @@ -1,166 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Utils; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server.Voice -{ - /// <summary> - /// Voice context. - /// </summary> - public class VoiceContext - { - /// <summary> - /// Storage of the sorted indices to <see cref="VoiceState"/>. - /// </summary> - private Memory<int> _sortedVoices; - - /// <summary> - /// Storage for <see cref="VoiceState"/>. - /// </summary> - private Memory<VoiceState> _voices; - - /// <summary> - /// Storage for <see cref="VoiceChannelResource"/>. - /// </summary> - private Memory<VoiceChannelResource> _voiceChannelResources; - - /// <summary> - /// Storage for <see cref="VoiceUpdateState"/> that are used during audio renderer server updates. - /// </summary> - private Memory<VoiceUpdateState> _voiceUpdateStatesCpu; - - /// <summary> - /// Storage for <see cref="VoiceUpdateState"/> for the <see cref="Dsp.AudioProcessor"/>. - /// </summary> - private Memory<VoiceUpdateState> _voiceUpdateStatesDsp; - - /// <summary> - /// The total voice count. - /// </summary> - private uint _voiceCount; - - public void Initialize(Memory<int> sortedVoices, Memory<VoiceState> voices, Memory<VoiceChannelResource> voiceChannelResources, Memory<VoiceUpdateState> voiceUpdateStatesCpu, Memory<VoiceUpdateState> voiceUpdateStatesDsp, uint voiceCount) - { - _sortedVoices = sortedVoices; - _voices = voices; - _voiceChannelResources = voiceChannelResources; - _voiceUpdateStatesCpu = voiceUpdateStatesCpu; - _voiceUpdateStatesDsp = voiceUpdateStatesDsp; - _voiceCount = voiceCount; - } - - /// <summary> - /// Get the total voice count. - /// </summary> - /// <returns>The total voice count.</returns> - public uint GetCount() - { - return _voiceCount; - } - - /// <summary> - /// Get a reference to a <see cref="VoiceChannelResource"/> at the given <paramref name="id"/>. - /// </summary> - /// <param name="id">The index to use.</param> - /// <returns>A reference to a <see cref="VoiceChannelResource"/> at the given <paramref name="id"/>.</returns> - public ref VoiceChannelResource GetChannelResource(int id) - { - return ref SpanIOHelper.GetFromMemory(_voiceChannelResources, id, _voiceCount); - } - - /// <summary> - /// Get a <see cref="Memory{VoiceUpdateState}"/> at the given <paramref name="id"/>. - /// </summary> - /// <param name="id">The index to use.</param> - /// <returns>A <see cref="Memory{VoiceUpdateState}"/> at the given <paramref name="id"/>.</returns> - /// <remarks>The returned <see cref="Memory{VoiceUpdateState}"/> should only be used when updating the server state.</remarks> - public Memory<VoiceUpdateState> GetUpdateStateForCpu(int id) - { - return SpanIOHelper.GetMemory(_voiceUpdateStatesCpu, id, _voiceCount); - } - - /// <summary> - /// Get a <see cref="Memory{VoiceUpdateState}"/> at the given <paramref name="id"/>. - /// </summary> - /// <param name="id">The index to use.</param> - /// <returns>A <see cref="Memory{VoiceUpdateState}"/> at the given <paramref name="id"/>.</returns> - /// <remarks>The returned <see cref="Memory{VoiceUpdateState}"/> should only be used in the context of processing on the <see cref="Dsp.AudioProcessor"/>.</remarks> - public Memory<VoiceUpdateState> GetUpdateStateForDsp(int id) - { - return SpanIOHelper.GetMemory(_voiceUpdateStatesDsp, id, _voiceCount); - } - - /// <summary> - /// Get a reference to a <see cref="VoiceState"/> at the given <paramref name="id"/>. - /// </summary> - /// <param name="id">The index to use.</param> - /// <returns>A reference to a <see cref="VoiceState"/> at the given <paramref name="id"/>.</returns> - public ref VoiceState GetState(int id) - { - return ref SpanIOHelper.GetFromMemory(_voices, id, _voiceCount); - } - - public ref VoiceState GetSortedState(int id) - { - Debug.Assert(id >= 0 && id < _voiceCount); - - return ref GetState(_sortedVoices.Span[id]); - } - - /// <summary> - /// Update internal state during command generation. - /// </summary> - public void UpdateForCommandGeneration() - { - _voiceUpdateStatesDsp.CopyTo(_voiceUpdateStatesCpu); - } - - /// <summary> - /// Sort the internal voices by priority and sorting order (if the priorities match). - /// </summary> - public void Sort() - { - for (int i = 0; i < _voiceCount; i++) - { - _sortedVoices.Span[i] = i; - } - - int[] sortedVoicesTemp = _sortedVoices.Slice(0, (int)GetCount()).ToArray(); - - Array.Sort(sortedVoicesTemp, (a, b) => - { - ref VoiceState aState = ref GetState(a); - ref VoiceState bState = ref GetState(b); - - int result = aState.Priority.CompareTo(bState.Priority); - - if (result == 0) - { - return aState.SortingOrder.CompareTo(bState.SortingOrder); - } - - return result; - }); - - sortedVoicesTemp.AsSpan().CopyTo(_sortedVoices.Span); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Voice/VoiceState.cs b/Ryujinx.Audio.Renderer/Server/Voice/VoiceState.cs deleted file mode 100644 index f30ee2f7..00000000 --- a/Ryujinx.Audio.Renderer/Server/Voice/VoiceState.cs +++ /dev/null @@ -1,715 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using Ryujinx.Common.Memory; -using Ryujinx.Common.Utilities; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; - -namespace Ryujinx.Audio.Renderer.Server.Voice -{ - [StructLayout(LayoutKind.Sequential, Pack = Alignment)] - public struct VoiceState - { - public const int Alignment = 0x10; - - /// <summary> - /// Set to true if the voice is used. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool InUse; - - /// <summary> - /// Set to true if the voice is new. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool IsNew; - - [MarshalAs(UnmanagedType.I1)] - public bool WasPlaying; - - /// <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 total channel count used. - /// </summary> - public uint ChannelsCount; - - /// <summary> - /// Id of the voice. - /// </summary> - public int Id; - - /// <summary> - /// Node id of the voice. - /// </summary> - public int NodeId; - - /// <summary> - /// The target mix id of the voice. - /// </summary> - public int MixId; - - /// <summary> - /// The current voice <see cref="Types.PlayState"/>. - /// </summary> - public Types.PlayState PlayState; - - /// <summary> - /// The previous voice <see cref="Types.PlayState"/>. - /// </summary> - public Types.PlayState PreviousPlayState; - - /// <summary> - /// The priority of the voice. - /// </summary> - public uint Priority; - - /// <summary> - /// Target sorting position of the voice. (used to sort voice with the same <see cref="Priority"/>) - /// </summary> - public uint SortingOrder; - - /// <summary> - /// The pitch used on the voice. - /// </summary> - public float Pitch; - - /// <summary> - /// The output volume of the voice. - /// </summary> - public float Volume; - - /// <summary> - /// The previous output volume of the voice. - /// </summary> - public float PreviousVolume; - - /// <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> - /// Change the behaviour of the voice. - /// </summary> - /// <remarks>This was added on REV5.</remarks> - public DecodingBehaviour DecodingBehaviour; - - /// <summary> - /// User state <see cref="AddressInfo"/> required by the data source. - /// </summary> - /// <remarks>Only used for <see cref="SampleFormat.Adpcm"/> as the GC-ADPCM coefficients.</remarks> - public AddressInfo DataSourceStateAddressInfo; - - /// <summary> - /// The wavebuffers of this voice. - /// </summary> - public Array4<WaveBuffer> WaveBuffers; - - /// <summary> - /// The channel resource ids associated to the voice. - /// </summary> - public Array6<int> ChannelResourceIds; - - /// <summary> - /// The target splitter id of the voice. - /// </summary> - public uint SplitterId; - - /// <summary> - /// Change the Sample Rate Conversion (SRC) quality of the voice. - /// </summary> - /// <remarks>This was added on REV8.</remarks> - public SampleRateConversionQuality SrcQuality; - - /// <summary> - /// If set to true, the voice was dropped. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool VoiceDropFlag; - - /// <summary> - /// Set to true if the data source state work buffer wasn't mapped. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool DataSourceStateUnmapped; - - /// <summary> - /// Set to true if any of the <see cref="WaveBuffer.BufferAddressInfo"/> work buffer wasn't mapped. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool BufferInfoUnmapped; - - /// <summary> - /// The biquad filter initialization state storage. - /// </summary> - private BiquadFilterNeedInitializationArrayStruct _biquadFilterNeedInitialization; - - /// <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; - - [StructLayout(LayoutKind.Sequential, Size = RendererConstants.VoiceBiquadFilterCount)] - private struct BiquadFilterNeedInitializationArrayStruct { } - - /// <summary> - /// The biquad filter initialization state array. - /// </summary> - public Span<bool> BiquadFilterNeedInitialization => SpanHelpers.AsSpan<BiquadFilterNeedInitializationArrayStruct, bool>(ref _biquadFilterNeedInitialization); - - /// <summary> - /// Initialize the <see cref="VoiceState"/>. - /// </summary> - public void Initialize() - { - IsNew = false; - VoiceDropFlag = false; - DataSourceStateUnmapped = false; - BufferInfoUnmapped = false; - FlushWaveBufferCount = 0; - PlayState = Types.PlayState.Stopped; - Priority = RendererConstants.VoiceLowestPriority; - Id = 0; - NodeId = 0; - SampleRate = 0; - SampleFormat = SampleFormat.Invalid; - ChannelsCount = 0; - Pitch = 0.0f; - Volume= 0.0f; - PreviousVolume = 0.0f; - BiquadFilters.ToSpan().Fill(new BiquadFilterParameter()); - WaveBuffersCount = 0; - WaveBuffersIndex = 0; - MixId = RendererConstants.UnusedMixId; - SplitterId = RendererConstants.UnusedSplitterId; - DataSourceStateAddressInfo.Setup(0, 0); - - InitializeWaveBuffers(); - } - - /// <summary> - /// Initialize the <see cref="WaveBuffer"/> in this <see cref="VoiceState"/>. - /// </summary> - private void InitializeWaveBuffers() - { - for (int i = 0; i < WaveBuffers.Length; i++) - { - WaveBuffers[i].StartSampleOffset = 0; - WaveBuffers[i].EndSampleOffset = 0; - WaveBuffers[i].ShouldLoop = false; - WaveBuffers[i].IsEndOfStream = false; - WaveBuffers[i].BufferAddressInfo.Setup(0, 0); - WaveBuffers[i].ContextAddressInfo.Setup(0, 0); - WaveBuffers[i].IsSendToAudioProcessor = true; - } - } - - /// <summary> - /// Check if the voice needs to be skipped. - /// </summary> - /// <returns>Returns true if the voice needs to be skipped.</returns> - public bool ShouldSkip() - { - return !InUse || WaveBuffersCount == 0 || DataSourceStateUnmapped || BufferInfoUnmapped || VoiceDropFlag; - } - - /// <summary> - /// Return true if the mix has any destinations. - /// </summary> - /// <returns>True if the mix has any destinations.</returns> - public bool HasAnyDestination() - { - return MixId != RendererConstants.UnusedMixId || SplitterId != RendererConstants.UnusedSplitterId; - } - - /// <summary> - /// Indicate if the server voice information needs to be updated. - /// </summary> - /// <param name="parameter">The user parameter.</param> - /// <returns>Return true, if the server voice information needs to be updated.</returns> - private bool ShouldUpdateParameters(ref VoiceInParameter parameter) - { - if (DataSourceStateAddressInfo.CpuAddress == parameter.DataSourceStateAddress) - { - return DataSourceStateAddressInfo.Size != parameter.DataSourceStateSize; - } - - return DataSourceStateAddressInfo.CpuAddress != parameter.DataSourceStateAddress || - DataSourceStateAddressInfo.Size != parameter.DataSourceStateSize || - DataSourceStateUnmapped; - } - - /// <summary> - /// Update the internal state from a user parameter. - /// </summary> - /// <param name="outErrorInfo">The possible <see cref="ErrorInfo"/> that was generated.</param> - /// <param name="parameter">The user parameter.</param> - /// <param name="poolMapper">The mapper to use.</param> - /// <param name="behaviourContext">The behaviour context.</param> - public void UpdateParameters(out ErrorInfo outErrorInfo, ref VoiceInParameter parameter, ref PoolMapper poolMapper, ref BehaviourContext behaviourContext) - { - InUse = parameter.InUse; - Id = parameter.Id; - NodeId = parameter.NodeId; - - UpdatePlayState(parameter.PlayState); - - SrcQuality = parameter.SrcQuality; - - Priority = parameter.Priority; - SortingOrder = parameter.SortingOrder; - SampleRate = parameter.SampleRate; - SampleFormat = parameter.SampleFormat; - ChannelsCount = parameter.ChannelCount; - Pitch = parameter.Pitch; - Volume = parameter.Volume; - parameter.BiquadFilters.ToSpan().CopyTo(BiquadFilters.ToSpan()); - WaveBuffersCount = parameter.WaveBuffersCount; - WaveBuffersIndex = parameter.WaveBuffersIndex; - - if (behaviourContext.IsFlushVoiceWaveBuffersSupported()) - { - FlushWaveBufferCount += parameter.FlushWaveBufferCount; - } - - MixId = parameter.MixId; - - if (behaviourContext.IsSplitterSupported()) - { - SplitterId = parameter.SplitterId; - } - else - { - SplitterId = RendererConstants.UnusedSplitterId; - } - - parameter.ChannelResourceIds.ToSpan().CopyTo(ChannelResourceIds.ToSpan()); - - DecodingBehaviour behaviour = DecodingBehaviour.Default; - - if (behaviourContext.IsDecodingBehaviourFlagSupported()) - { - behaviour = parameter.DecodingBehaviourFlags; - } - - DecodingBehaviour = behaviour; - - if (parameter.ResetVoiceDropFlag) - { - VoiceDropFlag = false; - } - - if (ShouldUpdateParameters(ref parameter)) - { - DataSourceStateUnmapped = !poolMapper.TryAttachBuffer(out outErrorInfo, ref DataSourceStateAddressInfo, parameter.DataSourceStateAddress, parameter.DataSourceStateSize); - } - else - { - outErrorInfo = new ErrorInfo(); - } - } - - /// <summary> - /// Update the internal play state from user play state. - /// </summary> - /// <param name="userPlayState">The target user play state.</param> - public void UpdatePlayState(PlayState userPlayState) - { - Types.PlayState oldServerPlayState = PlayState; - - PreviousPlayState = oldServerPlayState; - - Types.PlayState newServerPlayState; - - switch (userPlayState) - { - case Common.PlayState.Start: - newServerPlayState = Types.PlayState.Started; - break; - - case Common.PlayState.Stop: - if (oldServerPlayState == Types.PlayState.Stopped) - { - return; - } - - newServerPlayState = Types.PlayState.Stopping; - break; - - case Common.PlayState.Pause: - newServerPlayState = Types.PlayState.Paused; - break; - - default: - throw new NotImplementedException($"Unhandled PlayState.{userPlayState}"); - } - - PlayState = newServerPlayState; - } - - /// <summary> - /// Write the status of the voice to the given user output. - /// </summary> - /// <param name="outStatus">The given user output.</param> - /// <param name="parameter">The user parameter.</param> - /// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param> - public void WriteOutStatus(ref VoiceOutStatus outStatus, ref VoiceInParameter parameter, Memory<VoiceUpdateState>[] voiceUpdateStates) - { -#if DEBUG - // Sanity check in debug mode of the internal state - if (!parameter.IsNew && !IsNew) - { - for (int i = 1; i < ChannelsCount; i++) - { - ref VoiceUpdateState stateA = ref voiceUpdateStates[i - 1].Span[0]; - ref VoiceUpdateState stateB = ref voiceUpdateStates[i].Span[0]; - - Debug.Assert(stateA.WaveBufferConsumed == stateB.WaveBufferConsumed); - Debug.Assert(stateA.PlayedSampleCount == stateB.PlayedSampleCount); - Debug.Assert(stateA.Offset == stateB.Offset); - Debug.Assert(stateA.WaveBufferIndex == stateB.WaveBufferIndex); - Debug.Assert(stateA.Fraction == stateB.Fraction); - Debug.Assert(stateA.IsWaveBufferValid.SequenceEqual(stateB.IsWaveBufferValid)); - } - } -#endif - if (parameter.IsNew || IsNew) - { - IsNew = true; - - outStatus.VoiceDropFlag = false; - outStatus.PlayedWaveBuffersCount = 0; - outStatus.PlayedSampleCount = 0; - } - else - { - ref VoiceUpdateState state = ref voiceUpdateStates[0].Span[0]; - - outStatus.VoiceDropFlag = VoiceDropFlag; - outStatus.PlayedWaveBuffersCount = state.WaveBufferConsumed; - outStatus.PlayedSampleCount = state.PlayedSampleCount; - } - } - - /// <summary> - /// Update the internal state of all the <see cref="WaveBuffer"/> of the <see cref="VoiceState"/>. - /// </summary> - /// <param name="errorInfos">An array of <see cref="ErrorInfo"/> used to report errors when mapping any of the <see cref="WaveBuffer"/>.</param> - /// <param name="parameter">The user parameter.</param> - /// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param> - /// <param name="mapper">The mapper to use.</param> - /// <param name="behaviourContext">The behaviour context.</param> - public void UpdateWaveBuffers(out ErrorInfo[] errorInfos, ref VoiceInParameter parameter, Memory<VoiceUpdateState>[] voiceUpdateStates, ref PoolMapper mapper, ref BehaviourContext behaviourContext) - { - errorInfos = new ErrorInfo[RendererConstants.VoiceWaveBufferCount * 2]; - - if (parameter.IsNew) - { - InitializeWaveBuffers(); - - for (int i = 0; i < parameter.ChannelCount; i++) - { - voiceUpdateStates[i].Span[0].IsWaveBufferValid.Fill(false); - } - } - - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[0].Span[0]; - - for (int i = 0; i < RendererConstants.VoiceWaveBufferCount; i++) - { - UpdateWaveBuffer(errorInfos.AsSpan().Slice(i * 2, 2), ref WaveBuffers[i], ref parameter.WaveBuffers[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], ref mapper, ref behaviourContext); - } - } - - /// <summary> - /// Update the internal state of one of the <see cref="WaveBuffer"/> of the <see cref="VoiceState"/>. - /// </summary> - /// <param name="errorInfos">A <see cref="Span{ErrorInfo}"/> used to report errors when mapping the <see cref="WaveBuffer"/>.</param> - /// <param name="waveBuffer">The <see cref="WaveBuffer"/> to update.</param> - /// <param name="inputWaveBuffer">The <see cref="WaveBufferInternal"/> from the user input.</param> - /// <param name="sampleFormat">The <see cref="SampleFormat"/> from the user input.</param> - /// <param name="isValid">If set to true, the server side wavebuffer is considered valid.</param> - /// <param name="mapper">The mapper to use.</param> - /// <param name="behaviourContext">The behaviour context.</param> - private void UpdateWaveBuffer(Span<ErrorInfo> errorInfos, ref WaveBuffer waveBuffer, ref WaveBufferInternal inputWaveBuffer, SampleFormat sampleFormat, bool isValid, ref PoolMapper mapper, ref BehaviourContext behaviourContext) - { - if (!isValid && waveBuffer.IsSendToAudioProcessor && waveBuffer.BufferAddressInfo.CpuAddress != 0) - { - mapper.ForceUnmap(ref waveBuffer.BufferAddressInfo); - waveBuffer.BufferAddressInfo.Setup(0, 0); - } - - if (!inputWaveBuffer.SentToServer || BufferInfoUnmapped) - { - if (inputWaveBuffer.IsSampleOffsetValid(sampleFormat)) - { - Debug.Assert(waveBuffer.IsSendToAudioProcessor); - - waveBuffer.IsSendToAudioProcessor = false; - waveBuffer.StartSampleOffset = inputWaveBuffer.StartSampleOffset; - waveBuffer.EndSampleOffset = inputWaveBuffer.EndSampleOffset; - waveBuffer.ShouldLoop = inputWaveBuffer.ShouldLoop; - waveBuffer.IsEndOfStream = inputWaveBuffer.IsEndOfStream; - waveBuffer.LoopStartSampleOffset = inputWaveBuffer.LoopFirstSampleOffset; - waveBuffer.LoopEndSampleOffset = inputWaveBuffer.LoopLastSampleOffset; - waveBuffer.LoopCount = inputWaveBuffer.LoopCount; - - BufferInfoUnmapped = !mapper.TryAttachBuffer(out ErrorInfo bufferInfoError, ref waveBuffer.BufferAddressInfo, inputWaveBuffer.Address, inputWaveBuffer.Size); - - errorInfos[0] = bufferInfoError; - - if (sampleFormat == SampleFormat.Adpcm && behaviourContext.IsAdpcmLoopContextBugFixed() && inputWaveBuffer.ContextAddress != 0) - { - bool adpcmLoopContextMapped = mapper.TryAttachBuffer(out ErrorInfo adpcmLoopContextInfoError, - ref waveBuffer.ContextAddressInfo, - inputWaveBuffer.ContextAddress, - inputWaveBuffer.ContextSize); - - errorInfos[1] = adpcmLoopContextInfoError; - - if (adpcmLoopContextMapped) - { - BufferInfoUnmapped = DataSourceStateUnmapped; - } - else - { - BufferInfoUnmapped = true; - } - } - else - { - waveBuffer.ContextAddressInfo.Setup(0, 0); - } - } - else - { - errorInfos[0].ErrorCode = ResultCode.InvalidAddressInfo; - errorInfos[0].ExtraErrorInfo = inputWaveBuffer.Address; - } - } - } - - /// <summary> - /// Reset the resources associated to this <see cref="VoiceState"/>. - /// </summary> - /// <param name="context">The voice context.</param> - private void ResetResources(VoiceContext context) - { - for (int i = 0; i < ChannelsCount; i++) - { - int channelResourceId = ChannelResourceIds[i]; - - ref VoiceChannelResource voiceChannelResource = ref context.GetChannelResource(channelResourceId); - - Debug.Assert(voiceChannelResource.IsUsed); - - Memory<VoiceUpdateState> dspSharedState = context.GetUpdateStateForDsp(channelResourceId); - - MemoryMarshal.Cast<VoiceUpdateState, byte>(dspSharedState.Span).Fill(0); - - voiceChannelResource.UpdateState(); - } - } - - /// <summary> - /// Flush a certain amount of <see cref="WaveBuffer"/>. - /// </summary> - /// <param name="waveBufferCount">The amount of wavebuffer to flush.</param> - /// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param> - /// <param name="channelCount">The channel count from user input.</param> - private void FlushWaveBuffers(uint waveBufferCount, Memory<VoiceUpdateState>[] voiceUpdateStates, uint channelCount) - { - uint waveBufferIndex = WaveBuffersIndex; - - for (int i = 0; i < waveBufferCount; i++) - { - WaveBuffers[(int)waveBufferIndex].IsSendToAudioProcessor = true; - - for (int j = 0; j < channelCount; j++) - { - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[j].Span[0]; - - voiceUpdateState.WaveBufferIndex = (voiceUpdateState.WaveBufferIndex + 1) % RendererConstants.VoiceWaveBufferCount; - voiceUpdateState.WaveBufferConsumed++; - voiceUpdateState.IsWaveBufferValid[(int)waveBufferIndex] = false; - } - - waveBufferIndex = (waveBufferIndex + 1) % RendererConstants.VoiceWaveBufferCount; - } - } - - /// <summary> - /// Update the internal parameters for command generation. - /// </summary> - /// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param> - /// <returns>Return true if this voice should be played.</returns> - public bool UpdateParametersForCommandGeneration(Memory<VoiceUpdateState>[] voiceUpdateStates) - { - if (FlushWaveBufferCount != 0) - { - FlushWaveBuffers(FlushWaveBufferCount, voiceUpdateStates, ChannelsCount); - - FlushWaveBufferCount = 0; - } - - switch (PlayState) - { - case Types.PlayState.Started: - for (int i = 0; i < WaveBuffers.Length; i++) - { - ref WaveBuffer wavebuffer = ref WaveBuffers[i]; - - if (!wavebuffer.IsSendToAudioProcessor) - { - for (int y = 0; y < ChannelsCount; y++) - { - Debug.Assert(!voiceUpdateStates[y].Span[0].IsWaveBufferValid[i]); - - voiceUpdateStates[y].Span[0].IsWaveBufferValid[i] = true; - } - - wavebuffer.IsSendToAudioProcessor = true; - } - } - - WasPlaying = false; - - ref VoiceUpdateState primaryVoiceUpdateState = ref voiceUpdateStates[0].Span[0]; - - for (int i = 0; i < primaryVoiceUpdateState.IsWaveBufferValid.Length; i++) - { - if (primaryVoiceUpdateState.IsWaveBufferValid[i]) - { - return true; - } - } - - return false; - - case Types.PlayState.Stopping: - for (int i = 0; i < WaveBuffers.Length; i++) - { - ref WaveBuffer wavebuffer = ref WaveBuffers[i]; - - wavebuffer.IsSendToAudioProcessor = true; - - for (int j = 0; j < ChannelsCount; j++) - { - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[j].Span[0]; - - if (voiceUpdateState.IsWaveBufferValid[i]) - { - voiceUpdateState.WaveBufferIndex = (voiceUpdateState.WaveBufferIndex + 1) % RendererConstants.VoiceWaveBufferCount; - voiceUpdateState.WaveBufferConsumed++; - } - - voiceUpdateState.IsWaveBufferValid[i] = false; - } - } - - for (int i = 0; i < ChannelsCount; i++) - { - ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[i].Span[0]; - - voiceUpdateState.Offset = 0; - voiceUpdateState.PlayedSampleCount = 0; - voiceUpdateState.Pitch.ToSpan().Fill(0); - voiceUpdateState.Fraction = 0; - voiceUpdateState.LoopContext = new Dsp.State.AdpcmLoopContext(); - } - - PlayState = Types.PlayState.Stopped; - WasPlaying = PreviousPlayState == Types.PlayState.Started; - - return WasPlaying; - - case Types.PlayState.Stopped: - case Types.PlayState.Paused: - foreach (ref WaveBuffer wavebuffer in WaveBuffers.ToSpan()) - { - wavebuffer.BufferAddressInfo.GetReference(true); - wavebuffer.ContextAddressInfo.GetReference(true); - } - - if (SampleFormat == SampleFormat.Adpcm) - { - if (DataSourceStateAddressInfo.CpuAddress != 0) - { - DataSourceStateAddressInfo.GetReference(true); - } - } - - WasPlaying = PreviousPlayState == Types.PlayState.Started; - - return WasPlaying; - default: - throw new NotImplementedException($"{PlayState}"); - } - } - - /// <summary> - /// Update the internal state for command generation. - /// </summary> - /// <param name="context">The voice context.</param> - /// <returns>Return true if this voice should be played.</returns> - public bool UpdateForCommandGeneration(VoiceContext context) - { - if (IsNew) - { - ResetResources(context); - PreviousVolume = Volume; - IsNew = false; - } - - Memory<VoiceUpdateState>[] voiceUpdateStates = new Memory<VoiceUpdateState>[RendererConstants.VoiceChannelCountMax]; - - for (int i = 0; i < ChannelsCount; i++) - { - voiceUpdateStates[i] = context.GetUpdateStateForDsp(ChannelResourceIds[i]); - } - - return UpdateParametersForCommandGeneration(voiceUpdateStates); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Server/Voice/WaveBuffer.cs b/Ryujinx.Audio.Renderer/Server/Voice/WaveBuffer.cs deleted file mode 100644 index a03aa757..00000000 --- a/Ryujinx.Audio.Renderer/Server/Voice/WaveBuffer.cs +++ /dev/null @@ -1,121 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Voice -{ - /// <summary> - /// A wavebuffer used for server update. - /// </summary> - [StructLayout(LayoutKind.Sequential, Size = 0x58, Pack = 1)] - public struct WaveBuffer - { - /// <summary> - /// The <see cref="AddressInfo"/> of the sample data of the wavebuffer. - /// </summary> - public AddressInfo BufferAddressInfo; - - /// <summary> - /// The <see cref="AddressInfo"/> of the context of the wavebuffer. - /// </summary> - /// <remarks>Only used by <see cref="Common.SampleFormat.Adpcm"/>.</remarks> - public AddressInfo ContextAddressInfo; - - - /// <summary> - /// First sample to play of the wavebuffer. - /// </summary> - public uint StartSampleOffset; - - /// <summary> - /// Last sample to play of the wavebuffer. - /// </summary> - public uint EndSampleOffset; - - /// <summary> - /// Set to true if the wavebuffer is looping. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool ShouldLoop; - - /// <summary> - /// Set to true if the wavebuffer is the end of stream. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool IsEndOfStream; - - /// <summary> - /// Set to true if the wavebuffer wasn't sent to the <see cref="Dsp.AudioProcessor"/>. - /// </summary> - [MarshalAs(UnmanagedType.I1)] - public bool IsSendToAudioProcessor; - - /// <summary> - /// First sample to play when looping the wavebuffer. - /// </summary> - public uint LoopStartSampleOffset; - - /// <summary> - /// Last sample to play when looping the wavebuffer. - /// </summary> - public uint LoopEndSampleOffset; - - /// <summary> - /// The max loop count. - /// </summary> - public int LoopCount; - - /// <summary> - /// Create a new <see cref="Common.WaveBuffer"/> for use by the <see cref="Dsp.AudioProcessor"/>. - /// </summary> - /// <param name="version">The target version of the wavebuffer.</param> - /// <returns>A new <see cref="Common.WaveBuffer"/> for use by the <see cref="Dsp.AudioProcessor"/>.</returns> - public Common.WaveBuffer ToCommon(int version) - { - Common.WaveBuffer waveBuffer = new Common.WaveBuffer(); - - waveBuffer.Buffer = BufferAddressInfo.GetReference(true); - waveBuffer.BufferSize = (uint)BufferAddressInfo.Size; - - if (ContextAddressInfo.CpuAddress != 0) - { - waveBuffer.Context = ContextAddressInfo.GetReference(true); - waveBuffer.ContextSize = (uint)ContextAddressInfo.Size; - } - - waveBuffer.StartSampleOffset = StartSampleOffset; - waveBuffer.EndSampleOffset = EndSampleOffset; - waveBuffer.Looping = ShouldLoop; - waveBuffer.IsEndOfStream = IsEndOfStream; - - if (version == 2) - { - waveBuffer.LoopCount = LoopCount; - waveBuffer.LoopStartSampleOffset = LoopStartSampleOffset; - waveBuffer.LoopEndSampleOffset = LoopEndSampleOffset; - } - else - { - waveBuffer.LoopCount = -1; - } - - return waveBuffer; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Utils/AudioProcessorMemoryManager.cs b/Ryujinx.Audio.Renderer/Utils/AudioProcessorMemoryManager.cs deleted file mode 100644 index 99cbfcdc..00000000 --- a/Ryujinx.Audio.Renderer/Utils/AudioProcessorMemoryManager.cs +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System.Runtime.CompilerServices; - -using DspAddress = System.UInt64; -using CpuAddress = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Utils -{ - /// <summary> - /// The <see cref="Dsp.AudioProcessor"/> memory management - /// </summary> - /// <remarks>This is stub for the most part but is kept to permit LLE if wanted.</remarks> - static class AudioProcessorMemoryManager - { - /// <summary> - /// Map the given <see cref="CpuAddress"/> to the <see cref="Dsp.AudioProcessor"/> address space. - /// </summary> - /// <param name="processHandle">The process owning the CPU memory.</param> - /// <param name="cpuAddress">The <see cref="CpuAddress"/> to map.</param> - /// <param name="size">The size of the CPU memory region to map.</param> - /// <returns>The address on the <see cref="Dsp.AudioProcessor"/> address space.</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static DspAddress Map(uint processHandle, CpuAddress cpuAddress, ulong size) - { - return cpuAddress; - } - - /// <summary> - /// Unmap the given <see cref="CpuAddress"/> from the <see cref="Dsp.AudioProcessor"/> address space. - /// </summary> - /// <param name="processHandle">The process owning the CPU memory.</param> - /// <param name="cpuAddress">The <see cref="CpuAddress"/> to unmap.</param> - /// <param name="size">The size of the CPU memory region to unmap.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Unmap(uint processHandle, CpuAddress cpuAddress, ulong size) - { - } - - /// <summary> - /// Invalidate the <see cref="Dsp.AudioProcessor"/> data cache at the given address. - /// </summary> - /// <param name="address">The base DSP address to invalidate</param> - /// <param name="size">The size of the DSP memory region to invalidate.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InvalidateDspCache(DspAddress address, ulong size) - { - } - - /// <summary> - /// Invalidate the CPU data cache at the given address. - /// </summary> - /// <param name="address">The base <see cref="CpuAddress"/> to invalidate</param> - /// <param name="size">The size of the CPU memory region to invalidate.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InvalidateDataCache(CpuAddress address, ulong size) - { - } - } -} diff --git a/Ryujinx.Audio.Renderer/Utils/BitArray.cs b/Ryujinx.Audio.Renderer/Utils/BitArray.cs deleted file mode 100644 index 6109dd01..00000000 --- a/Ryujinx.Audio.Renderer/Utils/BitArray.cs +++ /dev/null @@ -1,120 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Utils -{ - /// <summary> - /// A simple bit array implementation backed by a <see cref="Memory{T}"/>. - /// </summary> - public class BitArray - { - /// <summary> - /// The backing storage of the <see cref="BitArray"/>. - /// </summary> - private Memory<byte> _storage; - - /// <summary> - /// Create a new <see cref="BitArray"/> from <see cref="Memory{T}"/>. - /// </summary> - /// <param name="storage">The backing storage of the <see cref="BitArray"/>.</param> - public BitArray(Memory<byte> storage) - { - _storage = storage; - } - - /// <summary> - /// Get the byte position of a given bit index. - /// </summary> - /// <param name="index">A bit index.</param> - /// <returns>The byte position of a given bit index.</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int ToPosition(int index) => index / 8; - - /// <summary> - /// Get the bit position of a given bit index inside a byte. - /// </summary> - /// <param name="index">A bit index.</param> - /// <returns>The bit position of a given bit index inside a byte.</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int ToBitPosition(int index) => index % 8; - - /// <summary> - /// Test if the bit at the given index is set. - /// </summary> - /// <param name="index">A bit index.</param> - /// <returns>Return true if the bit at the given index is set</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Test(int index) - { - ulong mask = 1ul << ToBitPosition(index); - - return (_storage.Span[ToPosition(index)] & mask) == mask; - } - - /// <summary> - /// Set the bit at the given index. - /// </summary> - /// <param name="index">A bit index.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(int index) - { - Set(index, true); - } - - /// <summary> - /// Reset the bit at the given index. - /// </summary> - /// <param name="index">A bit index.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Reset(int index) - { - Set(index, false); - } - - /// <summary> - /// Set a bit value at the given index. - /// </summary> - /// <param name="index">A bit index.</param> - /// <param name="value">The new bit value.</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void Set(int index, bool value) - { - byte mask = (byte)(1 << ToBitPosition(index)); - - if (value) - { - _storage.Span[ToPosition(index)] |= mask; - } - else - { - _storage.Span[ToPosition(index)] &= (byte)~mask; - } - } - - /// <summary> - /// Reset all bits in the storage. - /// </summary> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Reset() - { - _storage.Span.Fill(0); - } - } -} diff --git a/Ryujinx.Audio.Renderer/Utils/FileHardwareDevice.cs b/Ryujinx.Audio.Renderer/Utils/FileHardwareDevice.cs deleted file mode 100644 index d5cbb8df..00000000 --- a/Ryujinx.Audio.Renderer/Utils/FileHardwareDevice.cs +++ /dev/null @@ -1,105 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Integration; -using System; -using System.IO; -using System.Runtime.InteropServices; -using System.Text; - -namespace Ryujinx.Audio.Renderer.Utils -{ - /// <summary> - /// A <see cref="HardwareDevice"/> that outputs to a wav file. - /// </summary> - public class FileHardwareDevice : HardwareDevice - { - private FileStream _stream; - private uint _channelCount; - private uint _sampleRate; - - private const int HeaderSize = 44; - - public FileHardwareDevice(string path, uint channelCount, uint sampleRate) - { - _stream = File.OpenWrite(path); - _channelCount = channelCount; - _sampleRate = sampleRate; - - _stream.Seek(HeaderSize, SeekOrigin.Begin); - } - - private void UpdateHeader() - { - var writer = new BinaryWriter(_stream); - - long currentPos = writer.Seek(0, SeekOrigin.Current); - - writer.Seek(0, SeekOrigin.Begin); - - writer.Write(Encoding.ASCII.GetBytes("RIFF")); - writer.Write((int)(writer.BaseStream.Length - 8)); - writer.Write(Encoding.ASCII.GetBytes("WAVE")); - writer.Write(Encoding.ASCII.GetBytes("fmt ")); - writer.Write(16); - writer.Write((short)1); - writer.Write((short)GetChannelCount()); - writer.Write(GetSampleRate()); - writer.Write(GetSampleRate() * GetChannelCount() * sizeof(short)); - writer.Write((short)(GetChannelCount() * sizeof(short))); - writer.Write((short)(sizeof(short) * 8)); - writer.Write(Encoding.ASCII.GetBytes("data")); - writer.Write((int)(writer.BaseStream.Length - HeaderSize)); - - writer.Seek((int)currentPos, SeekOrigin.Begin); - } - - public void AppendBuffer(ReadOnlySpan<short> data, uint channelCount) - { - _stream.Write(MemoryMarshal.Cast<short, byte>(data)); - - UpdateHeader(); - _stream.Flush(); - } - - public uint GetChannelCount() - { - return _channelCount; - } - - public uint GetSampleRate() - { - return _sampleRate; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _stream?.Flush(); - _stream?.Dispose(); - - _stream = null; - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Utils/Mailbox.cs b/Ryujinx.Audio.Renderer/Utils/Mailbox.cs deleted file mode 100644 index a32de870..00000000 --- a/Ryujinx.Audio.Renderer/Utils/Mailbox.cs +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Collections.Concurrent; - -namespace Ryujinx.Audio.Renderer.Utils -{ - /// <summary> - /// A simple generic message queue for unmanaged types. - /// </summary> - /// <typeparam name="T">The target unmanaged type used</typeparam> - public class Mailbox<T> : IDisposable where T : unmanaged - { - private BlockingCollection<T> _messageQueue; - private BlockingCollection<T> _responseQueue; - - public Mailbox() - { - _messageQueue = new BlockingCollection<T>(1); - _responseQueue = new BlockingCollection<T>(1); - } - - public void SendMessage(T data) - { - _messageQueue.Add(data); - } - - public void SendResponse(T data) - { - _responseQueue.Add(data); - } - - public T ReceiveMessage() - { - return _messageQueue.Take(); - } - - public T ReceiveResponse() - { - return _responseQueue.Take(); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _messageQueue.Dispose(); - _responseQueue.Dispose(); - } - } - } -} diff --git a/Ryujinx.Audio.Renderer/Utils/SpanIOHelper.cs b/Ryujinx.Audio.Renderer/Utils/SpanIOHelper.cs deleted file mode 100644 index 70a2fce6..00000000 --- a/Ryujinx.Audio.Renderer/Utils/SpanIOHelper.cs +++ /dev/null @@ -1,188 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Utils -{ - /// <summary> - /// Helper for IO operations on <see cref="Span{T}"/> and <see cref="Memory{T}"/>. - /// </summary> - public static class SpanIOHelper - { - /// <summary> - /// Write the given data to the given backing <see cref="Memory{T}"/> and move cursor after the written data. - /// </summary> - /// <typeparam name="T">The data type.</typeparam> - /// <param name="backingMemory">The backing <see cref="Memory{T}"/> to store the data.</param> - /// <param name="data">The data to write to the backing <see cref="Memory{T}"/>.</param> - public static void Write<T>(ref Memory<byte> backingMemory, ref T data) where T : unmanaged - { - int size = Unsafe.SizeOf<T>(); - - if (size > backingMemory.Length) - { - throw new ArgumentOutOfRangeException(); - } - - MemoryMarshal.Write<T>(backingMemory.Span.Slice(0, size), ref data); - - backingMemory = backingMemory.Slice(size); - } - - /// <summary> - /// Write the given data to the given backing <see cref="Span{T}"/> and move cursor after the written data. - /// </summary> - /// <typeparam name="T">The data type.</typeparam> - /// <param name="backingMemory">The backing <see cref="Span{T}"/> to store the data.</param> - /// <param name="data">The data to write to the backing <see cref="Span{T}"/>.</param> - public static void Write<T>(ref Span<byte> backingMemory, ref T data) where T : unmanaged - { - int size = Unsafe.SizeOf<T>(); - - if (size > backingMemory.Length) - { - throw new ArgumentOutOfRangeException(); - } - - MemoryMarshal.Write<T>(backingMemory.Slice(0, size), ref data); - - backingMemory = backingMemory.Slice(size); - } - - /// <summary> - /// Get a <see cref="Span{T}"/> out of a <paramref name="backingMemory"/> and move cursor after T size. - /// </summary> - /// <typeparam name="T">The data type.</typeparam> - /// <param name="backingMemory">The backing <see cref="Memory{T}"/> to get a <see cref="Span{T}"/> from.</param> - /// <returns>A <see cref="Span{T}"/> from backing <see cref="Memory{T}"/>.</returns> - public static Span<T> GetWriteRef<T>(ref Memory<byte> backingMemory) where T : unmanaged - { - int size = Unsafe.SizeOf<T>(); - - if (size > backingMemory.Length) - { - throw new ArgumentOutOfRangeException(); - } - - Span<T> result = MemoryMarshal.Cast<byte, T>(backingMemory.Span.Slice(0, size)); - - backingMemory = backingMemory.Slice(size); - - return result; - } - - /// <summary> - /// Get a <see cref="Span{T}"/> out of a backingMemory and move cursor after T size. - /// </summary> - /// <typeparam name="T">The data type.</typeparam> - /// <param name="backingMemory">The backing <see cref="Span{T}"/> to get a <see cref="Span{T}"/> from.</param> - /// <returns>A <see cref="Span{T}"/> from backing <see cref="Span{T}"/>.</returns> - public static Span<T> GetWriteRef<T>(ref Span<byte> backingMemory) where T : unmanaged - { - int size = Unsafe.SizeOf<T>(); - - if (size > backingMemory.Length) - { - throw new ArgumentOutOfRangeException(); - } - - Span<T> result = MemoryMarshal.Cast<byte, T>(backingMemory.Slice(0, size)); - - backingMemory = backingMemory.Slice(size); - - return result; - } - - /// <summary> - /// Read data from the given backing <see cref="ReadOnlyMemory{T}"/> and move cursor after the read data. - /// </summary> - /// <typeparam name="T">The data type.</typeparam> - /// <param name="backingMemory">The backing <see cref="ReadOnlyMemory{T}"/> to read data from.</param> - /// <returns>Return the read data.</returns> - public static T Read<T>(ref ReadOnlyMemory<byte> backingMemory) where T : unmanaged - { - int size = Unsafe.SizeOf<T>(); - - if (size > backingMemory.Length) - { - throw new ArgumentOutOfRangeException(); - } - - T result = MemoryMarshal.Read<T>(backingMemory.Span.Slice(0, size)); - - backingMemory = backingMemory.Slice(size); - - return result; - } - - /// <summary> - /// Read data from the given backing <see cref="ReadOnlySpan{T}"/> and move cursor after the read data. - /// </summary> - /// <typeparam name="T">The data type.</typeparam> - /// <param name="backingMemory">The backing <see cref="ReadOnlySpan{T}"/> to read data from.</param> - /// <returns>Return the read data.</returns> - public static T Read<T>(ref ReadOnlySpan<byte> backingMemory) where T : unmanaged - { - int size = Unsafe.SizeOf<T>(); - - if (size > backingMemory.Length) - { - throw new ArgumentOutOfRangeException(); - } - - T result = MemoryMarshal.Read<T>(backingMemory.Slice(0, size)); - - backingMemory = backingMemory.Slice(size); - - return result; - } - - /// <summary> - /// Extract a <see cref="Memory{T}"/> at the given index. - /// </summary> - /// <typeparam name="T">The data type.</typeparam> - /// <param name="memory">The <see cref="Memory{T}"/> to extract the data from.</param> - /// <param name="id">The id in the provided memory.</param> - /// <param name="count">The max allowed count. (for bound checking of the id in debug mode)</param> - /// <returns>a <see cref="Memory{T}"/> at the given id.</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Memory<T> GetMemory<T>(Memory<T> memory, int id, uint count) where T : unmanaged - { - Debug.Assert(id >= 0 && id < count); - - return memory.Slice(id, 1); - } - - /// <summary> - /// Extract a ref T at the given index. - /// </summary> - /// <typeparam name="T">The data type.</typeparam> - /// <param name="memory">The <see cref="Memory{T}"/> to extract the data from.</param> - /// <param name="id">The id in the provided memory.</param> - /// <param name="count">The max allowed count. (for bound checking of the id in debug mode)</param> - /// <returns>a ref T at the given id.</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref T GetFromMemory<T>(Memory<T> memory, int id, uint count) where T : unmanaged - { - return ref GetMemory(memory, id, count).Span[0]; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Utils/SpanMemoryManager.cs b/Ryujinx.Audio.Renderer/Utils/SpanMemoryManager.cs deleted file mode 100644 index 102a9f95..00000000 --- a/Ryujinx.Audio.Renderer/Utils/SpanMemoryManager.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using System; -using System.Buffers; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Utils -{ - public sealed unsafe class SpanMemoryManager<T> : MemoryManager<T> - where T : unmanaged - { - private readonly T* _pointer; - private readonly int _length; - - public SpanMemoryManager(Span<T> span) - { - fixed (T* ptr = &MemoryMarshal.GetReference(span)) - { - _pointer = ptr; - _length = span.Length; - } - } - - public override Span<T> GetSpan() => new Span<T>(_pointer, _length); - - public override MemoryHandle Pin(int elementIndex = 0) - { - if (elementIndex < 0 || elementIndex >= _length) - { - throw new ArgumentOutOfRangeException(nameof(elementIndex)); - } - - return new MemoryHandle(_pointer + elementIndex); - } - - public override void Unpin() { } - - protected override void Dispose(bool disposing) { } - - public static Memory<T> Cast<TFrom>(Memory<TFrom> memory) where TFrom : unmanaged - { - return new SpanMemoryManager<T>(MemoryMarshal.Cast<TFrom, T>(memory.Span)).Memory; - } - } -} diff --git a/Ryujinx.Audio.Renderer/Utils/SplitterHardwareDevice.cs b/Ryujinx.Audio.Renderer/Utils/SplitterHardwareDevice.cs deleted file mode 100644 index f23bde8a..00000000 --- a/Ryujinx.Audio.Renderer/Utils/SplitterHardwareDevice.cs +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (c) 2019-2021 Ryujinx -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. -// - -using Ryujinx.Audio.Renderer.Integration; -using System; - -namespace Ryujinx.Audio.Renderer.Utils -{ - public class SplitterHardwareDevice : HardwareDevice - { - private HardwareDevice _baseDevice; - private HardwareDevice _secondaryDevice; - - public SplitterHardwareDevice(HardwareDevice baseDevice, HardwareDevice secondaryDevice) - { - _baseDevice = baseDevice; - _secondaryDevice = secondaryDevice; - } - - public void AppendBuffer(ReadOnlySpan<short> data, uint channelCount) - { - _baseDevice.AppendBuffer(data, channelCount); - _secondaryDevice?.AppendBuffer(data, channelCount); - } - - public uint GetChannelCount() - { - return _baseDevice.GetChannelCount(); - } - - public uint GetSampleRate() - { - return _baseDevice.GetSampleRate(); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _baseDevice.Dispose(); - _secondaryDevice?.Dispose(); - } - } - } -} |
