aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Audio.Renderer/Parameter/VoiceInParameter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Audio.Renderer/Parameter/VoiceInParameter.cs')
-rw-r--r--Ryujinx.Audio.Renderer/Parameter/VoiceInParameter.cs360
1 files changed, 360 insertions, 0 deletions
diff --git a/Ryujinx.Audio.Renderer/Parameter/VoiceInParameter.cs b/Ryujinx.Audio.Renderer/Parameter/VoiceInParameter.cs
new file mode 100644
index 00000000..220edcb0
--- /dev/null
+++ b/Ryujinx.Audio.Renderer/Parameter/VoiceInParameter.cs
@@ -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
+ }
+ }
+}