forked from Mirror/Ryujinx
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
This commit is contained in:
parent
472119c8da
commit
dff138229c
37 changed files with 140 additions and 58 deletions
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
@ -71,6 +72,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
return (short)value;
|
return (short)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static short GetCoefficientAtIndex(ReadOnlySpan<short> 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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int Decode(Span<short> output, ReadOnlySpan<byte> input, int startSampleOffset, int endSampleOffset, int offset, int count, ReadOnlySpan<short> coefficients, ref AdpcmLoopContext loopContext)
|
public static int Decode(Span<short> output, ReadOnlySpan<byte> input, int startSampleOffset, int endSampleOffset, int offset, int count, ReadOnlySpan<short> coefficients, ref AdpcmLoopContext loopContext)
|
||||||
{
|
{
|
||||||
|
@ -84,8 +98,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
byte coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
byte coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
||||||
short history0 = loopContext.History0;
|
short history0 = loopContext.History0;
|
||||||
short history1 = loopContext.History1;
|
short history1 = loopContext.History1;
|
||||||
short coefficient0 = coefficients[coefficientIndex * 2 + 0];
|
short coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 0);
|
||||||
short coefficient1 = coefficients[coefficientIndex * 2 + 1];
|
short coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
|
||||||
|
|
||||||
int decodedCount = Math.Min(count, endSampleOffset - startSampleOffset - offset);
|
int decodedCount = Math.Min(count, endSampleOffset - startSampleOffset - offset);
|
||||||
int nibbles = GetNibblesFromSampleCount(offset + startSampleOffset);
|
int nibbles = GetNibblesFromSampleCount(offset + startSampleOffset);
|
||||||
|
@ -109,8 +123,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
|
|
||||||
coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
||||||
|
|
||||||
coefficient0 = coefficients[coefficientIndex * 2 + 0];
|
coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2);
|
||||||
coefficient1 = coefficients[coefficientIndex * 2 + 1];
|
coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
|
||||||
|
|
||||||
nibbles += 2;
|
nibbles += 2;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
|
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.AuxiliaryBuffer;
|
public CommandType CommandType => CommandType.AuxiliaryBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint InputBufferIndex { get; }
|
public uint InputBufferIndex { get; }
|
||||||
public uint OutputBufferIndex { get; }
|
public uint OutputBufferIndex { get; }
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.BiquadFilter;
|
public CommandType CommandType => CommandType.BiquadFilter;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public Memory<BiquadFilterState> BiquadFilterState { get; }
|
public Memory<BiquadFilterState> BiquadFilterState { get; }
|
||||||
public int InputBufferIndex { get; }
|
public int InputBufferIndex { get; }
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.CaptureBuffer;
|
public CommandType CommandType => CommandType.CaptureBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint InputBufferIndex { get; }
|
public uint InputBufferIndex { get; }
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.CircularBufferSink;
|
public CommandType CommandType => CommandType.CircularBufferSink;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort[] Input { get; }
|
public ushort[] Input { get; }
|
||||||
public uint InputCount { get; }
|
public uint InputCount { get; }
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.ClearMixBuffer;
|
public CommandType CommandType => CommandType.ClearMixBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ClearMixBufferCommand(int nodeId)
|
public ClearMixBufferCommand(int nodeId)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.CopyMixBuffer;
|
public CommandType CommandType => CommandType.CopyMixBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType { get; }
|
public CommandType CommandType { get; }
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.Delay;
|
public CommandType CommandType => CommandType.Delay;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public DelayParameter Parameter => _parameter;
|
public DelayParameter Parameter => _parameter;
|
||||||
public Memory<DelayState> State { get; }
|
public Memory<DelayState> State { get; }
|
||||||
|
@ -49,15 +49,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices);
|
||||||
// TODO: Update delay processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping.
|
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, OutputBufferIndices);
|
||||||
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices);
|
|
||||||
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
private unsafe void ProcessDelayMono(ref DelayState state, float* outputBuffer, float* inputBuffer, uint sampleCount)
|
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 feedbackGain = FixedPointHelper.ToFloat(Parameter.FeedbackGain, FixedPointPrecision);
|
||||||
float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision);
|
float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision);
|
||||||
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
||||||
|
@ -70,7 +70,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
float temp = input * inGain + delayLineValue * feedbackGain;
|
float temp = input * inGain + delayLineValue * feedbackGain;
|
||||||
|
|
||||||
state.UpdateLowPassFilter(ref temp, 1);
|
state.UpdateLowPassFilter(ref temp, channelCount);
|
||||||
|
|
||||||
outputBuffer[i] = (input * dryGain + delayLineValue * outGain) / 64;
|
outputBuffer[i] = (input * dryGain + delayLineValue * outGain) / 64;
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
Y = state.DelayLines[1].Read(),
|
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<Vector2, float>(ref temp), channelCount);
|
state.UpdateLowPassFilter(ref Unsafe.As<Vector2, float>(ref temp), channelCount);
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
W = state.DelayLines[3].Read()
|
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<Vector4, float>(ref temp), channelCount);
|
state.UpdateLowPassFilter(ref Unsafe.As<Vector4, float>(ref temp), channelCount);
|
||||||
|
|
||||||
|
@ -171,12 +171,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
||||||
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
|
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
|
||||||
|
|
||||||
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain,
|
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, 0.0f, delayFeedbackCrossGain, 0.0f,
|
||||||
0.0f, delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f,
|
0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain,
|
||||||
delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f,
|
delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f,
|
||||||
0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f,
|
0.0f, 0.0f, 0.0f, feedbackGain, 0.0f, 0.0f,
|
||||||
delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackBaseGain, 0.0f,
|
delayFeedbackCrossGain, 0.0f, 0.0f, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain,
|
||||||
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, feedbackGain);
|
0.0f, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackBaseGain);
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
|
@ -200,7 +200,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
U = state.DelayLines[5].Read()
|
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<Vector6, float>(ref temp), channelCount);
|
state.UpdateLowPassFilter(ref Unsafe.As<Vector6, float>(ref temp), channelCount);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.DepopForMixBuffers;
|
public CommandType CommandType => CommandType.DepopForMixBuffers;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint MixBufferOffset { get; }
|
public uint MixBufferOffset { get; }
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.DepopPrepare;
|
public CommandType CommandType => CommandType.DepopPrepare;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint MixBufferCount { get; }
|
public uint MixBufferCount { get; }
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.DeviceSink;
|
public CommandType CommandType => CommandType.DeviceSink;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public string DeviceName { get; }
|
public string DeviceName { get; }
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.DownMixSurroundToStereo;
|
public CommandType CommandType => CommandType.DownMixSurroundToStereo;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort[] InputBufferIndices { get; }
|
public ushort[] InputBufferIndices { get; }
|
||||||
public ushort[] OutputBufferIndices { get; }
|
public ushort[] OutputBufferIndices { get; }
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.GroupedBiquadFilter;
|
public CommandType CommandType => CommandType.GroupedBiquadFilter;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
private BiquadFilterParameter[] _parameters;
|
private BiquadFilterParameter[] _parameters;
|
||||||
private Memory<BiquadFilterState> _biquadFilterStates;
|
private Memory<BiquadFilterState> _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.
|
// 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.
|
// As such we currently only implement a generic path for simplicity for double biquad.
|
||||||
// TODO: Implement double biquad filters fast path.
|
|
||||||
if (_parameters.Length == 1)
|
if (_parameters.Length == 1)
|
||||||
{
|
{
|
||||||
BiquadFilterHelper.ProcessBiquadFilter(ref _parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount);
|
BiquadFilterHelper.ProcessBiquadFilter(ref _parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount);
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType { get; }
|
public CommandType CommandType { get; }
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; }
|
public uint EstimatedProcessingTime { get; }
|
||||||
|
|
||||||
public void Process(CommandList context);
|
public void Process(CommandList context);
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.LimiterVersion1;
|
public CommandType CommandType => CommandType.LimiterVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public LimiterParameter Parameter => _parameter;
|
public LimiterParameter Parameter => _parameter;
|
||||||
public Memory<LimiterState> State { get; }
|
public Memory<LimiterState> State { get; }
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.LimiterVersion2;
|
public CommandType CommandType => CommandType.LimiterVersion2;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public LimiterParameter Parameter => _parameter;
|
public LimiterParameter Parameter => _parameter;
|
||||||
public Memory<LimiterState> State { get; }
|
public Memory<LimiterState> State { get; }
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.Mix;
|
public CommandType CommandType => CommandType.Mix;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.MixRamp;
|
public CommandType CommandType => CommandType.MixRamp;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.MixRampGrouped;
|
public CommandType CommandType => CommandType.MixRampGrouped;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint MixBufferCount { get; }
|
public uint MixBufferCount { get; }
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1;
|
public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1;
|
public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.Performance;
|
public CommandType CommandType => CommandType.Performance;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public PerformanceEntryAddresses PerformanceEntryAddresses { get; }
|
public PerformanceEntryAddresses PerformanceEntryAddresses { get; }
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.Reverb3d;
|
public CommandType CommandType => CommandType.Reverb3d;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.Reverb;
|
public CommandType CommandType => CommandType.Reverb;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ReverbParameter Parameter => _parameter;
|
public ReverbParameter Parameter => _parameter;
|
||||||
public Memory<ReverbState> State { get; }
|
public Memory<ReverbState> State { get; }
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.Upsample;
|
public CommandType CommandType => CommandType.Upsample;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint BufferCount { get; }
|
public uint BufferCount { get; }
|
||||||
public uint InputBufferIndex { get; }
|
public uint InputBufferIndex { get; }
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.Volume;
|
public CommandType CommandType => CommandType.Volume;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public CommandType CommandType => CommandType.VolumeRamp;
|
public CommandType CommandType => CommandType.VolumeRamp;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
{
|
{
|
||||||
private object _lock = new object();
|
private object _lock = new object();
|
||||||
|
|
||||||
|
private AudioRendererRenderingDevice _renderingDevice;
|
||||||
private AudioRendererExecutionMode _executionMode;
|
private AudioRendererExecutionMode _executionMode;
|
||||||
private IWritableEvent _systemEvent;
|
private IWritableEvent _systemEvent;
|
||||||
private ManualResetEvent _terminationEvent;
|
private ManualResetEvent _terminationEvent;
|
||||||
|
@ -63,6 +64,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
private uint _renderingTimeLimitPercent;
|
private uint _renderingTimeLimitPercent;
|
||||||
private bool _voiceDropEnabled;
|
private bool _voiceDropEnabled;
|
||||||
private uint _voiceDropCount;
|
private uint _voiceDropCount;
|
||||||
|
private float _voiceDropParameter;
|
||||||
private bool _isDspRunningBehind;
|
private bool _isDspRunningBehind;
|
||||||
|
|
||||||
private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator;
|
private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator;
|
||||||
|
@ -95,6 +97,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
|
|
||||||
_totalElapsedTicksUpdating = 0;
|
_totalElapsedTicksUpdating = 0;
|
||||||
_sessionId = 0;
|
_sessionId = 0;
|
||||||
|
_voiceDropParameter = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode Initialize(
|
public ResultCode Initialize(
|
||||||
|
@ -130,6 +133,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
_upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount;
|
_upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount;
|
||||||
_appletResourceId = appletResourceId;
|
_appletResourceId = appletResourceId;
|
||||||
_memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount;
|
_memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount;
|
||||||
|
_renderingDevice = parameter.RenderingDevice;
|
||||||
_executionMode = parameter.ExecutionMode;
|
_executionMode = parameter.ExecutionMode;
|
||||||
_sessionId = sessionId;
|
_sessionId = sessionId;
|
||||||
MemoryManager = memoryManager;
|
MemoryManager = memoryManager;
|
||||||
|
@ -337,6 +341,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
|
|
||||||
_processHandle = processHandle;
|
_processHandle = processHandle;
|
||||||
_elapsedFrameCount = 0;
|
_elapsedFrameCount = 0;
|
||||||
|
_voiceDropParameter = 1.0f;
|
||||||
|
|
||||||
switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion())
|
switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion())
|
||||||
{
|
{
|
||||||
|
@ -515,7 +520,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
return (ulong)(_manager.TickSource.ElapsedSeconds * Constants.TargetTimerFrequency);
|
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;
|
int i;
|
||||||
|
|
||||||
|
@ -584,7 +589,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
{
|
{
|
||||||
command.Enabled = false;
|
command.Enabled = false;
|
||||||
|
|
||||||
voicesEstimatedTime -= (long)command.EstimatedProcessingTime;
|
voicesEstimatedTime -= (uint)(_voiceDropParameter * command.EstimatedProcessingTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -618,13 +623,13 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
_voiceContext.Sort();
|
_voiceContext.Sort();
|
||||||
commandGenerator.GenerateVoices();
|
commandGenerator.GenerateVoices();
|
||||||
|
|
||||||
long voicesEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
|
uint voicesEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
|
||||||
|
|
||||||
commandGenerator.GenerateSubMixes();
|
commandGenerator.GenerateSubMixes();
|
||||||
commandGenerator.GenerateFinalMixes();
|
commandGenerator.GenerateFinalMixes();
|
||||||
commandGenerator.GenerateSinks();
|
commandGenerator.GenerateSinks();
|
||||||
|
|
||||||
long totalEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
|
uint totalEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
|
||||||
|
|
||||||
if (_voiceDropEnabled)
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -94,8 +94,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
/// REV11:
|
/// REV11:
|
||||||
/// The "legacy" effects (Delay, Reverb and Reverb 3D) were updated to match the standard channel mapping used by the audio renderer.
|
/// 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 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>
|
/// </summary>
|
||||||
/// <remarks>This was added in system update 14.0.0</remarks>
|
/// <remarks>This was added in system update 14.0.0 but some changes were made in 15.0.0</remarks>
|
||||||
public const int Revision11 = 11 << 24;
|
public const int Revision11 = 11 << 24;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The estimated total processing time.
|
/// The estimated total processing time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The command list that is populated by the <see cref="CommandBuffer"/>.
|
/// The command list that is populated by the <see cref="CommandBuffer"/>.
|
||||||
|
|
|
@ -263,12 +263,12 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
||||||
return UpdateResult.Success;
|
return UpdateResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress & (pageSize - 1)) != 0)
|
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress % pageSize) != 0)
|
||||||
{
|
{
|
||||||
return UpdateResult.InvalidParameter;
|
return UpdateResult.InvalidParameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inParameter.Size == 0 || (inParameter.Size & (pageSize - 1)) != 0)
|
if (inParameter.Size == 0 || (inParameter.Size % pageSize) != 0)
|
||||||
{
|
{
|
||||||
return UpdateResult.InvalidParameter;
|
return UpdateResult.InvalidParameter;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,5 +17,6 @@ namespace Ryujinx.Audio
|
||||||
InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId,
|
InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId,
|
||||||
InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId,
|
InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId,
|
||||||
UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId,
|
UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId,
|
||||||
|
InvalidExecutionContextOperation = (514 << ErrorCodeShift) | ModuleId,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
||||||
|
|
||||||
public ResultCode ExecuteAudioRendererRendering()
|
public ResultCode ExecuteAudioRendererRendering()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return (ResultCode)_impl.ExecuteAudioRendererRendering();
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetMixBufferCount()
|
public uint GetMixBufferCount()
|
||||||
|
@ -108,5 +108,15 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
||||||
_impl.Dispose();
|
_impl.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetVoiceDropParameter(float voiceDropParameter)
|
||||||
|
{
|
||||||
|
_impl.SetVoiceDropParameter(voiceDropParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetVoiceDropParameter()
|
||||||
|
{
|
||||||
|
return _impl.GetVoiceDropParameter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,35 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
||||||
return result;
|
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)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
if (isDisposing)
|
if (isDisposing)
|
||||||
|
|
|
@ -16,5 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
||||||
void SetRenderingTimeLimit(uint percent);
|
void SetRenderingTimeLimit(uint percent);
|
||||||
uint GetRenderingTimeLimit();
|
uint GetRenderingTimeLimit();
|
||||||
ResultCode ExecuteAudioRendererRendering();
|
ResultCode ExecuteAudioRendererRendering();
|
||||||
|
void SetVoiceDropParameter(float voiceDropParameter);
|
||||||
|
float GetVoiceDropParameter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue