| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- //
- // 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;
- }
- }
- }
- }
|