SplitterState.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. //
  2. // Copyright (c) 2019-2020 Ryujinx
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. //
  17. using Ryujinx.Audio.Renderer.Parameter;
  18. using System;
  19. using System.Buffers;
  20. using System.Diagnostics;
  21. using System.Runtime.InteropServices;
  22. namespace Ryujinx.Audio.Renderer.Server.Splitter
  23. {
  24. /// <summary>
  25. /// Server state for a splitter.
  26. /// </summary>
  27. [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = Alignment)]
  28. public struct SplitterState
  29. {
  30. public const int Alignment = 0x10;
  31. /// <summary>
  32. /// The unique id of this <see cref="SplitterState"/>.
  33. /// </summary>
  34. public int Id;
  35. /// <summary>
  36. /// Target sample rate to use on the splitter.
  37. /// </summary>
  38. public uint SampleRate;
  39. /// <summary>
  40. /// Count of splitter destinations (<see cref="SplitterDestination"/>).
  41. /// </summary>
  42. public int DestinationCount;
  43. /// <summary>
  44. /// Set to true if the splitter has a new connection.
  45. /// </summary>
  46. [MarshalAs(UnmanagedType.I1)]
  47. public bool HasNewConnection;
  48. /// <summary>
  49. /// Linked list of <see cref="SplitterDestination"/>.
  50. /// </summary>
  51. private unsafe SplitterDestination* _destinationsData;
  52. /// <summary>
  53. /// Span to the first element of the linked list of <see cref="SplitterDestination"/>.
  54. /// </summary>
  55. public Span<SplitterDestination> Destinations
  56. {
  57. get
  58. {
  59. unsafe
  60. {
  61. return (IntPtr)_destinationsData != IntPtr.Zero ? new Span<SplitterDestination>(_destinationsData, 1) : Span<SplitterDestination>.Empty;
  62. }
  63. }
  64. }
  65. /// <summary>
  66. /// Create a new <see cref="SplitterState"/>.
  67. /// </summary>
  68. /// <param name="id">The unique id of this <see cref="SplitterState"/>.</param>
  69. public SplitterState(int id) : this()
  70. {
  71. Id = id;
  72. }
  73. public Span<SplitterDestination> GetData(int index)
  74. {
  75. int i = 0;
  76. Span<SplitterDestination> result = Destinations;
  77. while (i < index)
  78. {
  79. if (result.IsEmpty)
  80. {
  81. break;
  82. }
  83. result = result[0].Next;
  84. i++;
  85. }
  86. return result;
  87. }
  88. /// <summary>
  89. /// Clear the new connection flag.
  90. /// </summary>
  91. public void ClearNewConnectionFlag()
  92. {
  93. HasNewConnection = false;
  94. }
  95. /// <summary>
  96. /// Utility function to apply a given <see cref="SpanAction{T, TArg}"/> to all <see cref="Destinations"/>.
  97. /// </summary>
  98. /// <param name="action">The action to execute on each elements.</param>
  99. private void ForEachDestination(SpanAction<SplitterDestination, int> action)
  100. {
  101. Span<SplitterDestination> temp = Destinations;
  102. int i = 0;
  103. while (true)
  104. {
  105. if (temp.IsEmpty)
  106. {
  107. break;
  108. }
  109. Span<SplitterDestination> next = temp[0].Next;
  110. action.Invoke(temp, i++);
  111. temp = next;
  112. }
  113. }
  114. /// <summary>
  115. /// Update the <see cref="SplitterState"/> from user parameter.
  116. /// </summary>
  117. /// <param name="context">The splitter context.</param>
  118. /// <param name="parameter">The user parameter.</param>
  119. /// <param name="input">The raw input data after the <paramref name="parameter"/>.</param>
  120. public void Update(SplitterContext context, ref SplitterInParameter parameter, ReadOnlySpan<byte> input)
  121. {
  122. ClearLinks();
  123. int destinationCount;
  124. if (context.IsBugFixed)
  125. {
  126. destinationCount = parameter.DestinationCount;
  127. }
  128. else
  129. {
  130. destinationCount = Math.Min(context.GetDestinationCountPerStateForCompatibility(), parameter.DestinationCount);
  131. }
  132. if (destinationCount > 0)
  133. {
  134. ReadOnlySpan<int> destinationIds = MemoryMarshal.Cast<byte, int>(input);
  135. Memory<SplitterDestination> destination = context.GetDestinationMemory(destinationIds[0]);
  136. SetDestination(ref destination.Span[0]);
  137. DestinationCount = destinationCount;
  138. for (int i = 1; i < destinationCount; i++)
  139. {
  140. Memory<SplitterDestination> nextDestination = context.GetDestinationMemory(destinationIds[i]);
  141. destination.Span[0].Link(ref nextDestination.Span[0]);
  142. destination = nextDestination;
  143. }
  144. }
  145. Debug.Assert(parameter.Id == Id);
  146. if (parameter.Id == Id)
  147. {
  148. SampleRate = parameter.SampleRate;
  149. HasNewConnection = true;
  150. }
  151. }
  152. /// <summary>
  153. /// Set the head of the linked list of <see cref="Destinations"/>.
  154. /// </summary>
  155. /// <param name="newValue">A reference to a <see cref="SplitterDestination"/>.</param>
  156. public void SetDestination(ref SplitterDestination newValue)
  157. {
  158. unsafe
  159. {
  160. fixed (SplitterDestination* newValuePtr = &newValue)
  161. {
  162. _destinationsData = newValuePtr;
  163. }
  164. }
  165. }
  166. /// <summary>
  167. /// Update the internal state of this instance.
  168. /// </summary>
  169. public void UpdateInternalState()
  170. {
  171. ForEachDestination((destination, _) => destination[0].UpdateInternalState());
  172. }
  173. /// <summary>
  174. /// Clear all links from the <see cref="Destinations"/>.
  175. /// </summary>
  176. public void ClearLinks()
  177. {
  178. ForEachDestination((destination, _) => destination[0].Unlink());
  179. unsafe
  180. {
  181. _destinationsData = (SplitterDestination*)IntPtr.Zero;
  182. }
  183. }
  184. /// <summary>
  185. /// Initialize a given <see cref="Span{SplitterState}"/>.
  186. /// </summary>
  187. /// <param name="splitters">All the <see cref="SplitterState"/> to initialize.</param>
  188. public static void InitializeSplitters(Span<SplitterState> splitters)
  189. {
  190. foreach (ref SplitterState splitter in splitters)
  191. {
  192. unsafe
  193. {
  194. splitter._destinationsData = (SplitterDestination*)IntPtr.Zero;
  195. }
  196. splitter.DestinationCount = 0;
  197. }
  198. }
  199. }
  200. }