SplitterDestination.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. using Ryujinx.Audio.Renderer.Parameter;
  2. using Ryujinx.Common.Utilities;
  3. using System;
  4. using System.Diagnostics;
  5. using System.Runtime.InteropServices;
  6. namespace Ryujinx.Audio.Renderer.Server.Splitter
  7. {
  8. /// <summary>
  9. /// Server state for a splitter destination.
  10. /// </summary>
  11. [StructLayout(LayoutKind.Sequential, Size = 0xE0, Pack = Alignment)]
  12. public struct SplitterDestination
  13. {
  14. public const int Alignment = 0x10;
  15. /// <summary>
  16. /// The unique id of this <see cref="SplitterDestination"/>.
  17. /// </summary>
  18. public int Id;
  19. /// <summary>
  20. /// The mix to output the result of the splitter.
  21. /// </summary>
  22. public int DestinationId;
  23. /// <summary>
  24. /// Mix buffer volumes storage.
  25. /// </summary>
  26. private MixArray _mix;
  27. private MixArray _previousMix;
  28. /// <summary>
  29. /// Pointer to the next linked element.
  30. /// </summary>
  31. private unsafe SplitterDestination* _next;
  32. /// <summary>
  33. /// Set to true if in use.
  34. /// </summary>
  35. [MarshalAs(UnmanagedType.I1)]
  36. public bool IsUsed;
  37. /// <summary>
  38. /// Set to true if the internal state need to be updated.
  39. /// </summary>
  40. [MarshalAs(UnmanagedType.I1)]
  41. public bool NeedToUpdateInternalState;
  42. [StructLayout(LayoutKind.Sequential, Size = 4 * Constants.MixBufferCountMax, Pack = 1)]
  43. private struct MixArray { }
  44. /// <summary>
  45. /// Mix buffer volumes.
  46. /// </summary>
  47. /// <remarks>Used when a splitter id is specified in the mix.</remarks>
  48. public Span<float> MixBufferVolume => SpanHelpers.AsSpan<MixArray, float>(ref _mix);
  49. /// <summary>
  50. /// Previous mix buffer volumes.
  51. /// </summary>
  52. /// <remarks>Used when a splitter id is specified in the mix.</remarks>
  53. public Span<float> PreviousMixBufferVolume => SpanHelpers.AsSpan<MixArray, float>(ref _previousMix);
  54. /// <summary>
  55. /// Get the <see cref="Span{SplitterDestination}"/> of the next element or <see cref="Span{SplitterDestination}.Empty"/> if not present.
  56. /// </summary>
  57. public Span<SplitterDestination> Next
  58. {
  59. get
  60. {
  61. unsafe
  62. {
  63. return _next != null ? new Span<SplitterDestination>(_next, 1) : Span<SplitterDestination>.Empty;
  64. }
  65. }
  66. }
  67. /// <summary>
  68. /// Create a new <see cref="SplitterDestination"/>.
  69. /// </summary>
  70. /// <param name="id">The unique id of this <see cref="SplitterDestination"/>.</param>
  71. public SplitterDestination(int id) : this()
  72. {
  73. Id = id;
  74. DestinationId = Constants.UnusedMixId;
  75. ClearVolumes();
  76. }
  77. /// <summary>
  78. /// Update the <see cref="SplitterDestination"/> from user parameter.
  79. /// </summary>
  80. /// <param name="parameter">The user parameter.</param>
  81. public void Update(SplitterDestinationInParameter parameter)
  82. {
  83. Debug.Assert(Id == parameter.Id);
  84. if (parameter.IsMagicValid() && Id == parameter.Id)
  85. {
  86. DestinationId = parameter.DestinationId;
  87. parameter.MixBufferVolume.CopyTo(MixBufferVolume);
  88. if (!IsUsed && parameter.IsUsed)
  89. {
  90. MixBufferVolume.CopyTo(PreviousMixBufferVolume);
  91. NeedToUpdateInternalState = false;
  92. }
  93. IsUsed = parameter.IsUsed;
  94. }
  95. }
  96. /// <summary>
  97. /// Update the internal state of the instance.
  98. /// </summary>
  99. public void UpdateInternalState()
  100. {
  101. if (IsUsed && NeedToUpdateInternalState)
  102. {
  103. MixBufferVolume.CopyTo(PreviousMixBufferVolume);
  104. }
  105. NeedToUpdateInternalState = false;
  106. }
  107. /// <summary>
  108. /// Set the update internal state marker.
  109. /// </summary>
  110. public void MarkAsNeedToUpdateInternalState()
  111. {
  112. NeedToUpdateInternalState = true;
  113. }
  114. /// <summary>
  115. /// Return true if the <see cref="SplitterDestination"/> is used and has a destination.
  116. /// </summary>
  117. /// <returns>True if the <see cref="SplitterDestination"/> is used and has a destination.</returns>
  118. public bool IsConfigured()
  119. {
  120. return IsUsed && DestinationId != Constants.UnusedMixId;
  121. }
  122. /// <summary>
  123. /// Get the volume for a given destination.
  124. /// </summary>
  125. /// <param name="destinationIndex">The destination index to use.</param>
  126. /// <returns>The volume for the given destination.</returns>
  127. public float GetMixVolume(int destinationIndex)
  128. {
  129. Debug.Assert(destinationIndex >= 0 && destinationIndex < Constants.MixBufferCountMax);
  130. return MixBufferVolume[destinationIndex];
  131. }
  132. /// <summary>
  133. /// Clear the volumes.
  134. /// </summary>
  135. public void ClearVolumes()
  136. {
  137. MixBufferVolume.Fill(0);
  138. PreviousMixBufferVolume.Fill(0);
  139. }
  140. /// <summary>
  141. /// Link the next element to the given <see cref="SplitterDestination"/>.
  142. /// </summary>
  143. /// <param name="next">The given <see cref="SplitterDestination"/> to link.</param>
  144. public void Link(ref SplitterDestination next)
  145. {
  146. unsafe
  147. {
  148. fixed (SplitterDestination* nextPtr = &next)
  149. {
  150. _next = nextPtr;
  151. }
  152. }
  153. }
  154. /// <summary>
  155. /// Remove the link to the next element.
  156. /// </summary>
  157. public void Unlink()
  158. {
  159. unsafe
  160. {
  161. _next = null;
  162. }
  163. }
  164. }
  165. }