CompressorCommand.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. using System;
  2. using System.Diagnostics;
  3. using Ryujinx.Audio.Renderer.Dsp.Effect;
  4. using Ryujinx.Audio.Renderer.Dsp.State;
  5. using Ryujinx.Audio.Renderer.Parameter.Effect;
  6. namespace Ryujinx.Audio.Renderer.Dsp.Command
  7. {
  8. public class CompressorCommand : ICommand
  9. {
  10. private const int FixedPointPrecision = 15;
  11. public bool Enabled { get; set; }
  12. public int NodeId { get; }
  13. public CommandType CommandType => CommandType.Compressor;
  14. public uint EstimatedProcessingTime { get; set; }
  15. public CompressorParameter Parameter => _parameter;
  16. public Memory<CompressorState> State { get; }
  17. public ushort[] OutputBufferIndices { get; }
  18. public ushort[] InputBufferIndices { get; }
  19. public bool IsEffectEnabled { get; }
  20. private CompressorParameter _parameter;
  21. public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
  22. {
  23. Enabled = true;
  24. NodeId = nodeId;
  25. _parameter = parameter;
  26. State = state;
  27. IsEffectEnabled = isEnabled;
  28. InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
  29. OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
  30. for (int i = 0; i < _parameter.ChannelCount; i++)
  31. {
  32. InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
  33. OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
  34. }
  35. }
  36. public void Process(CommandList context)
  37. {
  38. ref CompressorState state = ref State.Span[0];
  39. if (IsEffectEnabled)
  40. {
  41. if (_parameter.Status == Server.Effect.UsageState.Invalid)
  42. {
  43. state = new CompressorState(ref _parameter);
  44. }
  45. else if (_parameter.Status == Server.Effect.UsageState.New)
  46. {
  47. state.UpdateParameter(ref _parameter);
  48. }
  49. }
  50. ProcessCompressor(context, ref state);
  51. }
  52. private unsafe void ProcessCompressor(CommandList context, ref CompressorState state)
  53. {
  54. Debug.Assert(_parameter.IsChannelCountValid());
  55. if (IsEffectEnabled && _parameter.IsChannelCountValid())
  56. {
  57. Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
  58. Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
  59. Span<float> channelInput = stackalloc float[Parameter.ChannelCount];
  60. ExponentialMovingAverage inputMovingAverage = state.InputMovingAverage;
  61. float unknown4 = state.Unknown4;
  62. ExponentialMovingAverage compressionGainAverage = state.CompressionGainAverage;
  63. float previousCompressionEmaAlpha = state.PreviousCompressionEmaAlpha;
  64. for (int i = 0; i < _parameter.ChannelCount; i++)
  65. {
  66. inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]);
  67. outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]);
  68. }
  69. for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
  70. {
  71. for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
  72. {
  73. channelInput[channelIndex] = *((float*)inputBuffers[channelIndex] + sampleIndex);
  74. }
  75. float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain);
  76. float y = FloatingPointHelper.Log10(newMean) * 10.0f;
  77. float z = 0.0f;
  78. bool unknown10OutOfRange = false;
  79. if (newMean < 1.0e-10f)
  80. {
  81. z = 1.0f;
  82. unknown10OutOfRange = state.Unknown10 < -100.0f;
  83. }
  84. if (y >= state.Unknown10 || unknown10OutOfRange)
  85. {
  86. float tmpGain;
  87. if (y >= state.Unknown14)
  88. {
  89. tmpGain = ((1.0f / Parameter.Ratio) - 1.0f) * (y - Parameter.Threshold);
  90. }
  91. else
  92. {
  93. tmpGain = (y - state.Unknown10) * ((y - state.Unknown10) * -state.CompressorGainReduction);
  94. }
  95. z = FloatingPointHelper.DecibelToLinearExtended(tmpGain);
  96. }
  97. float unknown4New = z;
  98. float compressionEmaAlpha;
  99. if ((unknown4 - z) <= 0.08f)
  100. {
  101. compressionEmaAlpha = Parameter.ReleaseCoefficient;
  102. if ((unknown4 - z) >= -0.08f)
  103. {
  104. if (MathF.Abs(compressionGainAverage.Read() - z) >= 0.001f)
  105. {
  106. unknown4New = unknown4;
  107. }
  108. compressionEmaAlpha = previousCompressionEmaAlpha;
  109. }
  110. }
  111. else
  112. {
  113. compressionEmaAlpha = Parameter.AttackCoefficient;
  114. }
  115. float compressionGain = compressionGainAverage.Update(z, compressionEmaAlpha);
  116. for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
  117. {
  118. *((float*)outputBuffers[channelIndex] + sampleIndex) = channelInput[channelIndex] * compressionGain * state.OutputGain;
  119. }
  120. unknown4 = unknown4New;
  121. previousCompressionEmaAlpha = compressionEmaAlpha;
  122. }
  123. state.InputMovingAverage = inputMovingAverage;
  124. state.Unknown4 = unknown4;
  125. state.CompressionGainAverage = compressionGainAverage;
  126. state.PreviousCompressionEmaAlpha = previousCompressionEmaAlpha;
  127. }
  128. else
  129. {
  130. for (int i = 0; i < Parameter.ChannelCount; i++)
  131. {
  132. if (InputBufferIndices[i] != OutputBufferIndices[i])
  133. {
  134. context.CopyBuffer(OutputBufferIndices[i], InputBufferIndices[i]);
  135. }
  136. }
  137. }
  138. }
  139. }
  140. }