Haydn: Part 1 (#2007)
* Haydn: Part 1 Based on my reverse of audio 11.0.0. As always, core implementation under LGPLv3 for the same reasons as for Amadeus. This place the bases of a more flexible audio system while making audout & audin accurate. This have the following improvements: - Complete reimplementation of audout and audin. - Audin currently only have a dummy backend. - Dramatically reduce CPU usage by up to 50% in common cases (SoundIO and OpenAL). - Audio Renderer now can output to 5.1 devices when supported. - Audio Renderer init its backend on demand instead of keeping two up all the time. - All backends implementation are now in their own project. - Ryujinx.Audio.Renderer was renamed Ryujinx.Audio and was refactored because of this. As a note, games having issues with OpenAL haven't improved and will not because of OpenAL design (stopping when buffers finish playing causing possible audio "pops" when buffers are very small). * Update for latest hexkyz's edits on Switchbrew * audren: Rollback channel configuration changes * Address gdkchan's comments * Fix typo in OpenAL backend driver * Address last comments * Fix a nit * Address gdkchan's comments
This commit is contained in:
parent
1c49089ff0
commit
f556c80d02
249 changed files with 5614 additions and 2712 deletions
30
Ryujinx.Audio/Renderer/Common/AuxiliaryBufferAddresses.cs
Normal file
30
Ryujinx.Audio/Renderer/Common/AuxiliaryBufferAddresses.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// 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;
|
||||
}
|
||||
}
|
67
Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs
Normal file
67
Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs
Normal file
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
167
Ryujinx.Audio/Renderer/Common/EdgeMatrix.cs
Normal file
167
Ryujinx.Audio/Renderer/Common/EdgeMatrix.cs
Normal file
|
@ -0,0 +1,167 @@
|
|||
//
|
||||
// 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, Constants.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;
|
||||
}
|
||||
}
|
||||
}
|
60
Ryujinx.Audio/Renderer/Common/EffectType.cs
Normal file
60
Ryujinx.Audio/Renderer/Common/EffectType.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// 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
|
||||
}
|
||||
}
|
60
Ryujinx.Audio/Renderer/Common/MemoryPoolUserState.cs
Normal file
60
Ryujinx.Audio/Renderer/Common/MemoryPoolUserState.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// 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
|
||||
}
|
||||
}
|
45
Ryujinx.Audio/Renderer/Common/NodeIdHelper.cs
Normal file
45
Ryujinx.Audio/Renderer/Common/NodeIdHelper.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
50
Ryujinx.Audio/Renderer/Common/NodeIdType.cs
Normal file
50
Ryujinx.Audio/Renderer/Common/NodeIdType.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// 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
|
||||
}
|
||||
}
|
246
Ryujinx.Audio/Renderer/Common/NodeStates.cs
Normal file
246
Ryujinx.Audio/Renderer/Common/NodeStates.cs
Normal file
|
@ -0,0 +1,246 @@
|
|||
//
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
34
Ryujinx.Audio/Renderer/Common/PerformanceDetailType.cs
Normal file
34
Ryujinx.Audio/Renderer/Common/PerformanceDetailType.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// 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
|
||||
}
|
||||
}
|
28
Ryujinx.Audio/Renderer/Common/PerformanceEntryType.cs
Normal file
28
Ryujinx.Audio/Renderer/Common/PerformanceEntryType.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// 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
|
||||
}
|
||||
}
|
40
Ryujinx.Audio/Renderer/Common/PlayState.cs
Normal file
40
Ryujinx.Audio/Renderer/Common/PlayState.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// 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
|
||||
}
|
||||
}
|
50
Ryujinx.Audio/Renderer/Common/ReverbEarlyMode.cs
Normal file
50
Ryujinx.Audio/Renderer/Common/ReverbEarlyMode.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// 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
|
||||
}
|
||||
}
|
55
Ryujinx.Audio/Renderer/Common/ReverbLateMode.cs
Normal file
55
Ryujinx.Audio/Renderer/Common/ReverbLateMode.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// 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
|
||||
}
|
||||
}
|
40
Ryujinx.Audio/Renderer/Common/SinkType.cs
Normal file
40
Ryujinx.Audio/Renderer/Common/SinkType.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// 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
|
||||
}
|
||||
}
|
50
Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs
Normal file
50
Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// 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>();
|
||||
}
|
||||
}
|
||||
}
|
121
Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs
Normal file
121
Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs
Normal file
|
@ -0,0 +1,121 @@
|
|||
//
|
||||
// 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 * Constants.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 >= Constants.VoiceWaveBufferCount)
|
||||
{
|
||||
waveBufferIndex = 0;
|
||||
}
|
||||
|
||||
if (waveBuffer.IsEndOfStream)
|
||||
{
|
||||
playedSampleCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
99
Ryujinx.Audio/Renderer/Common/WaveBuffer.cs
Normal file
99
Ryujinx.Audio/Renderer/Common/WaveBuffer.cs
Normal file
|
@ -0,0 +1,99 @@
|
|||
//
|
||||
// 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;
|
||||
}
|
||||
}
|
78
Ryujinx.Audio/Renderer/Common/WorkBufferAllocator.cs
Normal file
78
Ryujinx.Audio/Renderer/Common/WorkBufferAllocator.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
//
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue