From dff138229c79483c189be6f3829ed88a5f95575d Mon Sep 17 00:00:00 2001 From: Mary-nyan Date: Mon, 28 Nov 2022 08:28:45 +0100 Subject: [PATCH] amadeus: Fixes and initial 15.0.0 support (#3908) * amadeus: Allow OOB read of GC-ADPCM coefficients Fixes "Ninja Gaiden Sigma 2" and possibly "NINJA GAIDEN 3: Razor's Edge" * amadeus: Fix wrong variable usage in delay effect We should transform the delay line values, not the input. * amadeus: Update GroupedBiquadFilterCommand documentation * amadeus: Simplify PoolMapper alignment checks * amadeus: Update Surround delay effect matrix to REV11 * amadeus: Add drop parameter support and use 32 bits integers for estimate time Also implement accurate ExecuteAudioRendererRendering stub. * Address gdkchan's comments * Address gdkchan's other comments * Address gdkchan's comment --- Ryujinx.Audio/Renderer/Dsp/AdpcmHelper.cs | 22 +++++++++--- .../Command/AdpcmDataSourceCommandVersion1.cs | 2 +- .../Dsp/Command/AuxiliaryBufferCommand.cs | 2 +- .../Dsp/Command/BiquadFilterCommand.cs | 2 +- .../Dsp/Command/CaptureBufferCommand.cs | 2 +- .../Dsp/Command/CircularBufferSinkCommand.cs | 2 +- .../Dsp/Command/ClearMixBufferCommand.cs | 2 +- .../Dsp/Command/CopyMixBufferCommand.cs | 2 +- .../Dsp/Command/DataSourceVersion2Command.cs | 2 +- .../Renderer/Dsp/Command/DelayCommand.cs | 30 ++++++++-------- .../Dsp/Command/DepopForMixBuffersCommand.cs | 2 +- .../Dsp/Command/DepopPrepareCommand.cs | 2 +- .../Renderer/Dsp/Command/DeviceSinkCommand.cs | 2 +- .../Command/DownMixSurroundToStereoCommand.cs | 2 +- .../Dsp/Command/GroupedBiquadFilterCommand.cs | 7 ++-- .../Renderer/Dsp/Command/ICommand.cs | 2 +- .../Dsp/Command/LimiterCommandVersion1.cs | 2 +- .../Dsp/Command/LimiterCommandVersion2.cs | 2 +- .../Renderer/Dsp/Command/MixCommand.cs | 2 +- .../Renderer/Dsp/Command/MixRampCommand.cs | 2 +- .../Dsp/Command/MixRampGroupedCommand.cs | 2 +- .../PcmFloatDataSourceCommandVersion1.cs | 2 +- .../PcmInt16DataSourceCommandVersion1.cs | 2 +- .../Dsp/Command/PerformanceCommand.cs | 2 +- .../Renderer/Dsp/Command/Reverb3dCommand.cs | 2 +- .../Renderer/Dsp/Command/ReverbCommand.cs | 2 +- .../Renderer/Dsp/Command/UpsampleCommand.cs | 2 +- .../Renderer/Dsp/Command/VolumeCommand.cs | 2 +- .../Renderer/Dsp/Command/VolumeRampCommand.cs | 2 +- .../Renderer/Server/AudioRenderSystem.cs | 34 ++++++++++++++++--- .../Renderer/Server/BehaviourContext.cs | 3 +- .../Renderer/Server/CommandBuffer.cs | 2 +- .../Renderer/Server/MemoryPool/PoolMapper.cs | 4 +-- Ryujinx.Audio/ResultCode.cs | 1 + .../Audio/AudioRenderer/AudioRenderer.cs | 12 ++++++- .../AudioRenderer/AudioRendererServer.cs | 29 ++++++++++++++++ .../Audio/AudioRenderer/IAudioRenderer.cs | 2 ++ 37 files changed, 140 insertions(+), 58 deletions(-) diff --git a/Ryujinx.Audio/Renderer/Dsp/AdpcmHelper.cs b/Ryujinx.Audio/Renderer/Dsp/AdpcmHelper.cs index f6638a9af3..2680dcb1e0 100644 --- a/Ryujinx.Audio/Renderer/Dsp/AdpcmHelper.cs +++ b/Ryujinx.Audio/Renderer/Dsp/AdpcmHelper.cs @@ -1,4 +1,5 @@ using Ryujinx.Audio.Renderer.Dsp.State; +using Ryujinx.Common.Logging; using System; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -71,6 +72,19 @@ namespace Ryujinx.Audio.Renderer.Dsp return (short)value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static short GetCoefficientAtIndex(ReadOnlySpan coefficients, int index) + { + if ((uint)index > (uint)coefficients.Length) + { + Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}"); + + return 0; + } + + return coefficients[index]; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Decode(Span output, ReadOnlySpan input, int startSampleOffset, int endSampleOffset, int offset, int count, ReadOnlySpan coefficients, ref AdpcmLoopContext loopContext) { @@ -84,8 +98,8 @@ namespace Ryujinx.Audio.Renderer.Dsp byte coefficientIndex = (byte)((predScale >> 4) & 0xF); short history0 = loopContext.History0; short history1 = loopContext.History1; - short coefficient0 = coefficients[coefficientIndex * 2 + 0]; - short coefficient1 = coefficients[coefficientIndex * 2 + 1]; + short coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 0); + short coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1); int decodedCount = Math.Min(count, endSampleOffset - startSampleOffset - offset); int nibbles = GetNibblesFromSampleCount(offset + startSampleOffset); @@ -109,8 +123,8 @@ namespace Ryujinx.Audio.Renderer.Dsp coefficientIndex = (byte)((predScale >> 4) & 0xF); - coefficient0 = coefficients[coefficientIndex * 2 + 0]; - coefficient1 = coefficients[coefficientIndex * 2 + 1]; + coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2); + coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1); nibbles += 2; diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/AdpcmDataSourceCommandVersion1.cs b/Ryujinx.Audio/Renderer/Dsp/Command/AdpcmDataSourceCommandVersion1.cs index 1ad629f49c..1fe6069f72 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/AdpcmDataSourceCommandVersion1.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/AdpcmDataSourceCommandVersion1.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.AdpcmDataSourceVersion1; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort OutputBufferIndex { get; } public uint SampleRate { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/AuxiliaryBufferCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/AuxiliaryBufferCommand.cs index cfa5400c12..5c3c0324b3 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/AuxiliaryBufferCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/AuxiliaryBufferCommand.cs @@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.AuxiliaryBuffer; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public uint InputBufferIndex { get; } public uint OutputBufferIndex { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs index e35911b24d..b994c1cb95 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/BiquadFilterCommand.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.BiquadFilter; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public Memory BiquadFilterState { get; } public int InputBufferIndex { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/CaptureBufferCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/CaptureBufferCommand.cs index ab1ea77d96..da1cb25466 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/CaptureBufferCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/CaptureBufferCommand.cs @@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.CaptureBuffer; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public uint InputBufferIndex { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/CircularBufferSinkCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/CircularBufferSinkCommand.cs index 27cd6e8421..e50637eb3d 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/CircularBufferSinkCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/CircularBufferSinkCommand.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.CircularBufferSink; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort[] Input { get; } public uint InputCount { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/ClearMixBufferCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/ClearMixBufferCommand.cs index c3530db1aa..9e653e8047 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/ClearMixBufferCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/ClearMixBufferCommand.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.ClearMixBuffer; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ClearMixBufferCommand(int nodeId) { diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/CopyMixBufferCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/CopyMixBufferCommand.cs index 64c297d11a..7237fddf65 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/CopyMixBufferCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/CopyMixBufferCommand.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.CopyMixBuffer; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort InputBufferIndex { get; } public ushort OutputBufferIndex { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/DataSourceVersion2Command.cs b/Ryujinx.Audio/Renderer/Dsp/Command/DataSourceVersion2Command.cs index f602262e3e..c1503b6a02 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/DataSourceVersion2Command.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/DataSourceVersion2Command.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType { get; } - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort OutputBufferIndex { get; } public uint SampleRate { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs index 8f11da9582..cb5678c7b3 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/DelayCommand.cs @@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.Delay; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public DelayParameter Parameter => _parameter; public Memory State { get; } @@ -49,15 +49,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command 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); + DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices); + DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, OutputBufferIndices); } [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] private unsafe void ProcessDelayMono(ref DelayState state, float* outputBuffer, float* inputBuffer, uint sampleCount) { + const ushort channelCount = 1; + float feedbackGain = FixedPointHelper.ToFloat(Parameter.FeedbackGain, FixedPointPrecision); float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision); float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision); @@ -70,7 +70,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command float temp = input * inGain + delayLineValue * feedbackGain; - state.UpdateLowPassFilter(ref temp, 1); + state.UpdateLowPassFilter(ref temp, channelCount); outputBuffer[i] = (input * dryGain + delayLineValue * outGain) / 64; } @@ -104,7 +104,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command Y = state.DelayLines[1].Read(), }; - Vector2 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain; + Vector2 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain; state.UpdateLowPassFilter(ref Unsafe.As(ref temp), channelCount); @@ -148,7 +148,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command W = state.DelayLines[3].Read() }; - Vector4 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain; + Vector4 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain; state.UpdateLowPassFilter(ref Unsafe.As(ref temp), channelCount); @@ -171,12 +171,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision); float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision); - Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, - 0.0f, delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, - delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, - 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, - delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackBaseGain, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, feedbackGain); + Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, 0.0f, delayFeedbackCrossGain, 0.0f, + 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, + delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, feedbackGain, 0.0f, 0.0f, + delayFeedbackCrossGain, 0.0f, 0.0f, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, + 0.0f, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackBaseGain); for (int i = 0; i < sampleCount; i++) { @@ -200,7 +200,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command U = state.DelayLines[5].Read() }; - Vector6 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain; + Vector6 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain; state.UpdateLowPassFilter(ref Unsafe.As(ref temp), channelCount); diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/DepopForMixBuffersCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/DepopForMixBuffersCommand.cs index e3a87c1023..1dba56e6cc 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/DepopForMixBuffersCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/DepopForMixBuffersCommand.cs @@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.DepopForMixBuffers; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public uint MixBufferOffset { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/DepopPrepareCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/DepopPrepareCommand.cs index 1e37ff7150..d02f7c1218 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/DepopPrepareCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/DepopPrepareCommand.cs @@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.DepopPrepare; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public uint MixBufferCount { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/DeviceSinkCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/DeviceSinkCommand.cs index a34fbc562c..9c88a4e7f4 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/DeviceSinkCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/DeviceSinkCommand.cs @@ -14,7 +14,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.DeviceSink; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public string DeviceName { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/DownMixSurroundToStereoCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/DownMixSurroundToStereoCommand.cs index d75da6f9fa..79cefcc53a 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/DownMixSurroundToStereoCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/DownMixSurroundToStereoCommand.cs @@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.DownMixSurroundToStereo; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort[] InputBufferIndices { get; } public ushort[] OutputBufferIndices { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/GroupedBiquadFilterCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/GroupedBiquadFilterCommand.cs index ae1ab12c56..b190cc10d5 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/GroupedBiquadFilterCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/GroupedBiquadFilterCommand.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.GroupedBiquadFilter; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } private BiquadFilterParameter[] _parameters; private Memory _biquadFilterStates; @@ -47,9 +47,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command } } - // NOTE: Nintendo also implements a hot path for double biquad filters, but no generic path when the command definition suggests it could be done. - // As such we currently only implement a generic path for simplicity. - // TODO: Implement double biquad filters fast path. + // NOTE: Nintendo only implement single and double biquad filters but no generic path when the command definition suggests it could be done. + // As such we currently only implement a generic path for simplicity for double biquad. if (_parameters.Length == 1) { BiquadFilterHelper.ProcessBiquadFilter(ref _parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount); diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/ICommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/ICommand.cs index dddd2511ea..d281e6e9fc 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/ICommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/ICommand.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType { get; } - public ulong EstimatedProcessingTime { get; } + public uint EstimatedProcessingTime { get; } public void Process(CommandList context); diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs b/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs index a393c88599..9cfef736e3 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion1.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.LimiterVersion1; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public LimiterParameter Parameter => _parameter; public Memory State { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs b/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs index ad703de14b..46c95e4f9d 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/LimiterCommandVersion2.cs @@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.LimiterVersion2; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public LimiterParameter Parameter => _parameter; public Memory State { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/MixCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/MixCommand.cs index d50309964a..2616bda57a 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/MixCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/MixCommand.cs @@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.Mix; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort InputBufferIndex { get; } public ushort OutputBufferIndex { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/MixRampCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/MixRampCommand.cs index 06af9f6fa7..76a1aba25b 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/MixRampCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/MixRampCommand.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.MixRamp; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort InputBufferIndex { get; } public ushort OutputBufferIndex { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs index 97bb0f508f..e348e35889 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/MixRampGroupedCommand.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.MixRampGrouped; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public uint MixBufferCount { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/PcmFloatDataSourceCommandVersion1.cs b/Ryujinx.Audio/Renderer/Dsp/Command/PcmFloatDataSourceCommandVersion1.cs index 7c48a511cc..7cec7d2ab9 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/PcmFloatDataSourceCommandVersion1.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/PcmFloatDataSourceCommandVersion1.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort OutputBufferIndex { get; } public uint SampleRate { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/PcmInt16DataSourceCommandVersion1.cs b/Ryujinx.Audio/Renderer/Dsp/Command/PcmInt16DataSourceCommandVersion1.cs index 8483f6d416..dfe9814fed 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/PcmInt16DataSourceCommandVersion1.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/PcmInt16DataSourceCommandVersion1.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort OutputBufferIndex { get; } public uint SampleRate { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/PerformanceCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/PerformanceCommand.cs index c2f94474d2..d3e3f80563 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/PerformanceCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/PerformanceCommand.cs @@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.Performance; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public PerformanceEntryAddresses PerformanceEntryAddresses { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/Reverb3dCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/Reverb3dCommand.cs index 04809245f8..eeb6456735 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/Reverb3dCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/Reverb3dCommand.cs @@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.Reverb3d; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort InputBufferIndex { get; } public ushort OutputBufferIndex { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs index 130706d10c..0a32a065d3 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/ReverbCommand.cs @@ -34,7 +34,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.Reverb; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ReverbParameter Parameter => _parameter; public Memory State { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/UpsampleCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/UpsampleCommand.cs index 6df44b3276..1617a6421d 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/UpsampleCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/UpsampleCommand.cs @@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.Upsample; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public uint BufferCount { get; } public uint InputBufferIndex { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/VolumeCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/VolumeCommand.cs index e294789116..0628f6d810 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/VolumeCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/VolumeCommand.cs @@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.Volume; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort InputBufferIndex { get; } public ushort OutputBufferIndex { get; } diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/VolumeRampCommand.cs b/Ryujinx.Audio/Renderer/Dsp/Command/VolumeRampCommand.cs index ffda8b1a0a..5c0c88451e 100644 --- a/Ryujinx.Audio/Renderer/Dsp/Command/VolumeRampCommand.cs +++ b/Ryujinx.Audio/Renderer/Dsp/Command/VolumeRampCommand.cs @@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command public CommandType CommandType => CommandType.VolumeRamp; - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } public ushort InputBufferIndex { get; } public ushort OutputBufferIndex { get; } diff --git a/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs b/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs index af163ae040..34fdef8a17 100644 --- a/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs +++ b/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs @@ -28,6 +28,7 @@ namespace Ryujinx.Audio.Renderer.Server { private object _lock = new object(); + private AudioRendererRenderingDevice _renderingDevice; private AudioRendererExecutionMode _executionMode; private IWritableEvent _systemEvent; private ManualResetEvent _terminationEvent; @@ -63,6 +64,7 @@ namespace Ryujinx.Audio.Renderer.Server private uint _renderingTimeLimitPercent; private bool _voiceDropEnabled; private uint _voiceDropCount; + private float _voiceDropParameter; private bool _isDspRunningBehind; private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator; @@ -95,6 +97,7 @@ namespace Ryujinx.Audio.Renderer.Server _totalElapsedTicksUpdating = 0; _sessionId = 0; + _voiceDropParameter = 1.0f; } public ResultCode Initialize( @@ -130,6 +133,7 @@ namespace Ryujinx.Audio.Renderer.Server _upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount; _appletResourceId = appletResourceId; _memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount; + _renderingDevice = parameter.RenderingDevice; _executionMode = parameter.ExecutionMode; _sessionId = sessionId; MemoryManager = memoryManager; @@ -337,6 +341,7 @@ namespace Ryujinx.Audio.Renderer.Server _processHandle = processHandle; _elapsedFrameCount = 0; + _voiceDropParameter = 1.0f; switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion()) { @@ -515,7 +520,7 @@ namespace Ryujinx.Audio.Renderer.Server return (ulong)(_manager.TickSource.ElapsedSeconds * Constants.TargetTimerFrequency); } - private uint ComputeVoiceDrop(CommandBuffer commandBuffer, long voicesEstimatedTime, long deltaTimeDsp) + private uint ComputeVoiceDrop(CommandBuffer commandBuffer, uint voicesEstimatedTime, long deltaTimeDsp) { int i; @@ -584,7 +589,7 @@ namespace Ryujinx.Audio.Renderer.Server { command.Enabled = false; - voicesEstimatedTime -= (long)command.EstimatedProcessingTime; + voicesEstimatedTime -= (uint)(_voiceDropParameter * command.EstimatedProcessingTime); } } } @@ -618,13 +623,13 @@ namespace Ryujinx.Audio.Renderer.Server _voiceContext.Sort(); commandGenerator.GenerateVoices(); - long voicesEstimatedTime = (long)commandBuffer.EstimatedProcessingTime; + uint voicesEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime); commandGenerator.GenerateSubMixes(); commandGenerator.GenerateFinalMixes(); commandGenerator.GenerateSinks(); - long totalEstimatedTime = (long)commandBuffer.EstimatedProcessingTime; + uint totalEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime); if (_voiceDropEnabled) { @@ -856,5 +861,26 @@ namespace Ryujinx.Audio.Renderer.Server } } } + + public void SetVoiceDropParameter(float voiceDropParameter) + { + _voiceDropParameter = Math.Clamp(voiceDropParameter, 0.0f, 2.0f); + } + + public float GetVoiceDropParameter() + { + return _voiceDropParameter; + } + + public ResultCode ExecuteAudioRendererRendering() + { + if (_executionMode == AudioRendererExecutionMode.Manual && _renderingDevice == AudioRendererRenderingDevice.Cpu) + { + // NOTE: Here Nintendo aborts with this error code, we don't want that. + return ResultCode.InvalidExecutionContextOperation; + } + + return ResultCode.UnsupportedOperation; + } } } \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs b/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs index 4172041513..adf5294ea0 100644 --- a/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs +++ b/Ryujinx.Audio/Renderer/Server/BehaviourContext.cs @@ -94,8 +94,9 @@ namespace Ryujinx.Audio.Renderer.Server /// 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. + /// A voice drop parameter was added in 15.0.0: This allows an application to amplify or attenuate the estimated time of DSP commands. /// - /// This was added in system update 14.0.0 + /// This was added in system update 14.0.0 but some changes were made in 15.0.0 public const int Revision11 = 11 << 24; /// diff --git a/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs b/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs index 3a3a981d78..e0741cc6e3 100644 --- a/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs +++ b/Ryujinx.Audio/Renderer/Server/CommandBuffer.cs @@ -25,7 +25,7 @@ namespace Ryujinx.Audio.Renderer.Server /// /// The estimated total processing time. /// - public ulong EstimatedProcessingTime { get; set; } + public uint EstimatedProcessingTime { get; set; } /// /// The command list that is populated by the . diff --git a/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs b/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs index cf0fc067e2..6c79da1576 100644 --- a/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs +++ b/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs @@ -263,12 +263,12 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool return UpdateResult.Success; } - if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress & (pageSize - 1)) != 0) + if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress % pageSize) != 0) { return UpdateResult.InvalidParameter; } - if (inParameter.Size == 0 || (inParameter.Size & (pageSize - 1)) != 0) + if (inParameter.Size == 0 || (inParameter.Size % pageSize) != 0) { return UpdateResult.InvalidParameter; } diff --git a/Ryujinx.Audio/ResultCode.cs b/Ryujinx.Audio/ResultCode.cs index 8e0bfcb0c9..1d05ac65ed 100644 --- a/Ryujinx.Audio/ResultCode.cs +++ b/Ryujinx.Audio/ResultCode.cs @@ -17,5 +17,6 @@ namespace Ryujinx.Audio InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId, InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId, UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId, + InvalidExecutionContextOperation = (514 << ErrorCodeShift) | ModuleId, } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs index d69bde0377..5b682bf845 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs @@ -16,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer public ResultCode ExecuteAudioRendererRendering() { - throw new NotImplementedException(); + return (ResultCode)_impl.ExecuteAudioRendererRendering(); } public uint GetMixBufferCount() @@ -108,5 +108,15 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer _impl.Dispose(); } } + + public void SetVoiceDropParameter(float voiceDropParameter) + { + _impl.SetVoiceDropParameter(voiceDropParameter); + } + + public float GetVoiceDropParameter() + { + return _impl.GetVoiceDropParameter(); + } } } diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs index dd48a666b2..b2ddb697a2 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs @@ -172,6 +172,35 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer return result; } + [CommandHipc(11)] // 3.0.0+ + // ExecuteAudioRendererRendering() + public ResultCode ExecuteAudioRendererRendering(ServiceCtx context) + { + return _impl.ExecuteAudioRendererRendering(); + } + + [CommandHipc(12)] // 15.0.0+ + // SetVoiceDropParameter(f32 voiceDropParameter) + public ResultCode SetVoiceDropParameter(ServiceCtx context) + { + float voiceDropParameter = context.RequestData.ReadSingle(); + + _impl.SetVoiceDropParameter(voiceDropParameter); + + return ResultCode.Success; + } + + [CommandHipc(13)] // 15.0.0+ + // GetVoiceDropParameter() -> f32 voiceDropParameter + public ResultCode GetVoiceDropParameter(ServiceCtx context) + { + float voiceDropParameter = _impl.GetVoiceDropParameter(); + + context.ResponseData.Write(voiceDropParameter); + + return ResultCode.Success; + } + protected override void Dispose(bool isDisposing) { if (isDisposing) diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs index a59c94e976..404bf4c102 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs @@ -16,5 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer void SetRenderingTimeLimit(uint percent); uint GetRenderingTimeLimit(); ResultCode ExecuteAudioRendererRendering(); + void SetVoiceDropParameter(float voiceDropParameter); + float GetVoiceDropParameter(); } }