SDK20 and REV15 support (ryubing/ryujinx!50)

See merge request ryubing/ryujinx!50
This commit is contained in:
LotP
2025-10-11 02:11:39 -05:00
committed by GreemDev
parent 4444ecae41
commit e2143d43bc
83 changed files with 2343 additions and 1195 deletions

View File

@@ -11,14 +11,14 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
public class VoiceContext
{
/// <summary>
/// Storage of the sorted indices to <see cref="VoiceState"/>.
/// Storage of the sorted indices to <see cref="VoiceInfo"/>.
/// </summary>
private Memory<int> _sortedVoices;
/// <summary>
/// Storage for <see cref="VoiceState"/>.
/// Storage for <see cref="VoiceInfo"/>.
/// </summary>
private Memory<VoiceState> _voices;
private Memory<VoiceInfo> _voices;
/// <summary>
/// Storage for <see cref="VoiceChannelResource"/>.
@@ -26,27 +26,27 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
private Memory<VoiceChannelResource> _voiceChannelResources;
/// <summary>
/// Storage for <see cref="VoiceUpdateState"/> that are used during audio renderer server updates.
/// Storage for <see cref="VoiceState"/> that are used during audio renderer server updates.
/// </summary>
private Memory<VoiceUpdateState> _voiceUpdateStatesCpu;
private Memory<VoiceState> _voiceStatesCpu;
/// <summary>
/// Storage for <see cref="VoiceUpdateState"/> for the <see cref="Dsp.AudioProcessor"/>.
/// Storage for <see cref="VoiceState"/> for the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
private Memory<VoiceUpdateState> _voiceUpdateStatesDsp;
private Memory<VoiceState> _voiceStatesDsp;
/// <summary>
/// The total voice count.
/// </summary>
private uint _voiceCount;
public void Initialize(Memory<int> sortedVoices, Memory<VoiceState> voices, Memory<VoiceChannelResource> voiceChannelResources, Memory<VoiceUpdateState> voiceUpdateStatesCpu, Memory<VoiceUpdateState> voiceUpdateStatesDsp, uint voiceCount)
public void Initialize(Memory<int> sortedVoices, Memory<VoiceInfo> voices, Memory<VoiceChannelResource> voiceChannelResources, Memory<VoiceState> voiceStatesCpu, Memory<VoiceState> voiceStatesDsp, uint voiceCount)
{
_sortedVoices = sortedVoices;
_voices = voices;
_voiceChannelResources = voiceChannelResources;
_voiceUpdateStatesCpu = voiceUpdateStatesCpu;
_voiceUpdateStatesDsp = voiceUpdateStatesDsp;
_voiceStatesCpu = voiceStatesCpu;
_voiceStatesDsp = voiceStatesDsp;
_voiceCount = voiceCount;
}
@@ -70,38 +70,38 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
}
/// <summary>
/// Get a <see cref="Memory{VoiceUpdateState}"/> at the given <paramref name="id"/>.
/// Get a <see cref="Memory{VoiceState}"/> at the given <paramref name="id"/>.
/// </summary>
/// <param name="id">The index to use.</param>
/// <returns>A <see cref="Memory{VoiceUpdateState}"/> at the given <paramref name="id"/>.</returns>
/// <remarks>The returned <see cref="Memory{VoiceUpdateState}"/> should only be used when updating the server state.</remarks>
public Memory<VoiceUpdateState> GetUpdateStateForCpu(int id)
/// <returns>A <see cref="Memory{VoiceState}"/> at the given <paramref name="id"/>.</returns>
/// <remarks>The returned <see cref="Memory{VoiceState}"/> should only be used when updating the server state.</remarks>
public Memory<VoiceState> GetUpdateStateForCpu(int id)
{
return SpanIOHelper.GetMemory(_voiceUpdateStatesCpu, id, _voiceCount);
return SpanIOHelper.GetMemory(_voiceStatesCpu, id, _voiceCount);
}
/// <summary>
/// Get a <see cref="Memory{VoiceUpdateState}"/> at the given <paramref name="id"/>.
/// Get a <see cref="Memory{VoiceState}"/> at the given <paramref name="id"/>.
/// </summary>
/// <param name="id">The index to use.</param>
/// <returns>A <see cref="Memory{VoiceUpdateState}"/> at the given <paramref name="id"/>.</returns>
/// <remarks>The returned <see cref="Memory{VoiceUpdateState}"/> should only be used in the context of processing on the <see cref="Dsp.AudioProcessor"/>.</remarks>
public Memory<VoiceUpdateState> GetUpdateStateForDsp(int id)
/// <returns>A <see cref="Memory{VoiceState}"/> at the given <paramref name="id"/>.</returns>
/// <remarks>The returned <see cref="Memory{VoiceState}"/> should only be used in the context of processing on the <see cref="Dsp.AudioProcessor"/>.</remarks>
public Memory<VoiceState> GetUpdateStateForDsp(int id)
{
return SpanIOHelper.GetMemory(_voiceUpdateStatesDsp, id, _voiceCount);
return SpanIOHelper.GetMemory(_voiceStatesDsp, id, _voiceCount);
}
/// <summary>
/// Get a reference to a <see cref="VoiceState"/> at the given <paramref name="id"/>.
/// Get a reference to a <see cref="VoiceInfo"/> at the given <paramref name="id"/>.
/// </summary>
/// <param name="id">The index to use.</param>
/// <returns>A reference to a <see cref="VoiceState"/> at the given <paramref name="id"/>.</returns>
public ref VoiceState GetState(int id)
/// <returns>A reference to a <see cref="VoiceInfo"/> at the given <paramref name="id"/>.</returns>
public ref VoiceInfo GetState(int id)
{
return ref SpanIOHelper.GetFromMemory(_voices, id, _voiceCount);
}
public ref VoiceState GetSortedState(int id)
public ref VoiceInfo GetSortedState(int id)
{
Debug.Assert(id >= 0 && id < _voiceCount);
@@ -113,7 +113,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
/// </summary>
public void UpdateForCommandGeneration()
{
_voiceUpdateStatesDsp.CopyTo(_voiceUpdateStatesCpu);
_voiceStatesDsp.CopyTo(_voiceStatesCpu);
}
/// <summary>
@@ -130,14 +130,14 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
sortedVoicesTemp.Sort((a, b) =>
{
ref VoiceState aState = ref GetState(a);
ref VoiceState bState = ref GetState(b);
ref VoiceInfo aInfo = ref GetState(a);
ref VoiceInfo bInfo = ref GetState(b);
int result = aState.Priority.CompareTo(bState.Priority);
int result = aInfo.Priority.CompareTo(bInfo.Priority);
if (result == 0)
{
return aState.SortingOrder.CompareTo(bState.SortingOrder);
return aInfo.SortingOrder.CompareTo(bInfo.SortingOrder);
}
return result;

View File

@@ -1,5 +1,6 @@
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Audio.Renderer.Dsp;
using Ryujinx.Audio.Renderer.Dsp.State;
using Ryujinx.Audio.Renderer.Parameter;
using Ryujinx.Audio.Renderer.Server.MemoryPool;
@@ -9,13 +10,13 @@ using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using static Ryujinx.Audio.Renderer.Common.BehaviourParameter;
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter1;
using PlayState = Ryujinx.Audio.Renderer.Server.Types.PlayState;
namespace Ryujinx.Audio.Renderer.Server.Voice
{
[StructLayout(LayoutKind.Sequential, Pack = Alignment)]
public struct VoiceState
public struct VoiceInfo
{
public const int Alignment = 0x10;
@@ -102,7 +103,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
/// <summary>
/// Biquad filters to apply to the output of the voice.
/// </summary>
public Array2<BiquadFilterParameter> BiquadFilters;
public Array2<BiquadFilterParameter2> BiquadFilters;
/// <summary>
/// Total count of <see cref="WaveBufferInternal"/> of the voice.
@@ -185,7 +186,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
public Span<bool> BiquadFilterNeedInitialization => SpanHelpers.AsSpan<BiquadFilterNeedInitializationArrayStruct, bool>(ref _biquadFilterNeedInitialization);
/// <summary>
/// Initialize the <see cref="VoiceState"/>.
/// Initialize the <see cref="VoiceInfo"/>.
/// </summary>
public void Initialize()
{
@@ -215,7 +216,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
}
/// <summary>
/// Initialize the <see cref="WaveBuffer"/> in this <see cref="VoiceState"/>.
/// Initialize the <see cref="WaveBuffer"/> in this <see cref="VoiceInfo"/>.
/// </summary>
private void InitializeWaveBuffers()
{
@@ -250,13 +251,13 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
{
return MixId != Constants.UnusedMixId || SplitterId != Constants.UnusedSplitterId;
}
/// <summary>
/// Indicate if the server voice information needs to be updated.
/// </summary>
/// <param name="parameter">The user parameter.</param>
/// <returns>Return true, if the server voice information needs to be updated.</returns>
private readonly bool ShouldUpdateParameters(in VoiceInParameter parameter)
private readonly bool ShouldUpdateParameters2(in VoiceInParameter2 parameter)
{
if (DataSourceStateAddressInfo.CpuAddress == parameter.DataSourceStateAddress)
{
@@ -268,14 +269,31 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
DataSourceStateUnmapped;
}
/// <summary>
/// Indicate if the server voice information needs to be updated.
/// </summary>
/// <param name="parameter">The user parameter.</param>
/// <returns>Return true, if the server voice information needs to be updated.</returns>
private readonly bool ShouldUpdateParameters1(in VoiceInParameter1 parameter)
{
if (DataSourceStateAddressInfo.CpuAddress == parameter.DataSourceStateAddress)
{
return DataSourceStateAddressInfo.Size != parameter.DataSourceStateSize;
}
return DataSourceStateAddressInfo.CpuAddress != parameter.DataSourceStateAddress ||
DataSourceStateAddressInfo.Size != parameter.DataSourceStateSize ||
DataSourceStateUnmapped;
}
/// <summary>
/// Update the internal state from a user parameter.
/// </summary>
/// <param name="outErrorInfo">The possible <see cref="ErrorInfo"/> that was generated.</param>
/// <param name="parameter">The user parameter.</param>
/// <param name="poolMapper">The mapper to use.</param>
/// <param name="behaviourContext">The behaviour context.</param>
public void UpdateParameters(out ErrorInfo outErrorInfo, in VoiceInParameter parameter, PoolMapper poolMapper, ref BehaviourContext behaviourContext)
/// <param name="behaviourInfo">The behaviour context.</param>
public void UpdateParameters2(out ErrorInfo outErrorInfo, in VoiceInParameter2 parameter, PoolMapper poolMapper, ref BehaviourInfo behaviourInfo)
{
InUse = parameter.InUse;
Id = parameter.Id;
@@ -296,14 +314,14 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
WaveBuffersCount = parameter.WaveBuffersCount;
WaveBuffersIndex = parameter.WaveBuffersIndex;
if (behaviourContext.IsFlushVoiceWaveBuffersSupported())
if (behaviourInfo.IsFlushVoiceWaveBuffersSupported())
{
FlushWaveBufferCount += parameter.FlushWaveBufferCount;
}
MixId = parameter.MixId;
if (behaviourContext.IsSplitterSupported())
if (behaviourInfo.IsSplitterSupported())
{
SplitterId = parameter.SplitterId;
}
@@ -316,7 +334,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
DecodingBehaviour behaviour = DecodingBehaviour.Default;
if (behaviourContext.IsDecodingBehaviourFlagSupported())
if (behaviourInfo.IsDecodingBehaviourFlagSupported())
{
behaviour = parameter.DecodingBehaviourFlags;
}
@@ -328,7 +346,78 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
VoiceDropFlag = false;
}
if (ShouldUpdateParameters(in parameter))
if (ShouldUpdateParameters2(in parameter))
{
DataSourceStateUnmapped = !poolMapper.TryAttachBuffer(out outErrorInfo, ref DataSourceStateAddressInfo, parameter.DataSourceStateAddress, parameter.DataSourceStateSize);
}
else
{
outErrorInfo = new ErrorInfo();
}
}
/// <summary>
/// Update the internal state from a user parameter.
/// </summary>
/// <param name="outErrorInfo">The possible <see cref="ErrorInfo"/> that was generated.</param>
/// <param name="parameter">The user paramter2.</param>
/// <param name="poolMapper">The mapper to use.</param>
/// <param name="behaviourInfo">The behaviour context.</param>
public void UpdateParameters1(out ErrorInfo outErrorInfo, in VoiceInParameter1 parameter, PoolMapper poolMapper, ref BehaviourInfo behaviourInfo)
{
InUse = parameter.InUse;
Id = parameter.Id;
NodeId = parameter.NodeId;
UpdatePlayState(parameter.PlayState);
SrcQuality = parameter.SrcQuality;
Priority = parameter.Priority;
SortingOrder = parameter.SortingOrder;
SampleRate = parameter.SampleRate;
SampleFormat = parameter.SampleFormat;
ChannelsCount = parameter.ChannelCount;
Pitch = parameter.Pitch;
Volume = parameter.Volume;
BiquadFilters[0] = BiquadFilterHelper.ToBiquadFilterParameter2(parameter.BiquadFilters[0]);
BiquadFilters[1] = BiquadFilterHelper.ToBiquadFilterParameter2(parameter.BiquadFilters[1]);
WaveBuffersCount = parameter.WaveBuffersCount;
WaveBuffersIndex = parameter.WaveBuffersIndex;
if (behaviourInfo.IsFlushVoiceWaveBuffersSupported())
{
FlushWaveBufferCount += parameter.FlushWaveBufferCount;
}
MixId = parameter.MixId;
if (behaviourInfo.IsSplitterSupported())
{
SplitterId = parameter.SplitterId;
}
else
{
SplitterId = Constants.UnusedSplitterId;
}
parameter.ChannelResourceIds.AsSpan().CopyTo(ChannelResourceIds.AsSpan());
DecodingBehaviour behaviour = DecodingBehaviour.Default;
if (behaviourInfo.IsDecodingBehaviourFlagSupported())
{
behaviour = parameter.DecodingBehaviourFlags;
}
DecodingBehaviour = behaviour;
if (parameter.ResetVoiceDropFlag)
{
VoiceDropFlag = false;
}
if (ShouldUpdateParameters1(in parameter))
{
DataSourceStateUnmapped = !poolMapper.TryAttachBuffer(out outErrorInfo, ref DataSourceStateAddressInfo, parameter.DataSourceStateAddress, parameter.DataSourceStateSize);
}
@@ -375,14 +464,14 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
PlayState = newServerPlayState;
}
/// <summary>
/// Write the status of the voice to the given user output.
/// </summary>
/// <param name="outStatus">The given user output.</param>
/// <param name="parameter">The user parameter.</param>
/// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param>
public void WriteOutStatus(ref VoiceOutStatus outStatus, in VoiceInParameter parameter, ReadOnlySpan<Memory<VoiceUpdateState>> voiceUpdateStates)
/// <param name="voiceStates">The voice states associated to the <see cref="VoiceInfo"/>.</param>
public void WriteOutStatus2(ref VoiceOutStatus outStatus, in VoiceInParameter2 parameter, ReadOnlySpan<Memory<VoiceState>> voiceStates)
{
#if DEBUG
// Sanity check in debug mode of the internal state
@@ -390,8 +479,8 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
{
for (int i = 1; i < ChannelsCount; i++)
{
ref VoiceUpdateState stateA = ref voiceUpdateStates[i - 1].Span[0];
ref VoiceUpdateState stateB = ref voiceUpdateStates[i].Span[0];
ref VoiceState stateA = ref voiceStates[i - 1].Span[0];
ref VoiceState stateB = ref voiceStates[i].Span[0];
Debug.Assert(stateA.WaveBufferConsumed == stateB.WaveBufferConsumed);
Debug.Assert(stateA.PlayedSampleCount == stateB.PlayedSampleCount);
@@ -412,7 +501,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
}
else
{
ref VoiceUpdateState state = ref voiceUpdateStates[0].Span[0];
ref VoiceState state = ref voiceStates[0].Span[0];
outStatus.VoiceDropFlag = VoiceDropFlag;
outStatus.PlayedWaveBuffersCount = state.WaveBufferConsumed;
@@ -421,19 +510,63 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
}
/// <summary>
/// Update the internal state of all the <see cref="WaveBuffer"/> of the <see cref="VoiceState"/>.
/// Write the status of the voice to the given user output.
/// </summary>
/// <param name="outStatus">The given user output.</param>
/// <param name="parameter">The user parameter.</param>
/// <param name="voiceStates">The voice states associated to the <see cref="VoiceInfo"/>.</param>
public void WriteOutStatus1(ref VoiceOutStatus outStatus, in VoiceInParameter1 parameter, ReadOnlySpan<Memory<VoiceState>> voiceStates)
{
#if DEBUG
// Sanity check in debug mode of the internal state
if (!parameter.IsNew && !IsNew)
{
for (int i = 1; i < ChannelsCount; i++)
{
ref VoiceState stateA = ref voiceStates[i - 1].Span[0];
ref VoiceState stateB = ref voiceStates[i].Span[0];
Debug.Assert(stateA.WaveBufferConsumed == stateB.WaveBufferConsumed);
Debug.Assert(stateA.PlayedSampleCount == stateB.PlayedSampleCount);
Debug.Assert(stateA.Offset == stateB.Offset);
Debug.Assert(stateA.WaveBufferIndex == stateB.WaveBufferIndex);
Debug.Assert(stateA.Fraction == stateB.Fraction);
Debug.Assert(stateA.IsWaveBufferValid.SequenceEqual(stateB.IsWaveBufferValid));
}
}
#endif
if (parameter.IsNew || IsNew)
{
IsNew = true;
outStatus.VoiceDropFlag = false;
outStatus.PlayedWaveBuffersCount = 0;
outStatus.PlayedSampleCount = 0;
}
else
{
ref VoiceState state = ref voiceStates[0].Span[0];
outStatus.VoiceDropFlag = VoiceDropFlag;
outStatus.PlayedWaveBuffersCount = state.WaveBufferConsumed;
outStatus.PlayedSampleCount = state.PlayedSampleCount;
}
}
/// <summary>
/// Update the internal state of all the <see cref="WaveBuffer"/> of the <see cref="VoiceInfo"/>.
/// </summary>
/// <param name="errorInfos">An array of <see cref="ErrorInfo"/> used to report errors when mapping any of the <see cref="WaveBuffer"/>.</param>
/// <param name="parameter">The user parameter.</param>
/// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param>
/// <param name="voiceStates">The voice states associated to the <see cref="VoiceInfo"/>.</param>
/// <param name="mapper">The mapper to use.</param>
/// <param name="behaviourContext">The behaviour context.</param>
public void UpdateWaveBuffers(
/// <param name="behaviourInfo">The behaviour context.</param>
public void UpdateWaveBuffers2(
out ErrorInfo[] errorInfos,
in VoiceInParameter parameter,
ReadOnlySpan<Memory<VoiceUpdateState>> voiceUpdateStates,
in VoiceInParameter2 parameter,
ReadOnlySpan<Memory<VoiceState>> voiceStates,
PoolMapper mapper,
ref BehaviourContext behaviourContext)
ref BehaviourInfo behaviourInfo)
{
errorInfos = new ErrorInfo[Constants.VoiceWaveBufferCount * 2];
@@ -443,23 +576,61 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
for (int i = 0; i < parameter.ChannelCount; i++)
{
voiceUpdateStates[i].Span[0].IsWaveBufferValid.Clear();
voiceStates[i].Span[0].IsWaveBufferValid.Clear();
}
}
ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[0].Span[0];
ref VoiceState voiceState = ref voiceStates[0].Span[0];
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
Span<WaveBufferInternal> pWaveBuffersSpan = parameter.WaveBuffers.AsSpan();
for (int i = 0; i < Constants.VoiceWaveBufferCount; i++)
{
UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref waveBuffersSpan[i], ref pWaveBuffersSpan[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], mapper, ref behaviourContext);
UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref waveBuffersSpan[i], ref pWaveBuffersSpan[i], parameter.SampleFormat, voiceState.IsWaveBufferValid[i], mapper, ref behaviourInfo);
}
}
/// <summary>
/// Update the internal state of one of the <see cref="WaveBuffer"/> of the <see cref="VoiceState"/>.
/// Update the internal state of all the <see cref="WaveBuffer"/> of the <see cref="VoiceInfo"/>.
/// </summary>
/// <param name="errorInfos">An array of <see cref="ErrorInfo"/> used to report errors when mapping any of the <see cref="WaveBuffer"/>.</param>
/// <param name="parameter">The user parameter.</param>
/// <param name="voiceStates">The voice states associated to the <see cref="VoiceInfo"/>.</param>
/// <param name="mapper">The mapper to use.</param>
/// <param name="behaviourInfo">The behaviour context.</param>
public void UpdateWaveBuffers1(
out ErrorInfo[] errorInfos,
in VoiceInParameter1 parameter,
ReadOnlySpan<Memory<VoiceState>> voiceStates,
PoolMapper mapper,
ref BehaviourInfo behaviourInfo)
{
errorInfos = new ErrorInfo[Constants.VoiceWaveBufferCount * 2];
if (parameter.IsNew)
{
InitializeWaveBuffers();
for (int i = 0; i < parameter.ChannelCount; i++)
{
voiceStates[i].Span[0].IsWaveBufferValid.Clear();
}
}
ref VoiceState voiceState = ref voiceStates[0].Span[0];
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
Span<WaveBufferInternal> pWaveBuffersSpan = parameter.WaveBuffers.AsSpan();
for (int i = 0; i < Constants.VoiceWaveBufferCount; i++)
{
UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref waveBuffersSpan[i], ref pWaveBuffersSpan[i], parameter.SampleFormat, voiceState.IsWaveBufferValid[i], mapper, ref behaviourInfo);
}
}
/// <summary>
/// Update the internal state of one of the <see cref="WaveBuffer"/> of the <see cref="VoiceInfo"/>.
/// </summary>
/// <param name="errorInfos">A <see cref="Span{ErrorInfo}"/> used to report errors when mapping the <see cref="WaveBuffer"/>.</param>
/// <param name="waveBuffer">The <see cref="WaveBuffer"/> to update.</param>
@@ -467,7 +638,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
/// <param name="sampleFormat">The <see cref="SampleFormat"/> from the user input.</param>
/// <param name="isValid">If set to true, the server side wavebuffer is considered valid.</param>
/// <param name="mapper">The mapper to use.</param>
/// <param name="behaviourContext">The behaviour context.</param>
/// <param name="behaviourInfo">The behaviour context.</param>
private void UpdateWaveBuffer(
Span<ErrorInfo> errorInfos,
ref WaveBuffer waveBuffer,
@@ -475,7 +646,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
SampleFormat sampleFormat,
bool isValid,
PoolMapper mapper,
ref BehaviourContext behaviourContext)
ref BehaviourInfo behaviourInfo)
{
if (!isValid && waveBuffer.IsSendToAudioProcessor && waveBuffer.BufferAddressInfo.CpuAddress != 0)
{
@@ -502,7 +673,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
errorInfos[0] = bufferInfoError;
if (sampleFormat == SampleFormat.Adpcm && behaviourContext.IsAdpcmLoopContextBugFixed() && inputWaveBuffer.ContextAddress != 0)
if (sampleFormat == SampleFormat.Adpcm && behaviourInfo.IsAdpcmLoopContextBugFixed() && inputWaveBuffer.ContextAddress != 0)
{
bool adpcmLoopContextMapped = mapper.TryAttachBuffer(out ErrorInfo adpcmLoopContextInfoError,
ref waveBuffer.ContextAddressInfo,
@@ -511,13 +682,13 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
errorInfos[1] = adpcmLoopContextInfoError;
if (adpcmLoopContextMapped)
if (!adpcmLoopContextMapped || BufferInfoUnmapped)
{
BufferInfoUnmapped = DataSourceStateUnmapped;
BufferInfoUnmapped = true;
}
else
{
BufferInfoUnmapped = true;
BufferInfoUnmapped = false;
}
}
else
@@ -534,7 +705,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
}
/// <summary>
/// Reset the resources associated to this <see cref="VoiceState"/>.
/// Reset the resources associated to this <see cref="VoiceInfo"/>.
/// </summary>
/// <param name="context">The voice context.</param>
private void ResetResources(VoiceContext context)
@@ -549,9 +720,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
Debug.Assert(voiceChannelResource.IsUsed);
Memory<VoiceUpdateState> dspSharedState = context.GetUpdateStateForDsp(channelResourceId);
Memory<VoiceState> dspSharedState = context.GetUpdateStateForDsp(channelResourceId);
MemoryMarshal.Cast<VoiceUpdateState, byte>(dspSharedState.Span).Clear();
MemoryMarshal.Cast<VoiceState, byte>(dspSharedState.Span).Clear();
voiceChannelResource.UpdateState();
}
@@ -561,9 +732,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
/// Flush a certain amount of <see cref="WaveBuffer"/>.
/// </summary>
/// <param name="waveBufferCount">The amount of wavebuffer to flush.</param>
/// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param>
/// <param name="voiceStates">The voice states associated to the <see cref="VoiceInfo"/>.</param>
/// <param name="channelCount">The channel count from user input.</param>
private void FlushWaveBuffers(uint waveBufferCount, Memory<VoiceUpdateState>[] voiceUpdateStates, uint channelCount)
private void FlushWaveBuffers(uint waveBufferCount, Memory<VoiceState>[] voiceStates, uint channelCount)
{
uint waveBufferIndex = WaveBuffersIndex;
@@ -575,12 +746,17 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
for (int j = 0; j < channelCount; j++)
{
ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[j].Span[0];
voiceUpdateState.WaveBufferIndex = (voiceUpdateState.WaveBufferIndex + 1) % Constants.VoiceWaveBufferCount;
voiceUpdateState.WaveBufferConsumed++;
voiceUpdateState.IsWaveBufferValid[(int)waveBufferIndex] = false;
ref VoiceState voiceState = ref voiceStates[j].Span[0];
if (!waveBuffersSpan[(int)waveBufferIndex].IsSendToAudioProcessor || voiceState.IsWaveBufferValid[(int)waveBufferIndex])
{
voiceState.WaveBufferIndex = (voiceState.WaveBufferIndex + 1) % Constants.VoiceWaveBufferCount;
voiceState.WaveBufferConsumed++;
voiceState.IsWaveBufferValid[(int)waveBufferIndex] = false;
}
}
waveBuffersSpan[(int)waveBufferIndex].IsSendToAudioProcessor = true;
waveBufferIndex = (waveBufferIndex + 1) % Constants.VoiceWaveBufferCount;
}
@@ -589,13 +765,13 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
/// <summary>
/// Update the internal parameters for command generation.
/// </summary>
/// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param>
/// <param name="voiceStates">The voice states associated to the <see cref="VoiceInfo"/>.</param>
/// <returns>Return true if this voice should be played.</returns>
public bool UpdateParametersForCommandGeneration(Memory<VoiceUpdateState>[] voiceUpdateStates)
public bool UpdateParametersForCommandGeneration(Memory<VoiceState>[] voiceStates)
{
if (FlushWaveBufferCount != 0)
{
FlushWaveBuffers(FlushWaveBufferCount, voiceUpdateStates, ChannelsCount);
FlushWaveBuffers(FlushWaveBufferCount, voiceStates, ChannelsCount);
FlushWaveBufferCount = 0;
}
@@ -615,9 +791,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
{
for (int y = 0; y < ChannelsCount; y++)
{
Debug.Assert(!voiceUpdateStates[y].Span[0].IsWaveBufferValid[i]);
Debug.Assert(!voiceStates[y].Span[0].IsWaveBufferValid[i]);
voiceUpdateStates[y].Span[0].IsWaveBufferValid[i] = true;
voiceStates[y].Span[0].IsWaveBufferValid[i] = true;
}
waveBuffer.IsSendToAudioProcessor = true;
@@ -626,11 +802,11 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
WasPlaying = false;
ref VoiceUpdateState primaryVoiceUpdateState = ref voiceUpdateStates[0].Span[0];
ref VoiceState primaryVoiceState = ref voiceStates[0].Span[0];
for (int i = 0; i < primaryVoiceUpdateState.IsWaveBufferValid.Length; i++)
for (int i = 0; i < primaryVoiceState.IsWaveBufferValid.Length; i++)
{
if (primaryVoiceUpdateState.IsWaveBufferValid[i])
if (primaryVoiceState.IsWaveBufferValid[i])
{
return true;
}
@@ -649,27 +825,27 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
for (int j = 0; j < ChannelsCount; j++)
{
ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[j].Span[0];
ref VoiceState voiceState = ref voiceStates[j].Span[0];
if (voiceUpdateState.IsWaveBufferValid[i])
if (voiceState.IsWaveBufferValid[i])
{
voiceUpdateState.WaveBufferIndex = (voiceUpdateState.WaveBufferIndex + 1) % Constants.VoiceWaveBufferCount;
voiceUpdateState.WaveBufferConsumed++;
voiceState.WaveBufferIndex = (voiceState.WaveBufferIndex + 1) % Constants.VoiceWaveBufferCount;
voiceState.WaveBufferConsumed++;
}
voiceUpdateState.IsWaveBufferValid[i] = false;
voiceState.IsWaveBufferValid[i] = false;
}
}
for (int i = 0; i < ChannelsCount; i++)
{
ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[i].Span[0];
ref VoiceState voiceState = ref voiceStates[i].Span[0];
voiceUpdateState.Offset = 0;
voiceUpdateState.PlayedSampleCount = 0;
voiceUpdateState.Pitch.AsSpan().Clear();
voiceUpdateState.Fraction = 0;
voiceUpdateState.LoopContext = new AdpcmLoopContext();
voiceState.Offset = 0;
voiceState.PlayedSampleCount = 0;
voiceState.Pitch.AsSpan().Clear();
voiceState.Fraction = 0;
voiceState.LoopContext = new AdpcmLoopContext();
}
PlayState = PlayState.Stopped;
@@ -715,16 +891,16 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
IsNew = false;
}
Memory<VoiceUpdateState>[] voiceUpdateStates = new Memory<VoiceUpdateState>[Constants.VoiceChannelCountMax];
Memory<VoiceState>[] voiceStates = new Memory<VoiceState>[Constants.VoiceChannelCountMax];
Span<int> channelResourceIdsSpan = ChannelResourceIds.AsSpan();
for (int i = 0; i < ChannelsCount; i++)
{
voiceUpdateStates[i] = context.GetUpdateStateForDsp(channelResourceIdsSpan[i]);
voiceStates[i] = context.GetUpdateStateForDsp(channelResourceIdsSpan[i]);
}
return UpdateParametersForCommandGeneration(voiceUpdateStates);
return UpdateParametersForCommandGeneration(voiceStates);
}
}
}