amadeus: Add missing compressor effect from REV11 (#4010)

* amadeus: Add missing compressor effect from REV11

This was in my reversing notes but seems I completely forgot to
implement it

Also took the opportunity to simplify the Limiter effect a bit.

* Remove some outdated comment

* Address gdkchan's comments
This commit is contained in:
Mary-nyan 2022-12-06 15:04:25 +01:00 committed by GitHub
parent dde9bb5c69
commit 40311310d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 658 additions and 27 deletions

View file

@ -44,7 +44,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <see cref="Parameter.RendererInfoOutStatus"/> was added to supply the count of update done sent to the DSP.
/// A new version of the command estimator was added to address timing changes caused by the voice changes.
/// Additionally, the rendering limit percent was incremented to 80%.
///
///
/// </summary>
/// <remarks>This was added in system update 6.0.0</remarks>
public const int Revision5 = 5 << 24;
@ -93,6 +93,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <summary>
/// REV11:
/// The "legacy" effects (Delay, Reverb and Reverb 3D) were updated to match the standard channel mapping used by the audio renderer.
/// A new effect was added: Compressor. This effect is effectively implemented with a DRC.
/// A new version of the command estimator was added to address timing changes caused by the legacy effects changes.
/// A voice drop parameter was added in 15.0.0: This allows an application to amplify or attenuate the estimated time of DSP commands.
/// </summary>

View file

@ -469,6 +469,18 @@ namespace Ryujinx.Audio.Renderer.Server
}
}
public void GenerateCompressorEffect(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
{
if (parameter.IsChannelCountValid())
{
CompressorCommand command = new CompressorCommand(bufferOffset, parameter, state, isEnabled, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
AddCommand(command);
}
}
/// <summary>
/// Generate a new <see cref="VolumeCommand"/>.
/// </summary>

View file

@ -606,6 +606,17 @@ namespace Ryujinx.Audio.Renderer.Server
}
}
private void GenerateCompressorEffect(uint bufferOffset, CompressorEffect effect, int nodeId)
{
Debug.Assert(effect.Type == EffectType.Compressor);
_commandBuffer.GenerateCompressorEffect(bufferOffset,
effect.Parameter,
effect.State,
effect.IsEnabled,
nodeId);
}
private void GenerateEffect(ref MixState mix, int effectId, BaseEffect effect)
{
int nodeId = mix.NodeId;
@ -650,6 +661,9 @@ namespace Ryujinx.Audio.Renderer.Server
case EffectType.CaptureBuffer:
GenerateCaptureEffect(mix.BufferOffset, (CaptureBufferEffect)effect, nodeId);
break;
case EffectType.Compressor:
GenerateCompressorEffect(mix.BufferOffset, (CompressorEffect)effect, nodeId);
break;
default:
throw new NotImplementedException($"Unsupported effect type {effect.Type}");
}

View file

@ -179,5 +179,10 @@ namespace Ryujinx.Audio.Renderer.Server
{
return 0;
}
public uint Estimate(CompressorCommand command)
{
return 0;
}
}
}

View file

@ -543,5 +543,10 @@ namespace Ryujinx.Audio.Renderer.Server
{
return 0;
}
public uint Estimate(CompressorCommand command)
{
return 0;
}
}
}

View file

@ -747,5 +747,10 @@ namespace Ryujinx.Audio.Renderer.Server
{
return 0;
}
public virtual uint Estimate(CompressorCommand command)
{
return 0;
}
}
}

View file

@ -232,5 +232,79 @@ namespace Ryujinx.Audio.Renderer.Server
}
}
}
public override uint Estimate(CompressorCommand command)
{
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
if (_sampleCount == 160)
{
if (command.Enabled)
{
switch (command.Parameter.ChannelCount)
{
case 1:
return 34431;
case 2:
return 44253;
case 4:
return 63827;
case 6:
return 83361;
default:
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
}
}
else
{
switch (command.Parameter.ChannelCount)
{
case 1:
return (uint)630.12f;
case 2:
return (uint)638.27f;
case 4:
return (uint)705.86f;
case 6:
return (uint)782.02f;
default:
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
}
}
}
if (command.Enabled)
{
switch (command.Parameter.ChannelCount)
{
case 1:
return 51095;
case 2:
return 65693;
case 4:
return 95383;
case 6:
return 124510;
default:
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
}
}
else
{
switch (command.Parameter.ChannelCount)
{
case 1:
return (uint)840.14f;
case 2:
return (uint)826.1f;
case 4:
return (uint)901.88f;
case 6:
return (uint)965.29f;
default:
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
}
}
}
}
}

View file

@ -262,6 +262,8 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
return PerformanceDetailType.Limiter;
case EffectType.CaptureBuffer:
return PerformanceDetailType.CaptureBuffer;
case EffectType.Compressor:
return PerformanceDetailType.Compressor;
default:
throw new NotImplementedException($"{Type}");
}

View file

@ -0,0 +1,67 @@
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Audio.Renderer.Dsp.State;
using Ryujinx.Audio.Renderer.Parameter.Effect;
using Ryujinx.Audio.Renderer.Parameter;
using Ryujinx.Audio.Renderer.Server.MemoryPool;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Server.Effect
{
/// <summary>
/// Server state for a compressor effect.
/// </summary>
public class CompressorEffect : BaseEffect
{
/// <summary>
/// The compressor parameter.
/// </summary>
public CompressorParameter Parameter;
/// <summary>
/// The compressor state.
/// </summary>
public Memory<CompressorState> State { get; }
/// <summary>
/// Create a new <see cref="CompressorEffect"/>.
/// </summary>
public CompressorEffect()
{
State = new CompressorState[1];
}
public override EffectType TargetEffectType => EffectType.Compressor;
public override ulong GetWorkBuffer(int index)
{
return GetSingleBuffer();
}
public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper)
{
// Nintendo doesn't do anything here but we still require updateErrorInfo to be initialised.
updateErrorInfo = new BehaviourParameter.ErrorInfo();
}
public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper)
{
Debug.Assert(IsTypeValid(ref parameter));
UpdateParameterBase(ref parameter);
Parameter = MemoryMarshal.Cast<byte, CompressorParameter>(parameter.SpecificData)[0];
IsEnabled = parameter.IsEnabled;
updateErrorInfo = new BehaviourParameter.ErrorInfo();
}
public override void UpdateForCommandGeneration()
{
UpdateUsageStateForCommandGeneration();
Parameter.Status = UsageState.Enabled;
}
}
}

View file

@ -35,5 +35,6 @@ namespace Ryujinx.Audio.Renderer.Server
uint Estimate(LimiterCommandVersion2 command);
uint Estimate(GroupedBiquadFilterCommand command);
uint Estimate(CaptureBufferCommand command);
uint Estimate(CompressorCommand command);
}
}

View file

@ -240,6 +240,10 @@ namespace Ryujinx.Audio.Renderer.Server
case EffectType.CaptureBuffer:
effect = new CaptureBufferEffect();
break;
case EffectType.Compressor:
effect = new CompressorEffect();
break;
default:
throw new NotImplementedException($"EffectType {parameter.Type} not implemented!");
}