From 3f4fb8f73a6635dbdca9dd11738c3a793f53ac65 Mon Sep 17 00:00:00 2001 From: Mary Date: Wed, 6 Apr 2022 09:12:38 +0200 Subject: [PATCH] amadeus: Update to REV11 (#3230) This should implement all ABI changes from REV11 on 14.0.0 As Nintendo changed the channel disposition for "legacy" effects (Delay, Reverb and Reverb 3D) to match the standard channel mapping, I took the liberty to just remap to the old disposition for now. The proper changes will be handled at a later date with a complete rewriting of those 3 effects to be more readable (see https://github.com/Ryujinx/Ryujinx/pull/3205 for the first iteration of it). --- .../Renderer/Dsp/Command/DelayCommand.cs | 7 +- .../Renderer/Dsp/Command/Reverb3dCommand.cs | 9 +- .../Renderer/Dsp/Command/ReverbCommand.cs | 9 +- .../Renderer/Dsp/DataSourceHelper.cs | 34 +++ .../Renderer/Dsp/State/Reverb3dState.cs | 4 +- .../Renderer/Dsp/State/ReverbState.cs | 4 +- .../Renderer/Server/AudioRenderSystem.cs | 3 + .../Renderer/Server/BehaviourContext.cs | 24 +- .../Renderer/Server/CommandBuffer.cs | 15 +- .../Renderer/Server/CommandGenerator.cs | 18 +- .../CommandProcessingTimeEstimatorVersion3.cs | 6 +- .../CommandProcessingTimeEstimatorVersion5.cs | 253 ++++++++++++++++++ 12 files changed, 358 insertions(+), 28 deletions(-) create mode 100644 Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs index ace0f2741e..8d416cc328 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs @@ -45,7 +45,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command private const int FixedPointPrecision = 14; - public DelayCommand(uint bufferOffset, DelayParameter parameter, Memory state, bool isEnabled, ulong workBuffer, int nodeId) + public DelayCommand(uint bufferOffset, DelayParameter parameter, Memory state, bool isEnabled, ulong workBuffer, int nodeId, bool newEffectChannelMappingSupported) { Enabled = true; NodeId = nodeId; @@ -63,6 +63,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]); OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]); } + + // NOTE: We do the opposite as Nintendo here for now to restore previous behaviour + // TODO: Update delay processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping. + DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices); + DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/Reverb3dCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/Reverb3dCommand.cs index 7da9804eb7..5cbc10606d 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/Reverb3dCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/Reverb3dCommand.cs @@ -63,7 +63,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command private Reverb3dParameter _parameter; - public Reverb3dCommand(uint bufferOffset, Reverb3dParameter parameter, Memory state, bool isEnabled, ulong workBuffer, int nodeId) + public Reverb3dCommand(uint bufferOffset, Reverb3dParameter parameter, Memory state, bool isEnabled, ulong workBuffer, int nodeId, bool newEffectChannelMappingSupported) { Enabled = true; IsEffectEnabled = isEnabled; @@ -80,6 +80,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]); OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]); } + + // NOTE: We do the opposite as Nintendo here for now to restore previous behaviour + // TODO: Update reverb 3d processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping. + DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices); + DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -194,7 +199,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command if (isSurround) { - *((float*)outputBuffers[4] + sampleIndex) += (outputValues[4] + state.BackLeftDelayLine.Update((values[2] - values[3]) * 0.5f) + channelInput[4] * state.DryGain); + *((float*)outputBuffers[4] + sampleIndex) += (outputValues[4] + state.FrontCenterDelayLine.Update((values[2] - values[3]) * 0.5f) + channelInput[4] * state.DryGain); } } } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs index 1da9c81b33..15c67f1706 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs @@ -66,7 +66,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command private const int FixedPointPrecision = 14; - public ReverbCommand(uint bufferOffset, ReverbParameter parameter, Memory state, bool isEnabled, ulong workBuffer, int nodeId, bool isLongSizePreDelaySupported) + public ReverbCommand(uint bufferOffset, ReverbParameter parameter, Memory state, bool isEnabled, ulong workBuffer, int nodeId, bool isLongSizePreDelaySupported, bool newEffectChannelMappingSupported) { Enabled = true; IsEffectEnabled = isEnabled; @@ -85,6 +85,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command } IsLongSizePreDelaySupported = isLongSizePreDelaySupported; + + // NOTE: We do the opposite as Nintendo here for now to restore previous behaviour + // TODO: Update reverb processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping. + DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices); + DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -214,7 +219,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command if (isSurround) { - outputValues[4] += state.BackLeftDelayLine.Update((feedbackOutputValues[2] - feedbackOutputValues[3]) * 0.5f); + outputValues[4] += state.FrontCenterDelayLine.Update((feedbackOutputValues[2] - feedbackOutputValues[3]) * 0.5f); } for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++) diff --git a/Ryujinx.Audio/Renderer/Dsp/DataSourceHelper.cs b/Ryujinx.Audio/Renderer/Dsp/DataSourceHelper.cs index 4732f504bd..5c413ee16a 100644 --- a/Ryujinx.Audio/Renderer/Dsp/DataSourceHelper.cs +++ b/Ryujinx.Audio/Renderer/Dsp/DataSourceHelper.cs @@ -445,5 +445,39 @@ namespace Ryujinx.Audio.Renderer.Dsp ToIntSlow(output, input, sampleCount); } } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void RemapLegacyChannelEffectMappingToChannelResourceMapping(bool isSupported, Span bufferIndices) + { + if (!isSupported && bufferIndices.Length == 6) + { + ushort backLeft = bufferIndices[2]; + ushort backRight = bufferIndices[3]; + ushort frontCenter = bufferIndices[4]; + ushort lowFrequency = bufferIndices[5]; + + bufferIndices[2] = frontCenter; + bufferIndices[3] = lowFrequency; + bufferIndices[4] = backLeft; + bufferIndices[5] = backRight; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void RemapChannelResourceMappingToLegacy(bool isSupported, Span bufferIndices) + { + if (isSupported && bufferIndices.Length == 6) + { + ushort frontCenter = bufferIndices[2]; + ushort lowFrequency = bufferIndices[3]; + ushort backLeft = bufferIndices[4]; + ushort backRight = bufferIndices[5]; + + bufferIndices[2] = backLeft; + bufferIndices[3] = backRight; + bufferIndices[4] = frontCenter; + bufferIndices[5] = lowFrequency; + } + } } } diff --git a/Ryujinx.Audio/Renderer/Dsp/State/Reverb3dState.cs b/Ryujinx.Audio/Renderer/Dsp/State/Reverb3dState.cs index be0f9734f8..dc7d6efe03 100644 --- a/Ryujinx.Audio/Renderer/Dsp/State/Reverb3dState.cs +++ b/Ryujinx.Audio/Renderer/Dsp/State/Reverb3dState.cs @@ -34,7 +34,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State public DecayDelay[] DecayDelays1 { get; } public DecayDelay[] DecayDelays2 { get; } public IDelayLine PreDelayLine { get; } - public IDelayLine BackLeftDelayLine { get; } + public IDelayLine FrontCenterDelayLine { get; } public float DryGain { get; private set; } public uint[] EarlyDelayTime { get; private set; } public float PreviousPreDelayValue { get; set; } @@ -69,7 +69,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State } PreDelayLine = new DelayLine3d(sampleRate, 400); - BackLeftDelayLine = new DelayLine3d(sampleRate, 5); + FrontCenterDelayLine = new DelayLine3d(sampleRate, 5); UpdateParameter(ref parameter); } diff --git a/Ryujinx.Audio/Renderer/Dsp/State/ReverbState.cs b/Ryujinx.Audio/Renderer/Dsp/State/ReverbState.cs index c75bdce2dc..fc0c6539aa 100644 --- a/Ryujinx.Audio/Renderer/Dsp/State/ReverbState.cs +++ b/Ryujinx.Audio/Renderer/Dsp/State/ReverbState.cs @@ -97,7 +97,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State public DelayLine[] FdnDelayLines { get; } public DecayDelay[] DecayDelays { get; } public DelayLine PreDelayLine { get; } - public DelayLine BackLeftDelayLine { get; } + public DelayLine FrontCenterDelayLine { get; } public uint[] EarlyDelayTime { get; } public float[] EarlyGain { get; } public uint PreDelayLineDelayTime { get; private set; } @@ -149,7 +149,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State } PreDelayLine = new DelayLine(sampleRate, preDelayTimeMax); - BackLeftDelayLine = new DelayLine(sampleRate, 5.0f); + FrontCenterDelayLine = new DelayLine(sampleRate, 5.0f); UpdateParameter(ref parameter); } diff --git a/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs b/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs index 277c2474d7..0c41909e5f 100644 --- a/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs +++ b/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs @@ -363,6 +363,9 @@ namespace Ryujinx.Audio.Renderer.Server case 4: _commandProcessingTimeEstimator = new CommandProcessingTimeEstimatorVersion4(_sampleCount, _mixBufferCount); break; + case 5: + _commandProcessingTimeEstimator = new CommandProcessingTimeEstimatorVersion5(_sampleCount, _mixBufferCount); + break; default: throw new NotImplementedException($"Unsupported processing time estimator version {_behaviourContext.GetCommandProcessingTimeEstimatorVersion()}."); } diff --git a/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs b/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs index d3a65b7257..cf9cda0ba8 100644 --- a/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs +++ b/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs @@ -107,10 +107,18 @@ namespace Ryujinx.Audio.Renderer.Server /// This was added in system update 13.0.0 public const int Revision10 = 10 << 24; + /// + /// REV11: + /// The "legacy" effects (Delay, Reverb and Reverb 3D) were updated to match the standard channel mapping used by the audio renderer. + /// A new version of the command estimator was added to address timing changes caused by the legacy effects changes. + /// + /// This was added in system update 14.0.0 + public const int Revision11 = 11 << 24; + /// /// Last revision supported by the implementation. /// - public const int LastRevision = Revision10; + public const int LastRevision = Revision11; /// /// Target revision magic supported by the implementation. @@ -366,12 +374,26 @@ namespace Ryujinx.Audio.Renderer.Server return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision10); } + /// + /// Check if the audio renderer should support new channel resource mapping for 5.1 on Delay, Reverb and Reverb 3D effects. + /// + /// True if the audio renderer support new channel resource mapping for 5.1. + public bool IsNewEffectChannelMappingSupported() + { + return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision11); + } + /// /// Get the version of the . /// /// The version of the . public int GetCommandProcessingTimeEstimatorVersion() { + if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision11)) + { + return 5; + } + if (CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision10)) { return 4; diff --git a/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs b/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs index 0e74c301e8..c3aae96ded 100644 --- a/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs +++ b/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs @@ -336,11 +336,12 @@ namespace Ryujinx.Audio.Renderer.Server /// The work buffer to use for processing. /// The node id associated to this command. /// If set to true, the long size pre-delay is supported. - public void GenerateReverbEffect(uint bufferOffset, ReverbParameter parameter, Memory state, bool isEnabled, CpuAddress workBuffer, int nodeId, bool isLongSizePreDelaySupported) + /// If set to true, the new effect channel mapping for 5.1 is supported. + public void GenerateReverbEffect(uint bufferOffset, ReverbParameter parameter, Memory state, bool isEnabled, CpuAddress workBuffer, int nodeId, bool isLongSizePreDelaySupported, bool newEffectChannelMappingSupported) { if (parameter.IsChannelCountValid()) { - ReverbCommand command = new ReverbCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, isLongSizePreDelaySupported); + ReverbCommand command = new ReverbCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, isLongSizePreDelaySupported, newEffectChannelMappingSupported); command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); @@ -357,11 +358,12 @@ namespace Ryujinx.Audio.Renderer.Server /// Set to true if the effect should be active. /// The work buffer to use for processing. /// The node id associated to this command. - public void GenerateReverb3dEffect(uint bufferOffset, Reverb3dParameter parameter, Memory state, bool isEnabled, CpuAddress workBuffer, int nodeId) + /// If set to true, the new effect channel mapping for 5.1 is supported. + public void GenerateReverb3dEffect(uint bufferOffset, Reverb3dParameter parameter, Memory state, bool isEnabled, CpuAddress workBuffer, int nodeId, bool newEffectChannelMappingSupported) { if (parameter.IsChannelCountValid()) { - Reverb3dCommand command = new Reverb3dCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId); + Reverb3dCommand command = new Reverb3dCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, newEffectChannelMappingSupported); command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); @@ -379,11 +381,12 @@ namespace Ryujinx.Audio.Renderer.Server /// Set to true if the effect should be active. /// The work buffer to use for processing. /// The node id associated to this command. - public void GenerateDelayEffect(uint bufferOffset, DelayParameter parameter, Memory state, bool isEnabled, CpuAddress workBuffer, int nodeId) + /// If set to true, the new effect channel mapping for 5.1 is supported. + public void GenerateDelayEffect(uint bufferOffset, DelayParameter parameter, Memory state, bool isEnabled, CpuAddress workBuffer, int nodeId, bool newEffectChannelMappingSupported) { if (parameter.IsChannelCountValid()) { - DelayCommand command = new DelayCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId); + DelayCommand command = new DelayCommand(bufferOffset, parameter, state, isEnabled, workBuffer, nodeId, newEffectChannelMappingSupported); command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); diff --git a/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs b/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs index 85c019c251..8194ebf13c 100644 --- a/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs +++ b/Ryujinx.Audio/Renderer/Server/CommandGenerator.cs @@ -483,31 +483,31 @@ namespace Ryujinx.Audio.Renderer.Server } } - private void GenerateDelayEffect(uint bufferOffset, DelayEffect effect, int nodeId) + private void GenerateDelayEffect(uint bufferOffset, DelayEffect effect, int nodeId, bool newEffectChannelMappingSupported) { Debug.Assert(effect.Type == EffectType.Delay); ulong workBuffer = effect.GetWorkBuffer(-1); - _commandBuffer.GenerateDelayEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId); + _commandBuffer.GenerateDelayEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId, newEffectChannelMappingSupported); } - private void GenerateReverbEffect(uint bufferOffset, ReverbEffect effect, int nodeId, bool isLongSizePreDelaySupported) + private void GenerateReverbEffect(uint bufferOffset, ReverbEffect effect, int nodeId, bool isLongSizePreDelaySupported, bool newEffectChannelMappingSupported) { Debug.Assert(effect.Type == EffectType.Reverb); ulong workBuffer = effect.GetWorkBuffer(-1); - _commandBuffer.GenerateReverbEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId, isLongSizePreDelaySupported); + _commandBuffer.GenerateReverbEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId, isLongSizePreDelaySupported, newEffectChannelMappingSupported); } - private void GenerateReverb3dEffect(uint bufferOffset, Reverb3dEffect effect, int nodeId) + private void GenerateReverb3dEffect(uint bufferOffset, Reverb3dEffect effect, int nodeId, bool newEffectChannelMappingSupported) { Debug.Assert(effect.Type == EffectType.Reverb3d); ulong workBuffer = effect.GetWorkBuffer(-1); - _commandBuffer.GenerateReverb3dEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId); + _commandBuffer.GenerateReverb3dEffect(bufferOffset, effect.Parameter, effect.State, effect.IsEnabled, workBuffer, nodeId, newEffectChannelMappingSupported); } private void GenerateBiquadFilterEffect(uint bufferOffset, BiquadFilterEffect effect, int nodeId) @@ -650,13 +650,13 @@ namespace Ryujinx.Audio.Renderer.Server GenerateAuxEffect(mix.BufferOffset, (AuxiliaryBufferEffect)effect, nodeId); break; case EffectType.Delay: - GenerateDelayEffect(mix.BufferOffset, (DelayEffect)effect, nodeId); + GenerateDelayEffect(mix.BufferOffset, (DelayEffect)effect, nodeId, _rendererContext.BehaviourContext.IsNewEffectChannelMappingSupported()); break; case EffectType.Reverb: - GenerateReverbEffect(mix.BufferOffset, (ReverbEffect)effect, nodeId, mix.IsLongSizePreDelaySupported); + GenerateReverbEffect(mix.BufferOffset, (ReverbEffect)effect, nodeId, mix.IsLongSizePreDelaySupported, _rendererContext.BehaviourContext.IsNewEffectChannelMappingSupported()); break; case EffectType.Reverb3d: - GenerateReverb3dEffect(mix.BufferOffset, (Reverb3dEffect)effect, nodeId); + GenerateReverb3dEffect(mix.BufferOffset, (Reverb3dEffect)effect, nodeId, _rendererContext.BehaviourContext.IsNewEffectChannelMappingSupported()); break; case EffectType.BiquadFilter: GenerateBiquadFilterEffect(mix.BufferOffset, (BiquadFilterEffect)effect, nodeId); diff --git a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs index 75d3d05bce..d9afdfb093 100644 --- a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs +++ b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs @@ -198,7 +198,7 @@ namespace Ryujinx.Audio.Renderer.Server return (uint)1853.2f; } - public uint Estimate(DelayCommand command) + public virtual uint Estimate(DelayCommand command) { Debug.Assert(_sampleCount == 160 || _sampleCount == 240); @@ -272,7 +272,7 @@ namespace Ryujinx.Audio.Renderer.Server } } - public uint Estimate(ReverbCommand command) + public virtual uint Estimate(ReverbCommand command) { Debug.Assert(_sampleCount == 160 || _sampleCount == 240); @@ -346,7 +346,7 @@ namespace Ryujinx.Audio.Renderer.Server } } - public uint Estimate(Reverb3dCommand command) + public virtual uint Estimate(Reverb3dCommand command) { Debug.Assert(_sampleCount == 160 || _sampleCount == 240); diff --git a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs new file mode 100644 index 0000000000..6b55a909cd --- /dev/null +++ b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs @@ -0,0 +1,253 @@ +// +// Copyright (c) 2019-2022 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 . +// + +using Ryujinx.Audio.Renderer.Dsp.Command; +using System; +using System.Diagnostics; + +namespace Ryujinx.Audio.Renderer.Server +{ + /// + /// version 5. (added with REV11) + /// + public class CommandProcessingTimeEstimatorVersion5 : CommandProcessingTimeEstimatorVersion4 + { + public CommandProcessingTimeEstimatorVersion5(uint sampleCount, uint bufferCount) : base(sampleCount, bufferCount) { } + + public override uint Estimate(DelayCommand command) + { + Debug.Assert(_sampleCount == 160 || _sampleCount == 240); + + if (_sampleCount == 160) + { + if (command.Enabled) + { + switch (command.Parameter.ChannelCount) + { + case 1: + return 8929; + case 2: + return 25501; + case 4: + return 47760; + case 6: + return 82203; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + else + { + switch (command.Parameter.ChannelCount) + { + case 1: + return (uint)1295.20f; + case 2: + return (uint)1213.60f; + case 4: + return (uint)942.03f; + case 6: + return (uint)1001.6f; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + } + + if (command.Enabled) + { + switch (command.Parameter.ChannelCount) + { + case 1: + return 11941; + case 2: + return 37197; + case 4: + return 69750; + case 6: + return 12004; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + else + { + switch (command.Parameter.ChannelCount) + { + case 1: + return (uint)997.67f; + case 2: + return (uint)977.63f; + case 4: + return (uint)792.31f; + case 6: + return (uint)875.43f; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + } + + public override uint Estimate(ReverbCommand command) + { + Debug.Assert(_sampleCount == 160 || _sampleCount == 240); + + if (_sampleCount == 160) + { + if (command.Enabled) + { + switch (command.Parameter.ChannelCount) + { + case 1: + return 81475; + case 2: + return 84975; + case 4: + return 91625; + case 6: + return 95332; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + else + { + switch (command.Parameter.ChannelCount) + { + case 1: + return (uint)536.30f; + case 2: + return (uint)588.80f; + case 4: + return (uint)643.70f; + case 6: + return (uint)706.0f; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + } + + if (command.Enabled) + { + switch (command.Parameter.ChannelCount) + { + case 1: + return 120170; + case 2: + return 125260; + case 4: + return 135750; + case 6: + return 141130; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + else + { + switch (command.Parameter.ChannelCount) + { + case 1: + return (uint)617.64f; + case 2: + return (uint)659.54f; + case 4: + return (uint)711.44f; + case 6: + return (uint)778.07f; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + } + + public override uint Estimate(Reverb3dCommand command) + { + Debug.Assert(_sampleCount == 160 || _sampleCount == 240); + + if (_sampleCount == 160) + { + if (command.Enabled) + { + switch (command.Parameter.ChannelCount) + { + case 1: + return 116750; + case 2: + return 125910; + case 4: + return 146340; + case 6: + return 165810; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + else + { + switch (command.Parameter.ChannelCount) + { + case 1: + return 735; + case 2: + return (uint)766.62f; + case 4: + return (uint)834.07f; + case 6: + return (uint)875.44f; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + } + + if (command.Enabled) + { + switch (command.Parameter.ChannelCount) + { + case 1: + return 170290; + case 2: + return 183880; + case 4: + return 214700; + case 6: + return 243850; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + else + { + switch (command.Parameter.ChannelCount) + { + case 1: + return (uint)508.47f; + case 2: + return (uint)582.45f; + case 4: + return (uint)626.42f; + case 6: + return (uint)682.47f; + default: + throw new NotImplementedException($"{command.Parameter.ChannelCount}"); + } + } + } + } +}