Amadeus: Final Act (#1481)

* Amadeus: Final Act

This is my requiem, I present to you Amadeus, a complete reimplementation of the Audio Renderer!

This reimplementation is based on my reversing of every version of the audio system module that I carried for the past 10 months.
This supports every revision (at the time of writing REV1 to REV8 included) and all features proposed by the Audio Renderer on real hardware.

Because this component could be used outside an emulation context, and to avoid possible "inspirations" not crediting the project, I decided to license the Ryujinx.Audio.Renderer project under LGPLv3.

- FE3H voices in videos and chapter intro are not present.
- Games that use two audio renderer **at the same time** are probably going to have issues right now **until we rewrite the audio output interface** (Crash Team Racing is the only known game to use two renderer at the same time).

- Persona 5 Scrambler now goes ingame but audio is garbage. This is caused by the fact that the game engine is syncing audio and video in a really aggressive way. This will disappears the day this game run at full speed.

* Make timing more precise when sleeping on Windows

Improve precision to a 1ms resolution on Windows NT based OS.
This is used to avoid having totally erratic timings and unify all
Windows users to the same resolution.

NOTE: This is only active when emulation is running.
This commit is contained in:
Mary
2020-08-18 03:49:37 +02:00
committed by GitHub
parent 2a314f3c28
commit a389dd59bd
250 changed files with 23691 additions and 1512 deletions

View File

@ -0,0 +1,116 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Audio.Renderer.Server.Types;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Audio Renderer user configuration.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct AudioRendererConfiguration
{
/// <summary>
/// The target sample rate of the user.
/// </summary>
/// <remarks>Only 32000Hz and 48000Hz are considered valid, other sample rates will cause undefined behaviour.</remarks>
public uint SampleRate;
/// <summary>
/// The target sample count per <see cref="Dsp.AudioProcessor"/> updates.
/// </summary>
public uint SampleCount;
/// <summary>
/// The maximum mix buffer count.
/// </summary>
public uint MixBufferCount;
/// <summary>
/// The maximum amount of sub mixes that could be used by the user.
/// </summary>
public uint SubMixBufferCount;
/// <summary>
/// The maximum amount of voices that could be used by the user.
/// </summary>
public uint VoiceCount;
/// <summary>
/// The maximum amount of sinks that could be used by the user.
/// </summary>
public uint SinkCount;
/// <summary>
/// The maximum amount of effects that could be used by the user.
/// </summary>
public uint EffectCount;
/// <summary>
/// The maximum amount of performance metric frames that could be used by the user.
/// </summary>
public uint PerformanceMetricFramesCount;
/// <summary>
/// Set to true if the user allows the <see cref="Server.AudioRenderSystem"/> to drop voices.
/// </summary>
/// <seealso cref="Server.AudioRenderSystem.ComputeVoiceDrop(Server.CommandBuffer, long, long)"/>
[MarshalAs(UnmanagedType.I1)]
public bool VoiceDropEnabled;
/// <summary>
/// Reserved/unused
/// </summary>
private byte _reserved;
/// <summary>
/// The target rendering device.
/// </summary>
/// <remarks>Must be <see cref="AudioRendererRenderingDevice.Dsp"/></remarks>
public AudioRendererRenderingDevice RenderingDevice;
/// <summary>
/// The target execution mode.
/// </summary>
/// <remarks>Must be <see cref="AudioRendererExecutionMode.Auto"/></remarks>
public AudioRendererExecutionMode ExecutionMode;
/// <summary>
/// The maximum amount of splitters that could be used by the user.
/// </summary>
public uint SplitterCount;
/// <summary>
/// The maximum amount of splitters destinations that could be used by the user.
/// </summary>
public uint SplitterDestinationCount;
/// <summary>
/// The size of the external context.
/// </summary>
/// <remarks>This is a leftover of the old "codec" interface system that was present between 1.0.0 and 3.0.0. This was entirely removed from the server side with REV8.</remarks>
public uint ExternalContextSize;
/// <summary>
/// The user audio revision
/// </summary>
/// <seealso cref="Server.BehaviourContext"/>
public int Revision;
}
}

View File

@ -0,0 +1,47 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Common.Memory;
using System;
using System.Runtime.InteropServices;
using static Ryujinx.Audio.Renderer.Common.BehaviourParameter;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Output information for behaviour.
/// </summary>
/// <remarks>This is used to report errors to the user during <see cref="Server.AudioRenderSystem.Update(Memory{byte}, Memory{byte}, ReadOnlyMemory{byte})"/> processing.</remarks>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BehaviourErrorInfoOutStatus
{
/// <summary>
/// The reported errors.
/// </summary>
public Array10<ErrorInfo> ErrorInfos;
/// <summary>
/// The amount of error that got reported.
/// </summary>
public uint ErrorInfosCount;
/// <summary>
/// Reserved/unused.
/// </summary>
private unsafe fixed uint _reserved[3];
}
}

View File

@ -0,0 +1,51 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Biquad filter parameters.
/// </summary>
[StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 1)]
public struct BiquadFilterParameter
{
/// <summary>
/// Set to true if the biquad filter is active.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool Enable;
/// <summary>
/// Reserved/padding.
/// </summary>
private byte _reserved;
/// <summary>
/// Biquad filter numerator (b0, b1, b2).
/// </summary>
public Array3<short> Numerator;
/// <summary>
/// Biquad filter denominator (a1, a2).
/// </summary>
/// <remarks>a0 = 1</remarks>
public Array2<short> Denominator;
}
}

View File

@ -0,0 +1,100 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter.Effect
{
/// <summary>
/// <see cref="EffectInParameter.SpecificData"/> for <see cref="Common.EffectType.AuxiliaryBuffer"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct AuxiliaryBufferParameter
{
/// <summary>
/// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/> to write data to <see cref="SendBufferInfoAddress"/>.
/// </summary>
public Array24<byte> Input;
/// <summary>
/// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/> to read data from <see cref="ReturnBufferInfoAddress"/>.
/// </summary>
public Array24<byte> Output;
/// <summary>
/// The total channel count used.
/// </summary>
public uint ChannelCount;
/// <summary>
/// The target sample rate.
/// </summary>
public uint SampleRate;
/// <summary>
/// The buffer storage total size.
/// </summary>
public uint BufferStorageSize;
/// <summary>
/// The maximum number of channels supported.
/// </summary>
/// <remarks>This is unused.</remarks>
public uint ChannelCountMax;
/// <summary>
/// The address of the start of the region containing two <see cref="Dsp.State.AuxiliaryBufferHeader"/> followed by the data that will be written by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public ulong SendBufferInfoAddress;
/// <summary>
/// The address of the start of the region containling data that will be written by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
/// <remarks>This is unused.</remarks>
public ulong SendBufferStorageAddress;
/// <summary>
/// The address of the start of the region containing two <see cref="Dsp.State.AuxiliaryBufferHeader"/> followed by the data that will be read by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public ulong ReturnBufferInfoAddress;
/// <summary>
/// The address of the start of the region containling data that will be read by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
/// <remarks>This is unused.</remarks>
public ulong ReturnBufferStorageAddress;
/// <summary>
/// Size of a sample of the mix buffer.
/// </summary>
/// <remarks>This is unused.</remarks>
public uint MixBufferSampleSize;
/// <summary>
/// The total count of sample that can be stored.
/// </summary>
/// <remarks>This is unused.</remarks>
public uint TotalSampleCount;
/// <summary>
/// The count of sample of the mix buffer.
/// </summary>
/// <remarks>This is unused.</remarks>
public uint MixBufferSampleCount;
}
}

View File

@ -0,0 +1,61 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Audio.Renderer.Server.Effect;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter.Effect
{
/// <summary>
/// <see cref="EffectInParameter.SpecificData"/> for <see cref="Common.EffectType.BiquadFilter"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BiquadFilterEffectParameter
{
/// <summary>
/// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public Array6<byte> Input;
/// <summary>
/// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public Array6<byte> Output;
/// <summary>
/// Biquad filter numerator (b0, b1, b2).
/// </summary>
public Array3<short> Numerator;
/// <summary>
/// Biquad filter denominator (a1, a2).
/// </summary>
/// <remarks>a0 = 1</remarks>
public Array2<short> Denominator;
/// <summary>
/// The total channel count used.
/// </summary>
public byte ChannelCount;
/// <summary>
/// The current usage status of the effect on the client side.
/// </summary>
public UsageState Status;
}
}

View File

@ -0,0 +1,49 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter.Effect
{
/// <summary>
/// <see cref="EffectInParameter.SpecificData"/> for <see cref="Common.EffectType.BufferMix"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BufferMixParameter
{
/// <summary>
/// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public Array24<byte> Input;
/// <summary>
/// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public Array24<byte> Output;
/// <summary>
/// The output volumes of the mixes.
/// </summary>
public Array24<float> Volumes;
/// <summary>
/// The total count of mixes used.
/// </summary>
public uint MixesCount;
}
}

View File

@ -0,0 +1,118 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Audio.Renderer.Server.Effect;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter.Effect
{
/// <summary>
/// <see cref="EffectInParameter.SpecificData"/> for <see cref="Common.EffectType.Delay"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DelayParameter
{
/// <summary>
/// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public Array6<byte> Input;
/// <summary>
/// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public Array6<byte> Output;
/// <summary>
/// The maximum number of channels supported.
/// </summary>
public ushort ChannelCountMax;
/// <summary>
/// The total channel count used.
/// </summary>
public ushort ChannelCount;
/// <summary>
/// The maximum delay time in milliseconds.
/// </summary>
public uint DelayTimeMax;
/// <summary>
/// The delay time in milliseconds.
/// </summary>
public uint DelayTime;
/// <summary>
/// The target sample rate. (Q15)
/// </summary>
public uint SampleRate;
/// <summary>
/// The input gain. (Q15)
/// </summary>
public uint InGain;
/// <summary>
/// The feedback gain. (Q15)
/// </summary>
public uint FeedbackGain;
/// <summary>
/// The output gain. (Q15)
/// </summary>
public uint OutGain;
/// <summary>
/// The dry gain. (Q15)
/// </summary>
public uint DryGain;
/// <summary>
/// The channel spread of the <see cref="FeedbackGain"/>. (Q15)
/// </summary>
public uint ChannelSpread;
/// <summary>
/// The low pass amount. (Q15)
/// </summary>
public uint LowPassAmount;
/// <summary>
/// The current usage status of the effect on the client side.
/// </summary>
public UsageState Status;
/// <summary>
/// Check if the <see cref="ChannelCount"/> is valid.
/// </summary>
/// <returns>Returns true if the <see cref="ChannelCount"/> is valid.</returns>
public bool IsChannelCountValid()
{
return EffectInParameter.IsChannelCountValid(ChannelCount);
}
/// <summary>
/// Check if the <see cref="ChannelCountMax"/> is valid.
/// </summary>
/// <returns>Returns true if the <see cref="ChannelCountMax"/> is valid.</returns>
public bool IsChannelCountMaxValid()
{
return EffectInParameter.IsChannelCountValid(ChannelCountMax);
}
}
}

View File

@ -0,0 +1,144 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Audio.Renderer.Server.Effect;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter.Effect
{
/// <summary>
/// <see cref="EffectInParameter.SpecificData"/> for <see cref="Common.EffectType.Reverb3d"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Reverb3dParameter
{
/// <summary>
/// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public Array6<byte> Input;
/// <summary>
/// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public Array6<byte> Output;
/// <summary>
/// The maximum number of channels supported.
/// </summary>
public ushort ChannelCountMax;
/// <summary>
/// The total channel count used.
/// </summary>
public ushort ChannelCount;
/// <summary>
/// Reserved/unused.
/// </summary>
private uint _reserved;
/// <summary>
/// The target sample rate.
/// </summary>
/// <remarks>This is in kHz.</remarks>
public uint SampleRate;
/// <summary>
/// Gain of the room high-frequency effect.
/// </summary>
public float RoomHf;
/// <summary>
/// Reference high frequency.
/// </summary>
public float HfReference;
/// <summary>
/// Reverberation decay time at low frequencies.
/// </summary>
public float DecayTime;
/// <summary>
/// Ratio of the decay time at high frequencies to the decay time at low frequencies.
/// </summary>
public float HfDecayRatio;
/// <summary>
/// Gain of the room effect.
/// </summary>
public float RoomGain;
/// <summary>
/// Gain of the early reflections relative to <see cref="RoomGain"/>.
/// </summary>
public float ReflectionsGain;
/// <summary>
/// Gain of the late reverberation relative to <see cref="RoomGain"/>.
/// </summary>
public float ReverbGain;
/// <summary>
/// Echo density in the late reverberation decay.
/// </summary>
public float Diffusion;
/// <summary>
/// Modal density in the late reverberation decay.
/// </summary>
public float ReflectionDelay;
/// <summary>
/// Time limit between the early reflections and the late reverberation relative to the time of the first reflection.
/// </summary>
public float ReverbDelayTime;
/// <summary>
/// Modal density in the late reverberation decay.
/// </summary>
public float Density;
/// <summary>
/// The dry gain.
/// </summary>
public float DryGain;
/// <summary>
/// The current usage status of the effect on the client side.
/// </summary>
public UsageState ParameterStatus;
/// <summary>
/// Check if the <see cref="ChannelCount"/> is valid.
/// </summary>
/// <returns>Returns true if the <see cref="ChannelCount"/> is valid.</returns>
public bool IsChannelCountValid()
{
return EffectInParameter.IsChannelCountValid(ChannelCount);
}
/// <summary>
/// Check if the <see cref="ChannelCountMax"/> is valid.
/// </summary>
/// <returns>Returns true if the <see cref="ChannelCountMax"/> is valid.</returns>
public bool IsChannelCountMaxValid()
{
return EffectInParameter.IsChannelCountValid(ChannelCountMax);
}
}
}

View File

@ -0,0 +1,136 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Audio.Renderer.Server.Effect;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter.Effect
{
/// <summary>
/// <see cref="EffectInParameter.SpecificData"/> for <see cref="Common.EffectType.Reverb"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ReverbParameter
{
/// <summary>
/// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public Array6<byte> Input;
/// <summary>
/// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public Array6<byte> Output;
/// <summary>
/// The maximum number of channels supported.
/// </summary>
public ushort ChannelCountMax;
/// <summary>
/// The total channel count used.
/// </summary>
public ushort ChannelCount;
/// <summary>
/// The target sample rate. (Q15)
/// </summary>
/// <remarks>This is in kHz.</remarks>
public int SampleRate;
/// <summary>
/// The early mode to use.
/// </summary>
public ReverbEarlyMode EarlyMode;
/// <summary>
/// The gain to apply to the result of the early reflection. (Q15)
/// </summary>
public int EarlyGain;
/// <summary>
/// The pre-delay time in milliseconds. (Q15)
/// </summary>
public int PreDelayTime;
/// <summary>
/// The late mode to use.
/// </summary>
public ReverbLateMode LateMode;
/// <summary>
/// The gain to apply to the result of the late reflection. (Q15)
/// </summary>
public int LateGain;
/// <summary>
/// The decay time. (Q15)
/// </summary>
public int DecayTime;
/// <summary>
/// The high frequency decay ratio. (Q15)
/// </summary>
/// <remarks>If <see cref="HighFrequencyDecayRatio"/> >= 0.995f, it is considered disabled.</remarks>
public int HighFrequencyDecayRatio;
/// <summary>
/// The coloration of the decay. (Q15)
/// </summary>
public int Coloration;
/// <summary>
/// The reverb gain. (Q15)
/// </summary>
public int ReverbGain;
/// <summary>
/// The output gain. (Q15)
/// </summary>
public int OutGain;
/// <summary>
/// The dry gain. (Q15)
/// </summary>
public int DryGain;
/// <summary>
/// The current usage status of the effect on the client side.
/// </summary>
public UsageState Status;
/// <summary>
/// Check if the <see cref="ChannelCount"/> is valid.
/// </summary>
/// <returns>Returns true if the <see cref="ChannelCount"/> is valid.</returns>
public bool IsChannelCountValid()
{
return EffectInParameter.IsChannelCountValid(ChannelCount);
}
/// <summary>
/// Check if the <see cref="ChannelCountMax"/> is valid.
/// </summary>
/// <returns>Returns true if the <see cref="ChannelCountMax"/> is valid.</returns>
public bool IsChannelCountMaxValid()
{
return EffectInParameter.IsChannelCountValid(ChannelCountMax);
}
}
}

View File

@ -0,0 +1,103 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Common.Utilities;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Input information for an effect.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct EffectInParameter
{
/// <summary>
/// Type of the effect.
/// </summary>
public EffectType Type;
/// <summary>
/// Set to true if the effect is new.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool IsNew;
/// <summary>
/// Set to true if the effect must be active.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool IsEnabled;
/// <summary>
/// Reserved/padding.
/// </summary>
private byte _reserved1;
/// <summary>
/// The target mix id of the effect.
/// </summary>
public int MixId;
/// <summary>
/// Address of the processing workbuffer.
/// </summary>
/// <remarks>This is additional data that could be required by the effect processing.</remarks>
public ulong BufferBase;
/// <summary>
/// Size of the processing workbuffer.
/// </summary>
/// <remarks>This is additional data that could be required by the effect processing.</remarks>
public ulong BufferSize;
/// <summary>
/// Position of the effect while processing effects.
/// </summary>
public uint ProcessingOrder;
/// <summary>
/// Reserved/padding.
/// </summary>
private uint _reserved2;
/// <summary>
/// Specific data storage.
/// </summary>
private SpecificDataStruct _specificDataStart;
[StructLayout(LayoutKind.Sequential, Size = 0xA0, Pack = 1)]
private struct SpecificDataStruct { }
/// <summary>
/// Specific data changing depending of the <see cref="Type"/>. See also the <see cref="Effect"/> namespace.
/// </summary>
public Span<byte> SpecificData => SpanHelpers.AsSpan<SpecificDataStruct, byte>(ref _specificDataStart);
/// <summary>
/// Check if the given channel count is valid.
/// </summary>
/// <param name="channelCount">The channel count to check</param>
/// <returns>Returns true if the channel count is valid.</returns>
public static bool IsChannelCountValid(int channelCount)
{
return channelCount == 1 || channelCount == 2 || channelCount == 4 || channelCount == 6;
}
}
}

View File

@ -0,0 +1,55 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Output information for an effect.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct EffectOutStatus
{
/// <summary>
/// The state of an effect.
/// </summary>
public enum EffectState : byte
{
/// <summary>
/// The effect is enabled.
/// </summary>
Enabled = 3,
/// <summary>
/// The effect is disabled.
/// </summary>
Disabled = 4
}
/// <summary>
/// Current effect state.
/// </summary>
// TODO: enum?
public EffectState State;
/// <summary>
/// Unused/Reserved.
/// </summary>
private unsafe fixed byte _reserved[15];
}
}

View File

@ -0,0 +1,50 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Audio.Renderer.Common;
using System.Runtime.InteropServices;
using CpuAddress = System.UInt64;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Input information for a memory pool.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MemoryPoolInParameter
{
/// <summary>
/// The CPU address used by the memory pool.
/// </summary>
public CpuAddress CpuAddress;
/// <summary>
/// The size used by the memory pool.
/// </summary>
public ulong Size;
/// <summary>
/// The target state the user wants.
/// </summary>
public MemoryPoolUserState State;
/// <summary>
/// Reserved/unused.
/// </summary>
private unsafe fixed uint _reserved[3];
}
}

View File

@ -0,0 +1,39 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Audio.Renderer.Common;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Output information for a memory pool.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MemoryPoolOutStatus
{
/// <summary>
/// The current server memory pool state.
/// </summary>
public MemoryPoolUserState State;
/// <summary>
/// Reserved/unused.
/// </summary>
private unsafe fixed uint _reserved[3];
}
}

View File

@ -0,0 +1,44 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Input information header for mix updates on REV7 and later
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MixInParameterDirtyOnlyUpdate
{
/// <summary>
/// Magic of the header
/// </summary>
/// <remarks>Never checked on hardware.</remarks>
public uint Magic;
/// <summary>
/// The count of <see cref="MixParameter"/> following this header.
/// </summary>
public uint MixCount;
/// <summary>
/// Reserved/unused.
/// </summary>
private unsafe fixed byte _reserved[24];
}
}

View File

@ -0,0 +1,112 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Common.Utilities;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Input information for a mix.
/// </summary>
/// <remarks>Also used on the client side for mix tracking.</remarks>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MixParameter
{
/// <summary>
/// Base volume of the mix.
/// </summary>
public float Volume;
/// <summary>
/// Target sample rate of the mix.
/// </summary>
public uint SampleRate;
/// <summary>
/// Target buffer count.
/// </summary>
public uint BufferCount;
/// <summary>
/// Set to true if in use.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool IsUsed;
/// <summary>
/// Set to true if it was changed.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool IsDirty;
/// <summary>
/// Reserved/padding.
/// </summary>
private ushort _reserved1;
/// <summary>
/// The id of the mix.
/// </summary>
public int MixId;
/// <summary>
/// The effect count. (client side)
/// </summary>
public uint EffectCount;
/// <summary>
/// The mix node id.
/// </summary>
public int NodeId;
/// <summary>
/// Reserved/padding.
/// </summary>
private ulong _reserved2;
/// <summary>
/// Mix buffer volumes storage.
/// </summary>
private MixVolumeArray _mixBufferVolumeArray;
/// <summary>
/// The mix to output the result of this mix.
/// </summary>
public int DestinationMixId;
/// <summary>
/// The splitter to output the result of this mix.
/// </summary>
public uint DestinationSplitterId;
/// <summary>
/// Reserved/padding.
/// </summary>
private uint _reserved3;
[StructLayout(LayoutKind.Sequential, Size = 4 * RendererConstants.MixBufferCountMax * RendererConstants.MixBufferCountMax, Pack = 1)]
private struct MixVolumeArray { }
/// <summary>
/// Mix buffer volumes.
/// </summary>
/// <remarks>Used when no splitter id is specified.</remarks>
public Span<float> MixBufferVolume => SpanHelpers.AsSpan<MixVolumeArray, float>(ref _mixBufferVolumeArray);
}
}

View File

@ -0,0 +1,38 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter.Performance
{
/// <summary>
/// Input information for performance monitoring.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PerformanceInParameter
{
/// <summary>
/// The target node id to monitor performance on.
/// </summary>
public int TargetNodeId;
/// <summary>
/// Reserved/unused.
/// </summary>
private unsafe fixed uint _reserved[3];
}
}

View File

@ -0,0 +1,38 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter.Performance
{
/// <summary>
/// Output information for performance monitoring.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PerformanceOutStatus
{
/// <summary>
/// Indicates the total size output to the performance buffer.
/// </summary>
public uint HistorySize;
/// <summary>
/// Reserved/unused.
/// </summary>
private unsafe fixed uint _reserved[3];
}
}

View File

@ -0,0 +1,38 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Renderer output information on REV5 and later.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RendererInfoOutStatus
{
/// <summary>
/// The count of updates sent to the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public ulong ElapsedFrameCount;
/// <summary>
/// Reserved/Unused.
/// </summary>
private ulong _reserved;
}
}

View File

@ -0,0 +1,78 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
using CpuAddress = System.UInt64;
namespace Ryujinx.Audio.Renderer.Parameter.Sink
{
/// <summary>
/// <see cref="SinkInParameter.SpecificData"/> for <see cref="SinkType.CircularBuffer"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CircularBufferParameter
{
/// <summary>
/// The CPU address of the user circular buffer.
/// </summary>
public CpuAddress BufferAddress;
/// <summary>
/// The size of the user circular buffer.
/// </summary>
public uint BufferSize;
/// <summary>
/// The total count of channels to output to the circular buffer.
/// </summary>
public uint InputCount;
/// <summary>
/// The target sample count to output per update in the circular buffer.
/// </summary>
public uint SampleCount;
/// <summary>
/// Last read offset on the CPU side.
/// </summary>
public uint LastReadOffset;
/// <summary>
/// The target <see cref="SampleFormat"/>.
/// </summary>
/// <remarks>Only <see cref="SampleFormat.PcmInt16"/> is supported.</remarks>
public SampleFormat SampleFormat;
/// <summary>
/// Reserved/padding.
/// </summary>
private unsafe fixed byte _reserved1[3];
/// <summary>
/// The input channels index that will be used.
/// </summary>
public Array6<byte> Input;
/// <summary>
/// Reserved/padding.
/// </summary>
private ushort _reserved2;
}
}

View File

@ -0,0 +1,75 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter.Sink
{
/// <summary>
/// <see cref="SinkInParameter.SpecificData"/> for <see cref="Common.SinkType.Device"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DeviceParameter
{
/// <summary>
/// Device name storage.
/// </summary>
private DeviceNameStruct _deviceName;
/// <summary>
/// Reserved/padding.
/// </summary>
private byte _padding;
/// <summary>
/// The total count of channels to output to the device.
/// </summary>
public uint InputCount;
/// <summary>
/// The input channels index that will be used.
/// </summary>
public Array6<byte> Input;
/// <summary>
/// Reserved/padding.
/// </summary>
private byte _reserved;
/// <summary>
/// Set to true if the user controls Surround to Stereo downmixing coefficients.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool DownMixParameterEnabled;
/// <summary>
/// The user Surround to Stereo downmixing coefficients.
/// </summary>
public Array4<float> DownMixParameter;
[StructLayout(LayoutKind.Sequential, Size = 0xFF, Pack = 1)]
private struct DeviceNameStruct { }
/// <summary>
/// The output device name.
/// </summary>
public Span<byte> DeviceName => SpanHelpers.AsSpan<DeviceNameStruct, byte>(ref _deviceName);
}
}

View File

@ -0,0 +1,70 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Common.Utilities;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Input information for a sink.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SinkInParameter
{
/// <summary>
/// Type of the sink.
/// </summary>
public SinkType Type;
/// <summary>
/// Set to true if the sink is used.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool IsUsed;
/// <summary>
/// Reserved/padding.
/// </summary>
private ushort _reserved1;
/// <summary>
/// The node id of the sink.
/// </summary>
public int NodeId;
/// <summary>
/// Reserved/padding.
/// </summary>
private unsafe fixed ulong _reserved2[3];
/// <summary>
/// Specific data storage.
/// </summary>
private SpecificDataStruct _specificDataStart;
[StructLayout(LayoutKind.Sequential, Size = 0x120, Pack = 1)]
private struct SpecificDataStruct { }
/// <summary>
/// Specific data changing depending of the <see cref="Type"/>. See also the <see cref="Sink"/> namespace.
/// </summary>
public Span<byte> SpecificData => SpanHelpers.AsSpan<SpecificDataStruct, byte>(ref _specificDataStart);
}
}

View File

@ -0,0 +1,43 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Output information for a sink.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SinkOutStatus
{
/// <summary>
/// Last written offset if the sink type is <see cref="Common.SinkType.CircularBuffer"/>.
/// </summary>
public uint LastWrittenOffset;
/// <summary>
/// Reserved/padding.
/// </summary>
private uint _padding;
/// <summary>
/// Reserved/padding.
/// </summary>
private unsafe fixed ulong _reserved[3];
}
}

View File

@ -0,0 +1,84 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Common.Utilities;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Input header for a splitter destination update.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SplitterDestinationInParameter
{
/// <summary>
/// Magic of the input header.
/// </summary>
public uint Magic;
/// <summary>
/// Target splitter destination data id.
/// </summary>
public int Id;
/// <summary>
/// Mix buffer volumes storage.
/// </summary>
private MixArray _mixBufferVolume;
/// <summary>
/// The mix to output the result of the splitter.
/// </summary>
public int DestinationId;
/// <summary>
/// Set to true if in use.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool IsUsed;
/// <summary>
/// Reserved/padding.
/// </summary>
private unsafe fixed byte _reserved[3];
[StructLayout(LayoutKind.Sequential, Size = 4 * RendererConstants.MixBufferCountMax, Pack = 1)]
private struct MixArray { }
/// <summary>
/// Mix buffer volumes.
/// </summary>
/// <remarks>Used when a splitter id is specified in the mix.</remarks>
public Span<float> MixBufferVolume => SpanHelpers.AsSpan<MixArray, float>(ref _mixBufferVolume);
/// <summary>
/// The expected constant of any input header.
/// </summary>
private const uint ValidMagic = 0x44444E53;
/// <summary>
/// Check if the magic is valid.
/// </summary>
/// <returns>Returns true if the magic is valid.</returns>
public bool IsMagicValid()
{
return Magic == ValidMagic;
}
}
}

View File

@ -0,0 +1,63 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Input header for a splitter state update.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SplitterInParameter
{
/// <summary>
/// Magic of the input header.
/// </summary>
public uint Magic;
/// <summary>
/// Target splitter id.
/// </summary>
public int Id;
/// <summary>
/// Target sample rate to use on the splitter.
/// </summary>
public uint SampleRate;
/// <summary>
/// Count of splitter destinations.
/// </summary>
/// <remarks>Splitter destination ids are defined right after this header.</remarks>
public int DestinationCount;
/// <summary>
/// The expected constant of any input header.
/// </summary>
private const uint ValidMagic = 0x49444E53;
/// <summary>
/// Check if the magic is valid.
/// </summary>
/// <returns>Returns true if the magic is valid.</returns>
public bool IsMagicValid()
{
return Magic == ValidMagic;
}
}
}

View File

@ -0,0 +1,62 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Input header for splitter update.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SplitterInParameterHeader
{
/// <summary>
/// Magic of the input header.
/// </summary>
public uint Magic;
/// <summary>
/// The count of <see cref="SplitterInParameter"/> after the header.
/// </summary>
public uint SplitterCount;
/// <summary>
/// The count of splitter destinations after the header and splitter info.
/// </summary>
public uint SplitterDestinationCount;
/// <summary>
/// Reserved/unused.
/// </summary>
private unsafe fixed uint _reserved[5];
/// <summary>
/// The expected constant of any input splitter header.
/// </summary>
private const uint ValidMagic = 0x48444E53;
/// <summary>
/// Check if the magic is valid.
/// </summary>
/// <returns>Returns true if the magic is valid.</returns>
public bool IsMagicValid()
{
return Magic == ValidMagic;
}
}
}

View File

@ -0,0 +1,45 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Input information for a voice channel resources.
/// </summary>
[StructLayout(LayoutKind.Sequential, Size = 0x70, Pack = 1)]
public struct VoiceChannelResourceInParameter
{
/// <summary>
/// The id of the voice channel resource.
/// </summary>
public uint Id;
/// <summary>
/// Mix volumes for the voice channel resource.
/// </summary>
public Array24<float> Mix;
/// <summary>
/// Indicate if the voice channel resource is used.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool IsUsed;
}
}

View File

@ -0,0 +1,360 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Audio.Renderer.Dsp;
using Ryujinx.Common.Memory;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Input information for a voice.
/// </summary>
[StructLayout(LayoutKind.Sequential, Size = 0x170, Pack = 1)]
public struct VoiceInParameter
{
/// <summary>
/// Id of the voice.
/// </summary>
public int Id;
/// <summary>
/// Node id of the voice.
/// </summary>
public int NodeId;
/// <summary>
/// Set to true if the voice is new.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool IsNew;
/// <summary>
/// Set to true if the voice is used.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool InUse;
/// <summary>
/// The voice <see cref="PlayState"/> wanted by the user.
/// </summary>
public PlayState PlayState;
/// <summary>
/// The <see cref="SampleFormat"/> of the voice.
/// </summary>
public SampleFormat SampleFormat;
/// <summary>
/// The sample rate of the voice.
/// </summary>
public uint SampleRate;
/// <summary>
/// The priority of the voice.
/// </summary>
public uint Priority;
/// <summary>
/// Target sorting position of the voice. (Used to sort voices with the same <see cref="Priority"/>)
/// </summary>
public uint SortingOrder;
/// <summary>
/// The total channel count used.
/// </summary>
public uint ChannelCount;
/// <summary>
/// The pitch used on the voice.
/// </summary>
public float Pitch;
/// <summary>
/// The output volume of the voice.
/// </summary>
public float Volume;
/// <summary>
/// Biquad filters to apply to the output of the voice.
/// </summary>
public Array2<BiquadFilterParameter> BiquadFilters;
/// <summary>
/// Total count of <see cref="WaveBufferInternal"/> of the voice.
/// </summary>
public uint WaveBuffersCount;
/// <summary>
/// Current playing <see cref="WaveBufferInternal"/> of the voice.
/// </summary>
public uint WaveBuffersIndex;
/// <summary>
/// Reserved/unused.
/// </summary>
private uint _reserved1;
/// <summary>
/// User state address required by the data source.
/// </summary>
/// <remarks>Only used for <see cref="SampleFormat.Adpcm"/> as the address of the GC-ADPCM coefficients.</remarks>
public ulong DataSourceStateAddress;
/// <summary>
/// User state size required by the data source.
/// </summary>
/// <remarks>Only used for <see cref="SampleFormat.Adpcm"/> as the size of the GC-ADPCM coefficients.</remarks>
public ulong DataSourceStateSize;
/// <summary>
/// The target mix id of the voice.
/// </summary>
public int MixId;
/// <summary>
/// The target splitter id of the voice.
/// </summary>
public uint SplitterId;
/// <summary>
/// The wavebuffer parameters of this voice.
/// </summary>
public Array4<WaveBufferInternal> WaveBuffers;
/// <summary>
/// The channel resource ids associated to the voice.
/// </summary>
public Array6<int> ChannelResourceIds;
/// <summary>
/// Reset the voice drop flag during voice server update.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool ResetVoiceDropFlag;
/// <summary>
/// Flush the amount of wavebuffer specified. This will result in the wavebuffer being skipped and marked played.
/// </summary>
/// <remarks>This was added on REV5.</remarks>
public byte FlushWaveBufferCount;
/// <summary>
/// Reserved/unused.
/// </summary>
private ushort _reserved2;
/// <summary>
/// Change the behaviour of the voice.
/// </summary>
/// <remarks>This was added on REV5.</remarks>
public DecodingBehaviour DecodingBehaviourFlags;
/// <summary>
/// Change the Sample Rate Conversion (SRC) quality of the voice.
/// </summary>
/// <remarks>This was added on REV8.</remarks>
public SampleRateConversionQuality SrcQuality;
/// <summary>
/// This was previously used for opus codec support on the Audio Renderer and was removed on REV3.
/// </summary>
public uint ExternalContext;
/// <summary>
/// This was previously used for opus codec support on the Audio Renderer and was removed on REV3.
/// </summary>
public uint ExternalContextSize;
/// <summary>
/// Reserved/unused.
/// </summary>
private unsafe fixed uint _reserved3[2];
/// <summary>
/// Input information for a voice wavebuffer.
/// </summary>
[StructLayout(LayoutKind.Sequential, Size = 0x38, Pack = 1)]
public struct WaveBufferInternal
{
/// <summary>
/// Address of the wavebuffer data.
/// </summary>
public ulong Address;
/// <summary>
/// Size of the wavebuffer data.
/// </summary>
public ulong Size;
/// <summary>
/// Offset of the first sample to play.
/// </summary>
public uint StartSampleOffset;
/// <summary>
/// Offset of the last sample to play.
/// </summary>
public uint EndSampleOffset;
/// <summary>
/// If set to true, the wavebuffer will loop when reaching <see cref="EndSampleOffset"/>.
/// </summary>
/// <remarks>
/// Starting with REV8, you can specify how many times to loop the wavebuffer (<see cref="LoopCount"/>) and where it should start and end when looping (<see cref="LoopFirstSampleOffset"/> and <see cref="LoopLastSampleOffset"/>)
/// </remarks>
[MarshalAs(UnmanagedType.I1)]
public bool ShouldLoop;
/// <summary>
/// Indicates that this is the last wavebuffer to play of the voice.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool IsEndOfStream;
/// <summary>
/// Indicates if the server should update its internal state.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool SentToServer;
/// <summary>
/// Reserved/unused.
/// </summary>
private byte _reserved;
/// <summary>
/// If set to anything other than 0, specifies how many times to loop the wavebuffer.
/// </summary>
/// <remarks>This was added in REV8.</remarks>
public int LoopCount;
/// <summary>
/// Address of the context used by the sample decoder.
/// </summary>
/// <remarks>This is only currently used by <see cref="SampleFormat.Adpcm"/>.</remarks>
public ulong ContextAddress;
/// <summary>
/// Size of the context used by the sample decoder.
/// </summary>
/// <remarks>This is only currently used by <see cref="SampleFormat.Adpcm"/>.</remarks>
public ulong ContextSize;
/// <summary>
/// If set to anything other than 0, specifies the offset of the first sample to play when looping.
/// </summary>
/// <remarks>This was added in REV8.</remarks>
public uint LoopFirstSampleOffset;
/// <summary>
/// If set to anything other than 0, specifies the offset of the last sample to play when looping.
/// </summary>
/// <remarks>This was added in REV8.</remarks>
public uint LoopLastSampleOffset;
/// <summary>
/// Check if the sample offsets are in a valid range for generic PCM.
/// </summary>
/// <typeparam name="T">The PCM sample type</typeparam>
/// <returns>Returns true if the sample offset are in range of the size.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool IsSampleOffsetInRangeForPcm<T>() where T : unmanaged
{
uint dataTypeSize = (uint)Unsafe.SizeOf<T>();
return StartSampleOffset * dataTypeSize <= Size &&
EndSampleOffset * dataTypeSize <= Size;
}
/// <summary>
/// Check if the sample offsets are in a valid range for the given <see cref="SampleFormat"/>.
/// </summary>
/// <param name="format">The target <see cref="SampleFormat"/></param>
/// <returns>Returns true if the sample offset are in range of the size.</returns>
public bool IsSampleOffsetValid(SampleFormat format)
{
bool result;
switch (format)
{
case SampleFormat.PcmInt16:
result = IsSampleOffsetInRangeForPcm<ushort>();
break;
case SampleFormat.PcmFloat:
result = IsSampleOffsetInRangeForPcm<float>();
break;
case SampleFormat.Adpcm:
result = AdpcmHelper.GetAdpcmDataSize((int)StartSampleOffset) <= Size &&
AdpcmHelper.GetAdpcmDataSize((int)EndSampleOffset) <= Size;
break;
default:
throw new NotImplementedException($"{format} not implemented!");
}
return result;
}
}
/// <summary>
/// Flag altering the behaviour of wavebuffer decoding.
/// </summary>
[Flags]
public enum DecodingBehaviour : ushort
{
/// <summary>
/// Default decoding behaviour.
/// </summary>
Default = 0,
/// <summary>
/// Reset the played samples accumulator when looping.
/// </summary>
PlayedSampleCountResetWhenLooping = 1,
/// <summary>
/// Skip pitch and Sample Rate Conversion (SRC).
/// </summary>
SkipPitchAndSampleRateConversion = 2
}
/// <summary>
/// Specify the quality to use during Sample Rate Conversion (SRC) and pitch handling.
/// </summary>
/// <remarks>This was added in REV8.</remarks>
public enum SampleRateConversionQuality : byte
{
/// <summary>
/// Resample interpolating 4 samples per output sample.
/// </summary>
Default,
/// <summary>
/// Resample interpolating 8 samples per output sample.
/// </summary>
High,
/// <summary>
/// Resample interpolating 1 samples per output sample.
/// </summary>
Low
}
}
}

View File

@ -0,0 +1,52 @@
//
// Copyright (c) 2019-2020 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter
{
/// <summary>
/// Output information about a voice.
/// </summary>
/// <remarks>See <seealso cref="Server.StateUpdater.UpdateVoices(Server.Voice.VoiceContext, System.Memory{Server.MemoryPool.MemoryPoolState})"/></remarks>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct VoiceOutStatus
{
/// <summary>
/// The total amount of samples that was played.
/// </summary>
/// <remarks>This is reset to 0 when a <see cref="Common.WaveBuffer"/> finishes playing and <see cref="Common.WaveBuffer.IsEndOfStream"/> is set.</remarks>
/// <remarks>This is reset to 0 when looping while <see cref="Parameter.VoiceInParameter.DecodingBehaviour.PlayedSampleCountResetWhenLooping"/> is set.</remarks>
public ulong PlayedSampleCount;
/// <summary>
/// The total amount of <see cref="WaveBuffer"/> consumed.
/// </summary>
public uint PlayedWaveBuffersCount;
/// <summary>
/// If set to true, the voice was dropped.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool VoiceDropFlag;
/// <summary>
/// Reserved/unused.
/// </summary>
private unsafe fixed byte _reserved[3];
}
}