aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Services/Audio
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Audio')
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AalHardwareDevice.cs98
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDevice.cs158
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs (renamed from Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioDevice.cs)156
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioKernelEvent.cs25
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs112
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs188
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioDevice.cs17
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs20
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs50
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/AudioRendererCommon.cs9
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/BehaviorInfo.cs30
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/CommandGenerator.cs16
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EdgeMatrix.cs19
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EffectContext.cs7
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs452
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/MemoryPoolContext.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/NodeStates.cs19
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/PerformanceManager.cs30
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Resampler.cs191
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/SplitterContext.cs25
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererConsts.cs17
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs22
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BehaviorIn.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BiquadFilter.cs16
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectIn.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectOut.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectState.cs8
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolIn.cs14
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolOut.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolState.cs13
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/PlayState.cs9
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/RendererInfoOut.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/SupportTags.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs24
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceChannelResourceIn.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceIn.cs49
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceOut.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/WaveBuffer.cs20
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs201
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs105
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs151
41 files changed, 885 insertions, 1488 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AalHardwareDevice.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AalHardwareDevice.cs
new file mode 100644
index 00000000..fdc23604
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AalHardwareDevice.cs
@@ -0,0 +1,98 @@
+using Ryujinx.Audio;
+using Ryujinx.Audio.Renderer;
+using Ryujinx.Audio.Renderer.Integration;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
+{
+ public class AalHardwareDevice : HardwareDevice
+ {
+ private IAalOutput _output;
+ private int _trackId;
+ private int _bufferTag;
+ private int _nextTag;
+ private AutoResetEvent _releaseEvent;
+
+ private uint _channelCount;
+ private uint _sampleRate;
+
+ private short[] _buffer;
+
+ private Queue<long> _releasedTags;
+
+ public AalHardwareDevice(int bufferTag, IAalOutput output, uint channelCount, uint sampleRate)
+ {
+ _bufferTag = bufferTag;
+ _channelCount = channelCount;
+ _sampleRate = sampleRate;
+ _output = output;
+ _releaseEvent = new AutoResetEvent(true);
+ _trackId = _output.OpenTrack((int)sampleRate, (int)channelCount, AudioCallback);
+ _releasedTags = new Queue<long>();
+
+ _buffer = new short[RendererConstants.TargetSampleCount * channelCount];
+
+ _output.Start(_trackId);
+ }
+
+ private void AudioCallback()
+ {
+ long[] released = _output.GetReleasedBuffers(_trackId, int.MaxValue);
+
+ lock (_releasedTags)
+ {
+ foreach (long tag in released)
+ {
+ _releasedTags.Enqueue(tag);
+ }
+ }
+ }
+
+ private long GetReleasedTag()
+ {
+ lock (_releasedTags)
+ {
+ if (_releasedTags.Count > 0)
+ {
+ return _releasedTags.Dequeue();
+ }
+
+ return (_bufferTag << 16) | (_nextTag++);
+ }
+ }
+
+ public void AppendBuffer(ReadOnlySpan<short> data, uint channelCount)
+ {
+ data.CopyTo(_buffer.AsSpan());
+
+ _output.AppendBuffer(_trackId, GetReleasedTag(), _buffer);
+ }
+
+ public uint GetChannelCount()
+ {
+ return _channelCount;
+ }
+
+ public uint GetSampleRate()
+ {
+ return _sampleRate;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _output.Stop(_trackId);
+ _output.CloseTrack(_trackId);
+ _releaseEvent.Dispose();
+ }
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDevice.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDevice.cs
new file mode 100644
index 00000000..8ba10946
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDevice.cs
@@ -0,0 +1,158 @@
+using Ryujinx.Audio.Renderer.Device;
+using Ryujinx.Audio.Renderer.Server;
+using Ryujinx.HLE.HOS.Kernel;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+
+namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
+{
+ class AudioDevice : IAudioDevice
+ {
+ private VirtualDeviceSession[] _sessions;
+ private ulong _appletResourceId;
+ private int _revision;
+ private bool _isUsbDeviceSupported;
+
+ private VirtualDeviceSessionRegistry _registry;
+ private KEvent _systemEvent;
+
+ public AudioDevice(VirtualDeviceSessionRegistry registry, KernelContext context, ulong appletResourceId, int revision)
+ {
+ _registry = registry;
+ _appletResourceId = appletResourceId;
+ _revision = revision;
+
+ BehaviourContext behaviourContext = new BehaviourContext();
+ behaviourContext.SetUserRevision(revision);
+
+ _isUsbDeviceSupported = behaviourContext.IsAudioUsbDeviceOutputSupported();
+ _sessions = _registry.GetSessionByAppletResourceId(appletResourceId);
+
+ // TODO: support the 3 different events correctly when we will have hot plugable audio devices.
+ _systemEvent = new KEvent(context);
+ _systemEvent.ReadableEvent.Signal();
+ }
+
+ private bool TryGetDeviceByName(out VirtualDeviceSession result, string name, bool ignoreRevLimitation = false)
+ {
+ result = null;
+
+ foreach (VirtualDeviceSession session in _sessions)
+ {
+ if (session.Device.Name.Equals(name))
+ {
+ if (!ignoreRevLimitation && !_isUsbDeviceSupported && session.Device.IsUsbDevice())
+ {
+ return false;
+ }
+
+ result = session;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public string GetActiveAudioDeviceName()
+ {
+ VirtualDevice device = _registry.ActiveDevice;
+
+ if (!_isUsbDeviceSupported && device.IsUsbDevice())
+ {
+ device = _registry.DefaultDevice;
+ }
+
+ return device.Name;
+ }
+
+ public uint GetActiveChannelCount()
+ {
+ VirtualDevice device = _registry.ActiveDevice;
+
+ if (!_isUsbDeviceSupported && device.IsUsbDevice())
+ {
+ device = _registry.DefaultDevice;
+ }
+
+ return device.ChannelCount;
+ }
+
+ public ResultCode GetAudioDeviceOutputVolume(string name, out float volume)
+ {
+ if (TryGetDeviceByName(out VirtualDeviceSession result, name))
+ {
+ volume = result.Volume;
+ }
+ else
+ {
+ volume = 0.0f;
+ }
+
+ return ResultCode.Success;
+ }
+
+ public ResultCode SetAudioDeviceOutputVolume(string name, float volume)
+ {
+ if (TryGetDeviceByName(out VirtualDeviceSession result, name, true))
+ {
+ if (!_isUsbDeviceSupported && result.Device.IsUsbDevice())
+ {
+ result = _sessions[0];
+ }
+
+ result.Volume = volume;
+ }
+
+ return ResultCode.Success;
+ }
+
+ public ResultCode GetAudioSystemMasterVolumeSetting(string name, out float systemMasterVolume)
+ {
+ if (TryGetDeviceByName(out VirtualDeviceSession result, name, true))
+ {
+ systemMasterVolume = result.Device.MasterVolume;
+ }
+ else
+ {
+ systemMasterVolume = 0.0f;
+ }
+
+ return ResultCode.Success;
+ }
+
+ public string[] ListAudioDeviceName()
+ {
+ int deviceCount = _sessions.Length;
+
+ if (!_isUsbDeviceSupported)
+ {
+ deviceCount--;
+ }
+
+ string[] result = new string[deviceCount];
+
+ for (int i = 0; i < deviceCount; i++)
+ {
+ result[i] = _sessions[i].Device.Name;
+ }
+
+ return result;
+ }
+
+ public KEvent QueryAudioDeviceInputEvent()
+ {
+ return _systemEvent;
+ }
+
+ public KEvent QueryAudioDeviceOutputEvent()
+ {
+ return _systemEvent;
+ }
+
+ public KEvent QueryAudioDeviceSystemEvent()
+ {
+ return _systemEvent;
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioDevice.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs
index 1cc263b6..1cf6741e 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioDevice.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioDeviceServer.cs
@@ -1,41 +1,40 @@
-using Ryujinx.Common.Logging;
+using Ryujinx.Common.Logging;
+using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
-using Ryujinx.HLE.HOS.SystemState;
using System;
using System.Text;
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
+namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
{
- class IAudioDevice : IpcService
+ class AudioDeviceServer : IpcService
{
- private KEvent _systemEvent;
+ private const int AudioDeviceNameSize = 0x100;
- public IAudioDevice(Horizon system)
- {
- _systemEvent = new KEvent(system.KernelContext);
+ private IAudioDevice _impl;
- // TODO: We shouldn't be signaling this here.
- _systemEvent.ReadableEvent.Signal();
+ public AudioDeviceServer(IAudioDevice impl)
+ {
+ _impl = impl;
}
[Command(0)]
// ListAudioDeviceName() -> (u32, buffer<bytes, 6>)
public ResultCode ListAudioDeviceName(ServiceCtx context)
{
- string[] deviceNames = SystemStateMgr.AudioOutputs;
-
- context.ResponseData.Write(deviceNames.Length);
+ string[] deviceNames = _impl.ListAudioDeviceName();
long position = context.Request.ReceiveBuff[0].Position;
- long size = context.Request.ReceiveBuff[0].Size;
+ long size = context.Request.ReceiveBuff[0].Size;
long basePosition = position;
+ int count = 0;
+
foreach (string name in deviceNames)
{
- byte[] buffer = Encoding.ASCII.GetBytes(name + "\0");
+ byte[] buffer = Encoding.ASCII.GetBytes(name);
if ((position - basePosition) + buffer.Length > size)
{
@@ -45,41 +44,58 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
}
context.Memory.Write((ulong)position, buffer);
+ MemoryHelper.FillWithZeros(context.Memory, position + buffer.Length, AudioDeviceNameSize - buffer.Length);
- position += buffer.Length;
+ position += AudioDeviceNameSize;
+ count++;
}
+ context.ResponseData.Write(count);
+
return ResultCode.Success;
}
[Command(1)]
- // SetAudioDeviceOutputVolume(u32, buffer<bytes, 5>)
+ // SetAudioDeviceOutputVolume(f32 volume, buffer<bytes, 5> name)
public ResultCode SetAudioDeviceOutputVolume(ServiceCtx context)
{
float volume = context.RequestData.ReadSingle();
long position = context.Request.SendBuff[0].Position;
- long size = context.Request.SendBuff[0].Size;
+ long size = context.Request.SendBuff[0].Size;
- byte[] deviceNameBuffer = new byte[size];
-
- context.Memory.Read((ulong)position, deviceNameBuffer);
+ string deviceName = MemoryHelper.ReadAsciiString(context.Memory, position, size);
- string deviceName = Encoding.ASCII.GetString(deviceNameBuffer);
+ return _impl.SetAudioDeviceOutputVolume(deviceName, volume);
+ }
- Logger.Stub?.PrintStub(LogClass.ServiceAudio);
+ [Command(2)]
+ // GetAudioDeviceOutputVolume(buffer<bytes, 5> name) -> f32 volume
+ public ResultCode GetAudioDeviceOutputVolume(ServiceCtx context)
+ {
+ long position = context.Request.SendBuff[0].Position;
+ long size = context.Request.SendBuff[0].Size;
- return ResultCode.Success;
+ string deviceName = MemoryHelper.ReadAsciiString(context.Memory, position, size);
+
+ ResultCode result = _impl.GetAudioDeviceOutputVolume(deviceName, out float volume);
+
+ if (result == ResultCode.Success)
+ {
+ context.ResponseData.Write(volume);
+ }
+
+ return result;
}
[Command(3)]
// GetActiveAudioDeviceName() -> buffer<bytes, 6>
public ResultCode GetActiveAudioDeviceName(ServiceCtx context)
{
- string name = context.Device.System.State.ActiveAudioOutput;
+ string name = _impl.GetActiveAudioDeviceName();
long position = context.Request.ReceiveBuff[0].Position;
- long size = context.Request.ReceiveBuff[0].Size;
+ long size = context.Request.ReceiveBuff[0].Size;
byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(name + "\0");
@@ -99,7 +115,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
// QueryAudioDeviceSystemEvent() -> handle<copy, event>
public ResultCode QueryAudioDeviceSystemEvent(ServiceCtx context)
{
- if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ KEvent deviceSystemEvent = _impl.QueryAudioDeviceSystemEvent();
+
+ if (context.Process.HandleTable.GenerateHandle(deviceSystemEvent.ReadableEvent, out int handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -115,28 +133,28 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
// GetActiveChannelCount() -> u32
public ResultCode GetActiveChannelCount(ServiceCtx context)
{
- context.ResponseData.Write(2);
+ context.ResponseData.Write(_impl.GetActiveChannelCount());
Logger.Stub?.PrintStub(LogClass.ServiceAudio);
return ResultCode.Success;
}
- [Command(6)]
+ [Command(6)] // 3.0.0+
// ListAudioDeviceNameAuto() -> (u32, buffer<bytes, 0x22>)
public ResultCode ListAudioDeviceNameAuto(ServiceCtx context)
{
- string[] deviceNames = SystemStateMgr.AudioOutputs;
-
- context.ResponseData.Write(deviceNames.Length);
+ string[] deviceNames = _impl.ListAudioDeviceName();
(long position, long size) = context.Request.GetBufferType0x22();
long basePosition = position;
+ int count = 0;
+
foreach (string name in deviceNames)
{
- byte[] buffer = Encoding.UTF8.GetBytes(name + '\0');
+ byte[] buffer = Encoding.ASCII.GetBytes(name);
if ((position - basePosition) + buffer.Length > size)
{
@@ -146,48 +164,53 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
}
context.Memory.Write((ulong)position, buffer);
+ MemoryHelper.FillWithZeros(context.Memory, position + buffer.Length, AudioDeviceNameSize - buffer.Length);
- position += buffer.Length;
+ position += AudioDeviceNameSize;
+ count++;
}
+ context.ResponseData.Write(count);
+
return ResultCode.Success;
}
- [Command(7)]
- // SetAudioDeviceOutputVolumeAuto(u32, buffer<bytes, 0x21>)
+ [Command(7)] // 3.0.0+
+ // SetAudioDeviceOutputVolumeAuto(f32 volume, buffer<bytes, 0x21> name)
public ResultCode SetAudioDeviceOutputVolumeAuto(ServiceCtx context)
{
float volume = context.RequestData.ReadSingle();
(long position, long size) = context.Request.GetBufferType0x21();
- byte[] deviceNameBuffer = new byte[size];
-
- context.Memory.Read((ulong)position, deviceNameBuffer);
-
- string deviceName = Encoding.UTF8.GetString(deviceNameBuffer);
+ string deviceName = MemoryHelper.ReadAsciiString(context.Memory, position, size);
- Logger.Stub?.PrintStub(LogClass.ServiceAudio);
-
- return ResultCode.Success;
+ return _impl.SetAudioDeviceOutputVolume(deviceName, volume);
}
- [Command(8)]
- // GetAudioDeviceOutputVolumeAuto(buffer<bytes, 0x21>) -> u32
+ [Command(8)] // 3.0.0+
+ // GetAudioDeviceOutputVolumeAuto(buffer<bytes, 0x21> name) -> f32
public ResultCode GetAudioDeviceOutputVolumeAuto(ServiceCtx context)
{
- context.ResponseData.Write(1f);
+ (long position, long size) = context.Request.GetBufferType0x21();
- Logger.Stub?.PrintStub(LogClass.ServiceAudio);
+ string deviceName = MemoryHelper.ReadAsciiString(context.Memory, position, size);
+
+ ResultCode result = _impl.GetAudioDeviceOutputVolume(deviceName, out float volume);
+
+ if (result == ResultCode.Success)
+ {
+ context.ResponseData.Write(volume);
+ }
return ResultCode.Success;
}
- [Command(10)]
+ [Command(10)] // 3.0.0+
// GetActiveAudioDeviceNameAuto() -> buffer<bytes, 0x22>
public ResultCode GetActiveAudioDeviceNameAuto(ServiceCtx context)
{
- string name = context.Device.System.State.ActiveAudioOutput;
+ string name = _impl.GetActiveAudioDeviceName();
(long position, long size) = context.Request.GetBufferType0x22();
@@ -205,11 +228,13 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
return ResultCode.Success;
}
- [Command(11)]
+ [Command(11)] // 3.0.0+
// QueryAudioDeviceInputEvent() -> handle<copy, event>
public ResultCode QueryAudioDeviceInputEvent(ServiceCtx context)
{
- if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ KEvent deviceInputEvent = _impl.QueryAudioDeviceInputEvent();
+
+ if (context.Process.HandleTable.GenerateHandle(deviceInputEvent.ReadableEvent, out int handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -221,11 +246,13 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
return ResultCode.Success;
}
- [Command(12)]
+ [Command(12)] // 3.0.0+
// QueryAudioDeviceOutputEvent() -> handle<copy, event>
public ResultCode QueryAudioDeviceOutputEvent(ServiceCtx context)
{
- if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ KEvent deviceOutputEvent = _impl.QueryAudioDeviceOutputEvent();
+
+ if (context.Process.HandleTable.GenerateHandle(deviceOutputEvent.ReadableEvent, out int handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
@@ -236,5 +263,24 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
return ResultCode.Success;
}
+
+ [Command(13)]
+ // GetAudioSystemMasterVolumeSetting(buffer<bytes, 5> name) -> f32
+ public ResultCode GetAudioSystemMasterVolumeSetting(ServiceCtx context)
+ {
+ long position = context.Request.SendBuff[0].Position;
+ long size = context.Request.SendBuff[0].Size;
+
+ string deviceName = MemoryHelper.ReadAsciiString(context.Memory, position, size);
+
+ ResultCode result = _impl.GetAudioSystemMasterVolumeSetting(deviceName, out float systemMasterVolume);
+
+ if (result == ResultCode.Success)
+ {
+ context.ResponseData.Write(systemMasterVolume);
+ }
+
+ return result;
+ }
}
-} \ No newline at end of file
+}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioKernelEvent.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioKernelEvent.cs
new file mode 100644
index 00000000..1a132b91
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioKernelEvent.cs
@@ -0,0 +1,25 @@
+using Ryujinx.Audio.Renderer.Integration;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+
+namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
+{
+ class AudioKernelEvent : IWritableEvent
+ {
+ public KEvent Event { get; }
+
+ public AudioKernelEvent(KEvent evnt)
+ {
+ Event = evnt;
+ }
+
+ public void Clear()
+ {
+ Event.WritableEvent.Clear();
+ }
+
+ public void Signal()
+ {
+ Event.WritableEvent.Signal();
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs
new file mode 100644
index 00000000..702648dd
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRenderer.cs
@@ -0,0 +1,112 @@
+using Ryujinx.Audio.Renderer.Integration;
+using Ryujinx.Audio.Renderer.Server;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
+{
+ class AudioRenderer : IAudioRenderer
+ {
+ private AudioRenderSystem _impl;
+
+ public AudioRenderer(AudioRenderSystem impl)
+ {
+ _impl = impl;
+ }
+
+ public ResultCode ExecuteAudioRendererRendering()
+ {
+ throw new NotImplementedException();
+ }
+
+ public uint GetMixBufferCount()
+ {
+ return _impl.GetMixBufferCount();
+ }
+
+ public uint GetRenderingTimeLimit()
+ {
+ return _impl.GetRenderingTimeLimit();
+ }
+
+ public uint GetSampleCount()
+ {
+ return _impl.GetSampleCount();
+ }
+
+ public uint GetSampleRate()
+ {
+ return _impl.GetSampleRate();
+ }
+
+ public int GetState()
+ {
+ if (_impl.IsActive())
+ {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ public ResultCode QuerySystemEvent(out KEvent systemEvent)
+ {
+ ResultCode resultCode = (ResultCode)_impl.QuerySystemEvent(out IWritableEvent outEvent);
+
+ if (resultCode == ResultCode.Success)
+ {
+ if (outEvent is AudioKernelEvent)
+ {
+ systemEvent = ((AudioKernelEvent)outEvent).Event;
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
+ }
+ else
+ {
+ systemEvent = null;
+ }
+
+ return resultCode;
+ }
+
+ public ResultCode RequestUpdate(Memory<byte> output, Memory<byte> performanceOutput, ReadOnlyMemory<byte> input)
+ {
+ return (ResultCode)_impl.Update(output, performanceOutput, input);
+ }
+
+ public void SetRenderingTimeLimit(uint percent)
+ {
+ _impl.SetRenderingTimeLimitPercent(percent);
+ }
+
+ public ResultCode Start()
+ {
+ _impl.Start();
+
+ return ResultCode.Success;
+ }
+
+ public ResultCode Stop()
+ {
+ _impl.Stop();
+
+ return ResultCode.Success;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _impl.Dispose();
+ }
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs
new file mode 100644
index 00000000..5ff5ddb3
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs
@@ -0,0 +1,188 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using System;
+using System.Buffers;
+
+namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
+{
+ class AudioRendererServer : IpcService, IDisposable
+ {
+ private IAudioRenderer _impl;
+
+ public AudioRendererServer(IAudioRenderer impl)
+ {
+ _impl = impl;
+ }
+
+ [Command(0)]
+ // GetSampleRate() -> u32
+ public ResultCode GetSampleRate(ServiceCtx context)
+ {
+ context.ResponseData.Write(_impl.GetSampleRate());
+
+ return ResultCode.Success;
+ }
+
+ [Command(1)]
+ // GetSampleCount() -> u32
+ public ResultCode GetSampleCount(ServiceCtx context)
+ {
+ context.ResponseData.Write(_impl.GetSampleCount());
+
+ return ResultCode.Success;
+ }
+
+ [Command(2)]
+ // GetMixBufferCount() -> u32
+ public ResultCode GetMixBufferCount(ServiceCtx context)
+ {
+ context.ResponseData.Write(_impl.GetMixBufferCount());
+
+ return ResultCode.Success;
+ }
+
+ [Command(3)]
+ // GetState() -> u32
+ public ResultCode GetState(ServiceCtx context)
+ {
+ context.ResponseData.Write(_impl.GetState());
+
+ return ResultCode.Success;
+ }
+
+ [Command(4)]
+ // RequestUpdate(buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 5> input)
+ // -> (buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 6> output, buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 6> performanceOutput)
+ public ResultCode RequestUpdate(ServiceCtx context)
+ {
+ long inputPosition = context.Request.SendBuff[0].Position;
+ long inputSize = context.Request.SendBuff[0].Size;
+
+ long outputPosition = context.Request.ReceiveBuff[0].Position;
+ long outputSize = context.Request.ReceiveBuff[0].Size;
+
+ long performanceOutputPosition = context.Request.ReceiveBuff[1].Position;
+ long performanceOutputSize = context.Request.ReceiveBuff[1].Size;
+
+ ReadOnlyMemory<byte> input = context.Memory.GetSpan((ulong)inputPosition, (int)inputSize).ToArray();
+
+ Memory<byte> output = new byte[outputSize];
+ Memory<byte> performanceOutput = new byte[performanceOutputSize];
+
+ using MemoryHandle outputHandle = output.Pin();
+ using MemoryHandle performanceOutputHandle = performanceOutput.Pin();
+
+ ResultCode result = _impl.RequestUpdate(output, performanceOutput, input);
+
+ if (result == ResultCode.Success)
+ {
+ context.Memory.Write((ulong)outputPosition, output.Span);
+ context.Memory.Write((ulong)performanceOutputPosition, performanceOutput.Span);
+ }
+ else
+ {
+ Logger.Error?.Print(LogClass.ServiceAudio, $"Error while processing renderer update: 0x{result}");
+ }
+
+ return result;
+ }
+
+ [Command(5)]
+ // Start()
+ public ResultCode Start(ServiceCtx context)
+ {
+ return _impl.Start();
+ }
+
+ [Command(6)]
+ // Stop()
+ public ResultCode Stop(ServiceCtx context)
+ {
+ return _impl.Stop();
+ }
+
+ [Command(7)]
+ // QuerySystemEvent() -> handle<copy, event>
+ public ResultCode QuerySystemEvent(ServiceCtx context)
+ {
+ ResultCode result = _impl.QuerySystemEvent(out KEvent systemEvent);
+
+ if (result == ResultCode.Success)
+ {
+ if (context.Process.HandleTable.GenerateHandle(systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
+ {
+ throw new InvalidOperationException("Out of handles!");
+ }
+
+ context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
+ }
+
+ return result;
+ }
+
+ [Command(8)]
+ // SetAudioRendererRenderingTimeLimit(u32 limit)
+ public ResultCode SetAudioRendererRenderingTimeLimit(ServiceCtx context)
+ {
+ uint limit = context.RequestData.ReadUInt32();
+
+ _impl.SetRenderingTimeLimit(limit);
+
+ return ResultCode.Success;
+ }
+
+ [Command(9)]
+ // GetAudioRendererRenderingTimeLimit() -> u32 limit
+ public ResultCode GetAudioRendererRenderingTimeLimit(ServiceCtx context)
+ {
+ uint limit = _impl.GetRenderingTimeLimit();
+
+ context.ResponseData.Write(limit);
+
+ return ResultCode.Success;
+ }
+
+ [Command(10)] // 3.0.0+
+ // RequestUpdateAuto(buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 0x21> input)
+ // -> (buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 0x22> output, buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 0x22> performanceOutput)
+ public ResultCode RequestUpdateAuto(ServiceCtx context)
+ {
+ (long inputPosition, long inputSize) = context.Request.GetBufferType0x21();
+ (long outputPosition, long outputSize) = context.Request.GetBufferType0x22(0);
+ (long performanceOutputPosition, long performanceOutputSize) = context.Request.GetBufferType0x22(1);
+
+ ReadOnlyMemory<byte> input = context.Memory.GetSpan((ulong)inputPosition, (int)inputSize).ToArray();
+
+ Memory<byte> output = new byte[outputSize];
+ Memory<byte> performanceOutput = new byte[performanceOutputSize];
+
+ using MemoryHandle outputHandle = output.Pin();
+ using MemoryHandle performanceOutputHandle = performanceOutput.Pin();
+
+ ResultCode result = _impl.RequestUpdate(output, performanceOutput, input);
+
+ if (result == ResultCode.Success)
+ {
+ context.Memory.Write((ulong)outputPosition, output.Span);
+ context.Memory.Write((ulong)performanceOutputPosition, performanceOutput.Span);
+ }
+
+ return result;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _impl.Dispose();
+ }
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioDevice.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioDevice.cs
new file mode 100644
index 00000000..42ea727f
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioDevice.cs
@@ -0,0 +1,17 @@
+using Ryujinx.HLE.HOS.Kernel.Threading;
+
+namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
+{
+ interface IAudioDevice
+ {
+ string[] ListAudioDeviceName();
+ ResultCode SetAudioDeviceOutputVolume(string name, float volume);
+ ResultCode GetAudioDeviceOutputVolume(string name, out float volume);
+ string GetActiveAudioDeviceName();
+ KEvent QueryAudioDeviceSystemEvent();
+ uint GetActiveChannelCount();
+ KEvent QueryAudioDeviceInputEvent();
+ KEvent QueryAudioDeviceOutputEvent();
+ ResultCode GetAudioSystemMasterVolumeSetting(string name, out float systemMasterVolume);
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs
new file mode 100644
index 00000000..a59c94e9
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/IAudioRenderer.cs
@@ -0,0 +1,20 @@
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
+{
+ interface IAudioRenderer : IDisposable
+ {
+ uint GetSampleRate();
+ uint GetSampleCount();
+ uint GetMixBufferCount();
+ int GetState();
+ ResultCode RequestUpdate(Memory<byte> output, Memory<byte> performanceOutput, ReadOnlyMemory<byte> input);
+ ResultCode Start();
+ ResultCode Stop();
+ ResultCode QuerySystemEvent(out KEvent systemEvent);
+ void SetRenderingTimeLimit(uint percent);
+ uint GetRenderingTimeLimit();
+ ResultCode ExecuteAudioRendererRendering();
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs
new file mode 100644
index 00000000..e12a9919
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs
@@ -0,0 +1,50 @@
+using Ryujinx.Audio.Renderer.Device;
+using Ryujinx.Audio.Renderer.Parameter;
+using Ryujinx.Audio.Renderer.Server;
+using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer;
+
+using AudioRendererManagerImpl = Ryujinx.Audio.Renderer.Server.AudioRendererManager;
+
+namespace Ryujinx.HLE.HOS.Services.Audio
+{
+ class AudioRendererManager : IAudioRendererManager
+ {
+ private AudioRendererManagerImpl _impl;
+ private VirtualDeviceSessionRegistry _registry;
+
+ public AudioRendererManager(AudioRendererManagerImpl impl, VirtualDeviceSessionRegistry registry)
+ {
+ _impl = impl;
+ _registry = registry;
+ }
+
+ public ResultCode GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context, out IAudioDevice outObject, int revision, ulong appletResourceUserId)
+ {
+ outObject = new AudioDevice(_registry, context.Device.System.KernelContext, appletResourceUserId, revision);
+
+ return ResultCode.Success;
+ }
+
+ public ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter)
+ {
+ return AudioRendererManagerImpl.GetWorkBufferSize(ref parameter);
+ }
+
+ public ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle)
+ {
+ ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, context.Memory, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle);
+
+ if (result == ResultCode.Success)
+ {
+ obj = new AudioRenderer.AudioRenderer(renderer);
+ }
+ else
+ {
+ obj = null;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/AudioRendererCommon.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/AudioRendererCommon.cs
deleted file mode 100644
index c884b465..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/AudioRendererCommon.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- static class AudioRendererCommon
- {
- public static bool CheckValidRevision(AudioRendererParameter parameters) => GetRevisionVersion(parameters.Revision) <= AudioRendererConsts.Revision;
- public static bool CheckFeatureSupported(int revision, int supportedRevision) => revision >= supportedRevision;
- public static int GetRevisionVersion(int revision) => (revision - AudioRendererConsts.Rev0Magic) >> 24;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/BehaviorInfo.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/BehaviorInfo.cs
deleted file mode 100644
index 461e4337..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/BehaviorInfo.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- class BehaviorInfo
- {
- private const int _revision = AudioRendererConsts.Revision;
-
- private int _userRevision = 0;
-
- public BehaviorInfo()
- {
- /* TODO: this class got a size of 0xC0
- 0x00 - uint - Internal Revision
- 0x04 - uint - User Revision
- 0x08 - ... unknown ...
- */
- }
-
- public bool IsSplitterSupported() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.Splitter);
- public bool IsSplitterBugFixed() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.SplitterBugFix);
- public bool IsVariadicCommandBufferSizeSupported() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.VariadicCommandBufferSize);
- public bool IsElapsedFrameCountSupported() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.ElapsedFrameCount);
-
- public int GetPerformanceMetricsDataFormat() => AudioRendererCommon.CheckFeatureSupported(_userRevision, SupportTags.PerformanceMetricsDataFormatVersion2) ? 2 : 1;
-
- public void SetUserLibRevision(int revision)
- {
- _userRevision = AudioRendererCommon.GetRevisionVersion(revision);
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/CommandGenerator.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/CommandGenerator.cs
deleted file mode 100644
index b09b990b..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/CommandGenerator.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- static class CommandGenerator
- {
- public static long CalculateCommandBufferSize(AudioRendererParameter parameters)
- {
- return parameters.EffectCount * 0x840 +
- parameters.SubMixCount * 0x5A38 +
- parameters.SinkCount * 0x148 +
- parameters.SplitterDestinationDataCount * 0x540 +
- (parameters.SplitterCount * 0x68 + 0x2E0) * parameters.VoiceCount +
- ((parameters.VoiceCount + parameters.SubMixCount + parameters.EffectCount + parameters.SinkCount + 0x65) << 6) +
- 0x3F8;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EdgeMatrix.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EdgeMatrix.cs
deleted file mode 100644
index 3f87ae04..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EdgeMatrix.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using Ryujinx.Common;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- static class EdgeMatrix
- {
- public static int GetWorkBufferSize(int totalMixCount)
- {
- int size = BitUtils.AlignUp(totalMixCount * totalMixCount, AudioRendererConsts.BufferAlignment);
-
- if (size < 0)
- {
- size |= 7;
- }
-
- return size / 8;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EffectContext.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EffectContext.cs
deleted file mode 100644
index 88f087ed..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/EffectContext.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- class EffectContext
- {
- public EffectOut OutStatus;
- }
-}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs
deleted file mode 100644
index b5802d2d..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/IAudioRenderer.cs
+++ /dev/null
@@ -1,452 +0,0 @@
-using Ryujinx.Audio;
-using Ryujinx.Audio.Adpcm;
-using Ryujinx.Common.Logging;
-using Ryujinx.Cpu;
-using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
-using Ryujinx.HLE.HOS.Kernel.Threading;
-using Ryujinx.HLE.Utilities;
-using System;
-using System.Runtime.InteropServices;
-using System.Runtime.Intrinsics;
-using System.Runtime.Intrinsics.X86;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- class IAudioRenderer : IpcService, IDisposable
- {
- // This is the amount of samples that are going to be appended
- // each time that RequestUpdateAudioRenderer is called. Ideally,
- // this value shouldn't be neither too small (to avoid the player
- // starving due to running out of samples) or too large (to avoid
- // high latency).
- private const int MixBufferSamplesCount = 960;
-
- private KEvent _updateEvent;
-
- private MemoryManager _memory;
-
- private IAalOutput _audioOut;
-
- private AudioRendererParameter _params;
-
- private MemoryPoolContext[] _memoryPools;
-
- private VoiceContext[] _voices;
-
- private EffectContext[] _effects;
-
- private int _track;
-
- private PlayState _playState;
-
- private ulong _elapsedFrameCount;
-
- public IAudioRenderer(
- Horizon system,
- MemoryManager memory,
- IAalOutput audioOut,
- AudioRendererParameter rendererParams)
- {
- _updateEvent = new KEvent(system.KernelContext);
-
- _memory = memory;
- _audioOut = audioOut;
- _params = rendererParams;
-
- _track = audioOut.OpenTrack(
- AudioRendererConsts.HostSampleRate,
- AudioRendererConsts.HostChannelsCount,
- AudioCallback);
-
- _memoryPools = CreateArray<MemoryPoolContext>(rendererParams.EffectCount + rendererParams.VoiceCount * 4);
-
- _voices = CreateArray<VoiceContext>(rendererParams.VoiceCount);
-
- _effects = CreateArray<EffectContext>(rendererParams.EffectCount);
-
- _elapsedFrameCount = 0;
-
- InitializeAudioOut();
-
- _playState = PlayState.Stopped;
- }
-
- [Command(0)]
- // GetSampleRate() -> u32
- public ResultCode GetSampleRate(ServiceCtx context)
- {
- context.ResponseData.Write(_params.SampleRate);
-
- return ResultCode.Success;
- }
-
- [Command(1)]
- // GetSampleCount() -> u32
- public ResultCode GetSampleCount(ServiceCtx context)
- {
- context.ResponseData.Write(_params.SampleCount);
-
- return ResultCode.Success;
- }
-
- [Command(2)]
- // GetMixBufferCount() -> u32
- public ResultCode GetMixBufferCount(ServiceCtx context)
- {
- context.ResponseData.Write(_params.SubMixCount);
-
- return ResultCode.Success;
- }
-
- [Command(3)]
- // GetState() -> u32
- public ResultCode GetState(ServiceCtx context)
- {
- context.ResponseData.Write((int)_playState);
-
- Logger.Stub?.PrintStub(LogClass.ServiceAudio, new { State = Enum.GetName(typeof(PlayState), _playState) });
-
- return ResultCode.Success;
- }
-
- private void AudioCallback()
- {
- _updateEvent.ReadableEvent.Signal();
- }
-
- private static T[] CreateArray<T>(int size) where T : new()
- {
- T[] output = new T[size];
-
- for (int index = 0; index < size; index++)
- {
- output[index] = new T();
- }
-
- return output;
- }
-
- private void InitializeAudioOut()
- {
- AppendMixedBuffer(0);
- AppendMixedBuffer(1);
- AppendMixedBuffer(2);
-
- _audioOut.Start(_track);
- }
-
- [Command(4)]
- // RequestUpdateAudioRenderer(buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 5>)
- // -> (buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 6>, buffer<nn::audio::detail::AudioRendererUpdateDataHeader, 6>)
- public ResultCode RequestUpdateAudioRenderer(ServiceCtx context)
- {
- long outputPosition = context.Request.ReceiveBuff[0].Position;
- long outputSize = context.Request.ReceiveBuff[0].Size;
-
- MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
-
- long inputPosition = context.Request.SendBuff[0].Position;
-
- StructReader reader = new StructReader(context.Memory, inputPosition);
- StructWriter writer = new StructWriter(context.Memory, outputPosition);
-
- UpdateDataHeader inputHeader = reader.Read<UpdateDataHeader>();
-
- BehaviorInfo behaviorInfo = new BehaviorInfo();
-
- behaviorInfo.SetUserLibRevision(inputHeader.Revision);
-
- reader.Read<BehaviorIn>(inputHeader.BehaviorSize);
-
- MemoryPoolIn[] memoryPoolsIn = reader.Read<MemoryPoolIn>(inputHeader.MemoryPoolSize);
-
- for (int index = 0; index < memoryPoolsIn.Length; index++)
- {
- MemoryPoolIn memoryPool = memoryPoolsIn[index];
-
- if (memoryPool.State == MemoryPoolState.RequestAttach)
- {
- _memoryPools[index].OutStatus.State = MemoryPoolState.Attached;
- }
- else if (memoryPool.State == MemoryPoolState.RequestDetach)
- {
- _memoryPools[index].OutStatus.State = MemoryPoolState.Detached;
- }
- }
-
- reader.Read<VoiceChannelResourceIn>(inputHeader.VoiceResourceSize);
-
- VoiceIn[] voicesIn = reader.Read<VoiceIn>(inputHeader.VoiceSize);
-
- for (int index = 0; index < voicesIn.Length; index++)
- {
- VoiceIn voice = voicesIn[index];
-
- VoiceContext voiceCtx = _voices[index];
-
- voiceCtx.SetAcquireState(voice.Acquired != 0);
-
- if (voice.Acquired == 0)
- {
- continue;
- }
-
- if (voice.FirstUpdate != 0)
- {
- voiceCtx.AdpcmCtx = GetAdpcmDecoderContext(
- voice.AdpcmCoeffsPosition,
- voice.AdpcmCoeffsSize);
-
- voiceCtx.SampleFormat = voice.SampleFormat;
- voiceCtx.SampleRate = voice.SampleRate;
- voiceCtx.ChannelsCount = voice.ChannelsCount;
-
- voiceCtx.SetBufferIndex(voice.BaseWaveBufferIndex);
- }
-
- voiceCtx.WaveBuffers[0] = voice.WaveBuffer0;
- voiceCtx.WaveBuffers[1] = voice.WaveBuffer1;
- voiceCtx.WaveBuffers[2] = voice.WaveBuffer2;
- voiceCtx.WaveBuffers[3] = voice.WaveBuffer3;
- voiceCtx.Volume = voice.Volume;
- voiceCtx.PlayState = voice.PlayState;
- }
-
- EffectIn[] effectsIn = reader.Read<EffectIn>(inputHeader.EffectSize);
-
- for (int index = 0; index < effectsIn.Length; index++)
- {
- if (effectsIn[index].IsNew != 0)
- {
- _effects[index].OutStatus.State = EffectState.New;
- }
- }
-
- UpdateAudio();
-
- UpdateDataHeader outputHeader = new UpdateDataHeader();
-
- int updateHeaderSize = Marshal.SizeOf<UpdateDataHeader>();
-
- outputHeader.Revision = AudioRendererConsts.RevMagic;
- outputHeader.BehaviorSize = 0xb0;
- outputHeader.MemoryPoolSize = (_params.EffectCount + _params.VoiceCount * 4) * 0x10;
- outputHeader.VoiceSize = _params.VoiceCount * 0x10;
- outputHeader.EffectSize = _params.EffectCount * 0x10;
- outputHeader.SinkSize = _params.SinkCount * 0x20;
- outputHeader.PerformanceManagerSize = 0x10;
-
- if (behaviorInfo.IsElapsedFrameCountSupported())
- {
- outputHeader.ElapsedFrameCountInfoSize = 0x10;
- }
-
- outputHeader.TotalSize = updateHeaderSize +
- outputHeader.BehaviorSize +
- outputHeader.MemoryPoolSize +
- outputHeader.VoiceSize +
- outputHeader.EffectSize +
- outputHeader.SinkSize +
- outputHeader.PerformanceManagerSize +
- outputHeader.ElapsedFrameCountInfoSize;
-
- writer.Write(outputHeader);
-
- foreach (MemoryPoolContext memoryPool in _memoryPools)
- {
- writer.Write(memoryPool.OutStatus);
- }
-
- foreach (VoiceContext voice in _voices)
- {
- writer.Write(voice.OutStatus);
- }
-
- foreach (EffectContext effect in _effects)
- {
- writer.Write(effect.OutStatus);
- }
-
- writer.SkipBytes(_params.SinkCount * 0x20);
- writer.SkipBytes(outputHeader.PerformanceManagerSize);
- writer.SkipBytes(outputHeader.BehaviorSize);
-
- if (behaviorInfo.IsElapsedFrameCountSupported())
- {
- writer.Write(new RendererInfoOut
- {
- ElapsedFrameCount = _elapsedFrameCount
- });
- }
-
- return ResultCode.Success;
- }
-
- [Command(5)]
- // Start()
- public ResultCode StartAudioRenderer(ServiceCtx context)
- {
- Logger.Stub?.PrintStub(LogClass.ServiceAudio);
-
- _playState = PlayState.Playing;
-
- return ResultCode.Success;
- }
-
- [Command(6)]
- // Stop()
- public ResultCode StopAudioRenderer(ServiceCtx context)
- {
- Logger.Stub?.PrintStub(LogClass.ServiceAudio);
-
- _playState = PlayState.Stopped;
-
- return ResultCode.Success;
- }
-
- [Command(7)]
- // QuerySystemEvent() -> handle<copy, event>
- public ResultCode QuerySystemEvent(ServiceCtx context)
- {
- if (context.Process.HandleTable.GenerateHandle(_updateEvent.ReadableEvent, out int handle) != KernelResult.Success)
- {
- throw new InvalidOperationException("Out of handles!");
- }
-
- context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
-
- return ResultCode.Success;
- }
-
- private AdpcmDecoderContext GetAdpcmDecoderContext(long position, long size)
- {
- if (size == 0)
- {
- return null;
- }
-
- AdpcmDecoderContext context = new AdpcmDecoderContext
- {
- Coefficients = new short[size >> 1]
- };
-
- for (int offset = 0; offset < size; offset += 2)
- {
- context.Coefficients[offset >> 1] = _memory.Read<short>((ulong)(position + offset));
- }
-
- return context;
- }
-
- private void UpdateAudio()
- {
- long[] released = _audioOut.GetReleasedBuffers(_track, 2);
-
- for (int index = 0; index < released.Length; index++)
- {
- AppendMixedBuffer(released[index]);
- }
-
- _elapsedFrameCount++;
- }
-
- private void AppendMixedBuffer(long tag)
- {
- int[] mixBuffer = new int[MixBufferSamplesCount * AudioRendererConsts.HostChannelsCount];
-
- foreach (VoiceContext voice in _voices)
- {
- if (!voice.Playing || voice.CurrentWaveBuffer.Size == 0)
- {
- continue;
- }
-
- int outOffset = 0;
- int pendingSamples = MixBufferSamplesCount;
-
- while (pendingSamples > 0)
- {
- int[] samples = voice.GetBufferData(_memory, pendingSamples, out int returnedSamples);
-
- if (returnedSamples == 0)
- {
- break;
- }
-
- pendingSamples -= returnedSamples;
-
- for (int offset = 0; offset < samples.Length; offset++)
- {
- mixBuffer[outOffset++] += (int)(samples[offset] * voice.Volume);
- }
- }
- }
-
- _audioOut.AppendBuffer(_track, tag, GetFinalBuffer(mixBuffer));
- }
-
- private unsafe static short[] GetFinalBuffer(int[] buffer)
- {
- short[] output = new short[buffer.Length];
-
- int offset = 0;
-
- // Perform Saturation using SSE2 if supported
- if (Sse2.IsSupported)
- {
- fixed (int* inptr = buffer)
- fixed (short* outptr = output)
- {
- for (; offset + 32 <= buffer.Length; offset += 32)
- {
- // Unroll the loop a little to ensure the CPU pipeline
- // is always full.
- Vector128<int> block1A = Sse2.LoadVector128(inptr + offset + 0);
- Vector128<int> block1B = Sse2.LoadVector128(inptr + offset + 4);
-
- Vector128<int> block2A = Sse2.LoadVector128(inptr + offset + 8);
- Vector128<int> block2B = Sse2.LoadVector128(inptr + offset + 12);
-
- Vector128<int> block3A = Sse2.LoadVector128(inptr + offset + 16);
- Vector128<int> block3B = Sse2.LoadVector128(inptr + offset + 20);
-
- Vector128<int> block4A = Sse2.LoadVector128(inptr + offset + 24);
- Vector128<int> block4B = Sse2.LoadVector128(inptr + offset + 28);
-
- Vector128<short> output1 = Sse2.PackSignedSaturate(block1A, block1B);
- Vector128<short> output2 = Sse2.PackSignedSaturate(block2A, block2B);
- Vector128<short> output3 = Sse2.PackSignedSaturate(block3A, block3B);
- Vector128<short> output4 = Sse2.PackSignedSaturate(block4A, block4B);
-
- Sse2.Store(outptr + offset + 0, output1);
- Sse2.Store(outptr + offset + 8, output2);
- Sse2.Store(outptr + offset + 16, output3);
- Sse2.Store(outptr + offset + 24, output4);
- }
- }
- }
-
- // Process left overs
- for (; offset < buffer.Length; offset++)
- {
- output[offset] = DspUtils.Saturate(buffer[offset]);
- }
-
- return output;
- }
-
- public void Dispose()
- {
- Dispose(true);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- _audioOut.CloseTrack(_track);
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/MemoryPoolContext.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/MemoryPoolContext.cs
deleted file mode 100644
index 3f48114c..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/MemoryPoolContext.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- class MemoryPoolContext
- {
- public MemoryPoolOut OutStatus;
-
- public MemoryPoolContext()
- {
- OutStatus.State = MemoryPoolState.Detached;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/NodeStates.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/NodeStates.cs
deleted file mode 100644
index 7ae9aeea..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/NodeStates.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using Ryujinx.Common;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- static class NodeStates
- {
- public static long GetWorkBufferSize(int totalMixCount)
- {
- int size = BitUtils.AlignUp(totalMixCount, AudioRendererConsts.BufferAlignment);
-
- if (size < 0)
- {
- size |= 7;
- }
-
- return 4 * (totalMixCount * totalMixCount) + 12 * totalMixCount + 2 * (size / 8);
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/PerformanceManager.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/PerformanceManager.cs
deleted file mode 100644
index a5b3d79f..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/PerformanceManager.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using Ryujinx.Common.Logging;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- static class PerformanceManager
- {
- public static long GetRequiredBufferSizeForPerformanceMetricsPerFrame(BehaviorInfo behaviorInfo, AudioRendererParameter parameters)
- {
- int performanceMetricsDataFormat = behaviorInfo.GetPerformanceMetricsDataFormat();
-
- if (performanceMetricsDataFormat == 2)
- {
- return 24 * (parameters.VoiceCount +
- parameters.EffectCount +
- parameters.SubMixCount +
- parameters.SinkCount + 1) + 0x990;
- }
-
- if (performanceMetricsDataFormat != 1)
- {
- Logger.Warning?.Print(LogClass.ServiceAudio, $"PerformanceMetricsDataFormat: {performanceMetricsDataFormat} is not supported!");
- }
-
- return (((parameters.VoiceCount +
- parameters.EffectCount +
- parameters.SubMixCount +
- parameters.SinkCount + 1) << 32) >> 0x1C) + 0x658;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Resampler.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Resampler.cs
deleted file mode 100644
index 936e7f50..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Resampler.cs
+++ /dev/null
@@ -1,191 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- static class Resampler
- {
-#region "LookUp Tables"
- private static short[] _curveLut0 = new short[]
- {
- 6600, 19426, 6722, 3, 6479, 19424, 6845, 9, 6359, 19419, 6968, 15, 6239, 19412, 7093, 22,
- 6121, 19403, 7219, 28, 6004, 19391, 7345, 34, 5888, 19377, 7472, 41, 5773, 19361, 7600, 48,
- 5659, 19342, 7728, 55, 5546, 19321, 7857, 62, 5434, 19298, 7987, 69, 5323, 19273, 8118, 77,
- 5213, 19245, 8249, 84, 5104, 19215, 8381, 92, 4997, 19183, 8513, 101, 4890, 19148, 8646, 109,
- 4785, 19112, 8780, 118, 4681, 19073, 8914, 127, 4579, 19031, 9048, 137, 4477, 18988, 9183, 147,
- 4377, 18942, 9318, 157, 4277, 18895, 9454, 168, 4179, 18845, 9590, 179, 4083, 18793, 9726, 190,
- 3987, 18738, 9863, 202, 3893, 18682, 10000, 215, 3800, 18624, 10137, 228, 3709, 18563, 10274, 241,
- 3618, 18500, 10411, 255, 3529, 18436, 10549, 270, 3441, 18369, 10687, 285, 3355, 18300, 10824, 300,
- 3269, 18230, 10962, 317, 3186, 18157, 11100, 334, 3103, 18082, 11238, 351, 3022, 18006, 11375, 369,
- 2942, 17927, 11513, 388, 2863, 17847, 11650, 408, 2785, 17765, 11788, 428, 2709, 17681, 11925, 449,
- 2635, 17595, 12062, 471, 2561, 17507, 12198, 494, 2489, 17418, 12334, 517, 2418, 17327, 12470, 541,
- 2348, 17234, 12606, 566, 2280, 17140, 12741, 592, 2213, 17044, 12876, 619, 2147, 16946, 13010, 647,
- 2083, 16846, 13144, 675, 2020, 16745, 13277, 704, 1958, 16643, 13409, 735, 1897, 16539, 13541, 766,
- 1838, 16434, 13673, 798, 1780, 16327, 13803, 832, 1723, 16218, 13933, 866, 1667, 16109, 14062, 901,
- 1613, 15998, 14191, 937, 1560, 15885, 14318, 975, 1508, 15772, 14445, 1013, 1457, 15657, 14571, 1052,
- 1407, 15540, 14695, 1093, 1359, 15423, 14819, 1134, 1312, 15304, 14942, 1177, 1266, 15185, 15064, 1221,
- 1221, 15064, 15185, 1266, 1177, 14942, 15304, 1312, 1134, 14819, 15423, 1359, 1093, 14695, 15540, 1407,
- 1052, 14571, 15657, 1457, 1013, 14445, 15772, 1508, 975, 14318, 15885, 1560, 937, 14191, 15998, 1613,
- 901, 14062, 16109, 1667, 866, 13933, 16218, 1723, 832, 13803, 16327, 1780, 798, 13673, 16434, 1838,
- 766, 13541, 16539, 1897, 735, 13409, 16643, 1958, 704, 13277, 16745, 2020, 675, 13144, 16846, 2083,
- 647, 13010, 16946, 2147, 619, 12876, 17044, 2213, 592, 12741, 17140, 2280, 566, 12606, 17234, 2348,
- 541, 12470, 17327, 2418, 517, 12334, 17418, 2489, 494, 12198, 17507, 2561, 471, 12062, 17595, 2635,
- 449, 11925, 17681, 2709, 428, 11788, 17765, 2785, 408, 11650, 17847, 2863, 388, 11513, 17927, 2942,
- 369, 11375, 18006, 3022, 351, 11238, 18082, 3103, 334, 11100, 18157, 3186, 317, 10962, 18230, 3269,
- 300, 10824, 18300, 3355, 285, 10687, 18369, 3441, 270, 10549, 18436, 3529, 255, 10411, 18500, 3618,
- 241, 10274, 18563, 3709, 228, 10137, 18624, 3800, 215, 10000, 18682, 3893, 202, 9863, 18738, 3987,
- 190, 9726, 18793, 4083, 179, 9590, 18845, 4179, 168, 9454, 18895, 4277, 157, 9318, 18942, 4377,
- 147, 9183, 18988, 4477, 137, 9048, 19031, 4579, 127, 8914, 19073, 4681, 118, 8780, 19112, 4785,
- 109, 8646, 19148, 4890, 101, 8513, 19183, 4997, 92, 8381, 19215, 5104, 84, 8249, 19245, 5213,
- 77, 8118, 19273, 5323, 69, 7987, 19298, 5434, 62, 7857, 19321, 5546, 55, 7728, 19342, 5659,
- 48, 7600, 19361, 5773, 41, 7472, 19377, 5888, 34, 7345, 19391, 6004, 28, 7219, 19403, 6121,
- 22, 7093, 19412, 6239, 15, 6968, 19419, 6359, 9, 6845, 19424, 6479, 3, 6722, 19426, 6600
- };
-
- private static short[] _curveLut1 = new short[]
- {
- -68, 32639, 69, -5, -200, 32630, 212, -15, -328, 32613, 359, -26, -450, 32586, 512, -36,
- -568, 32551, 669, -47, -680, 32507, 832, -58, -788, 32454, 1000, -69, -891, 32393, 1174, -80,
- -990, 32323, 1352, -92, -1084, 32244, 1536, -103, -1173, 32157, 1724, -115, -1258, 32061, 1919, -128,
- -1338, 31956, 2118, -140, -1414, 31844, 2322, -153, -1486, 31723, 2532, -167, -1554, 31593, 2747, -180,
- -1617, 31456, 2967, -194, -1676, 31310, 3192, -209, -1732, 31157, 3422, -224, -1783, 30995, 3657, -240,
- -1830, 30826, 3897, -256, -1874, 30649, 4143, -272, -1914, 30464, 4393, -289, -1951, 30272, 4648, -307,
- -1984, 30072, 4908, -325, -2014, 29866, 5172, -343, -2040, 29652, 5442, -362, -2063, 29431, 5716, -382,
- -2083, 29203, 5994, -403, -2100, 28968, 6277, -424, -2114, 28727, 6565, -445, -2125, 28480, 6857, -468,
- -2133, 28226, 7153, -490, -2139, 27966, 7453, -514, -2142, 27700, 7758, -538, -2142, 27428, 8066, -563,
- -2141, 27151, 8378, -588, -2136, 26867, 8694, -614, -2130, 26579, 9013, -641, -2121, 26285, 9336, -668,
- -2111, 25987, 9663, -696, -2098, 25683, 9993, -724, -2084, 25375, 10326, -753, -2067, 25063, 10662, -783,
- -2049, 24746, 11000, -813, -2030, 24425, 11342, -844, -2009, 24100, 11686, -875, -1986, 23771, 12033, -907,
- -1962, 23438, 12382, -939, -1937, 23103, 12733, -972, -1911, 22764, 13086, -1005, -1883, 22422, 13441, -1039,
- -1855, 22077, 13798, -1072, -1825, 21729, 14156, -1107, -1795, 21380, 14516, -1141, -1764, 21027, 14877, -1176,
- -1732, 20673, 15239, -1211, -1700, 20317, 15602, -1246, -1667, 19959, 15965, -1282, -1633, 19600, 16329, -1317,
- -1599, 19239, 16694, -1353, -1564, 18878, 17058, -1388, -1530, 18515, 17423, -1424, -1495, 18151, 17787, -1459,
- -1459, 17787, 18151, -1495, -1424, 17423, 18515, -1530, -1388, 17058, 18878, -1564, -1353, 16694, 19239, -1599,
- -1317, 16329, 19600, -1633, -1282, 15965, 19959, -1667, -1246, 15602, 20317, -1700, -1211, 15239, 20673, -1732,
- -1176, 14877, 21027, -1764, -1141, 14516, 21380, -1795, -1107, 14156, 21729, -1825, -1072, 13798, 22077, -1855,
- -1039, 13441, 22422, -1883, -1005, 13086, 22764, -1911, -972, 12733, 23103, -1937, -939, 12382, 23438, -1962,
- -907, 12033, 23771, -1986, -875, 11686, 24100, -2009, -844, 11342, 24425, -2030, -813, 11000, 24746, -2049,
- -783, 10662, 25063, -2067, -753, 10326, 25375, -2084, -724, 9993, 25683, -2098, -696, 9663, 25987, -2111,
- -668, 9336, 26285, -2121, -641, 9013, 26579, -2130, -614, 8694, 26867, -2136, -588, 8378, 27151, -2141,
- -563, 8066, 27428, -2142, -538, 7758, 27700, -2142, -514, 7453, 27966, -2139, -490, 7153, 28226, -2133,
- -468, 6857, 28480, -2125, -445, 6565, 28727, -2114, -424, 6277, 28968, -2100, -403, 5994, 29203, -2083,
- -382, 5716, 29431, -2063, -362, 5442, 29652, -2040, -343, 5172, 29866, -2014, -325, 4908, 30072, -1984,
- -307, 4648, 30272, -1951, -289, 4393, 30464, -1914, -272, 4143, 30649, -1874, -256, 3897, 30826, -1830,
- -240, 3657, 30995, -1783, -224, 3422, 31157, -1732, -209, 3192, 31310, -1676, -194, 2967, 31456, -1617,
- -180, 2747, 31593, -1554, -167, 2532, 31723, -1486, -153, 2322, 31844, -1414, -140, 2118, 31956, -1338,
- -128, 1919, 32061, -1258, -115, 1724, 32157, -1173, -103, 1536, 32244, -1084, -92, 1352, 32323, -990,
- -80, 1174, 32393, -891, -69, 1000, 32454, -788, -58, 832, 32507, -680, -47, 669, 32551, -568,
- -36, 512, 32586, -450, -26, 359, 32613, -328, -15, 212, 32630, -200, -5, 69, 32639, -68
- };
-
- private static short[] _curveLut2 = new short[]
- {
- 3195, 26287, 3329, -32, 3064, 26281, 3467, -34, 2936, 26270, 3608, -38, 2811, 26253, 3751, -42,
- 2688, 26230, 3897, -46, 2568, 26202, 4046, -50, 2451, 26169, 4199, -54, 2338, 26130, 4354, -58,
- 2227, 26085, 4512, -63, 2120, 26035, 4673, -67, 2015, 25980, 4837, -72, 1912, 25919, 5004, -76,
- 1813, 25852, 5174, -81, 1716, 25780, 5347, -87, 1622, 25704, 5522, -92, 1531, 25621, 5701, -98,
- 1442, 25533, 5882, -103, 1357, 25440, 6066, -109, 1274, 25342, 6253, -115, 1193, 25239, 6442, -121,
- 1115, 25131, 6635, -127, 1040, 25018, 6830, -133, 967, 24899, 7027, -140, 897, 24776, 7227, -146,
- 829, 24648, 7430, -153, 764, 24516, 7635, -159, 701, 24379, 7842, -166, 641, 24237, 8052, -174,
- 583, 24091, 8264, -181, 526, 23940, 8478, -187, 472, 23785, 8695, -194, 420, 23626, 8914, -202,
- 371, 23462, 9135, -209, 324, 23295, 9358, -215, 279, 23123, 9583, -222, 236, 22948, 9809, -230,
- 194, 22769, 10038, -237, 154, 22586, 10269, -243, 117, 22399, 10501, -250, 81, 22208, 10735, -258,
- 47, 22015, 10970, -265, 15, 21818, 11206, -271, -16, 21618, 11444, -277, -44, 21415, 11684, -283,
- -71, 21208, 11924, -290, -97, 20999, 12166, -296, -121, 20786, 12409, -302, -143, 20571, 12653, -306,
- -163, 20354, 12898, -311, -183, 20134, 13143, -316, -201, 19911, 13389, -321, -218, 19686, 13635, -325,
- -234, 19459, 13882, -328, -248, 19230, 14130, -332, -261, 18998, 14377, -335, -273, 18765, 14625, -337,
- -284, 18531, 14873, -339, -294, 18295, 15121, -341, -302, 18057, 15369, -341, -310, 17817, 15617, -341,
- -317, 17577, 15864, -340, -323, 17335, 16111, -340, -328, 17092, 16357, -338, -332, 16848, 16603, -336,
- -336, 16603, 16848, -332, -338, 16357, 17092, -328, -340, 16111, 17335, -323, -340, 15864, 17577, -317,
- -341, 15617, 17817, -310, -341, 15369, 18057, -302, -341, 15121, 18295, -294, -339, 14873, 18531, -284,
- -337, 14625, 18765, -273, -335, 14377, 18998, -261, -332, 14130, 19230, -248, -328, 13882, 19459, -234,
- -325, 13635, 19686, -218, -321, 13389, 19911, -201, -316, 13143, 20134, -183, -311, 12898, 20354, -163,
- -306, 12653, 20571, -143, -302, 12409, 20786, -121, -296, 12166, 20999, -97, -290, 11924, 21208, -71,
- -283, 11684, 21415, -44, -277, 11444, 21618, -16, -271, 11206, 21818, 15, -265, 10970, 22015, 47,
- -258, 10735, 22208, 81, -250, 10501, 22399, 117, -243, 10269, 22586, 154, -237, 10038, 22769, 194,
- -230, 9809, 22948, 236, -222, 9583, 23123, 279, -215, 9358, 23295, 324, -209, 9135, 23462, 371,
- -202, 8914, 23626, 420, -194, 8695, 23785, 472, -187, 8478, 23940, 526, -181, 8264, 24091, 583,
- -174, 8052, 24237, 641, -166, 7842, 24379, 701, -159, 7635, 24516, 764, -153, 7430, 24648, 829,
- -146, 7227, 24776, 897, -140, 7027, 24899, 967, -133, 6830, 25018, 1040, -127, 6635, 25131, 1115,
- -121, 6442, 25239, 1193, -115, 6253, 25342, 1274, -109, 6066, 25440, 1357, -103, 5882, 25533, 1442,
- -98, 5701, 25621, 1531, -92, 5522, 25704, 1622, -87, 5347, 25780, 1716, -81, 5174, 25852, 1813,
- -76, 5004, 25919, 1912, -72, 4837, 25980, 2015, -67, 4673, 26035, 2120, -63, 4512, 26085, 2227,
- -58, 4354, 26130, 2338, -54, 4199, 26169, 2451, -50, 4046, 26202, 2568, -46, 3897, 26230, 2688,
- -42, 3751, 26253, 2811, -38, 3608, 26270, 2936, -34, 3467, 26281, 3064, -32, 3329, 26287, 3195
- };
-#endregion
-
- public static int[] Resample2Ch(
- int[] buffer,
- int srcSampleRate,
- int dstSampleRate,
- int samplesCount,
- ref int fracPart)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
-
- if (srcSampleRate <= 0)
- {
- throw new ArgumentOutOfRangeException(nameof(srcSampleRate));
- }
-
- if (dstSampleRate <= 0)
- {
- throw new ArgumentOutOfRangeException(nameof(dstSampleRate));
- }
-
- double ratio = (double)srcSampleRate / dstSampleRate;
-
- int newSamplesCount = (int)(samplesCount / ratio);
-
- int step = (int)(ratio * 0x8000);
-
- int[] output = new int[newSamplesCount * 2];
-
- short[] lut;
-
- if (step > 0xaaaa)
- {
- lut = _curveLut0;
- }
- else if (step <= 0x8000)
- {
- lut = _curveLut1;
- }
- else
- {
- lut = _curveLut2;
- }
-
- int inOffs = 0;
-
- for (int outOffs = 0; outOffs < output.Length; outOffs += 2)
- {
- int lutIndex = (fracPart >> 8) * 4;
-
- int sample0 = buffer[(inOffs + 0) * 2 + 0] * lut[lutIndex + 0] +
- buffer[(inOffs + 1) * 2 + 0] * lut[lutIndex + 1] +
- buffer[(inOffs + 2) * 2 + 0] * lut[lutIndex + 2] +
- buffer[(inOffs + 3) * 2 + 0] * lut[lutIndex + 3];
-
- int sample1 = buffer[(inOffs + 0) * 2 + 1] * lut[lutIndex + 0] +
- buffer[(inOffs + 1) * 2 + 1] * lut[lutIndex + 1] +
- buffer[(inOffs + 2) * 2 + 1] * lut[lutIndex + 2] +
- buffer[(inOffs + 3) * 2 + 1] * lut[lutIndex + 3];
-
- int newOffset = fracPart + step;
-
- inOffs += newOffset >> 15;
-
- fracPart = newOffset & 0x7fff;
-
- output[outOffs + 0] = sample0 >> 15;
- output[outOffs + 1] = sample1 >> 15;
- }
-
- return output;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/SplitterContext.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/SplitterContext.cs
deleted file mode 100644
index e46af443..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/SplitterContext.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using Ryujinx.Common;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- class SplitterContext
- {
- public static long CalcWorkBufferSize(BehaviorInfo behaviorInfo, AudioRendererParameter parameters)
- {
- if (!behaviorInfo.IsSplitterSupported())
- {
- return 0;
- }
-
- long size = parameters.SplitterDestinationDataCount * 0xE0 +
- parameters.SplitterCount * 0x20;
-
- if (!behaviorInfo.IsSplitterBugFixed())
- {
- size += BitUtils.AlignUp(4 * parameters.SplitterDestinationDataCount, 16);
- }
-
- return size;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererConsts.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererConsts.cs
deleted file mode 100644
index 864bda0d..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererConsts.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- static class AudioRendererConsts
- {
- // Revision Consts
- public const int Revision = 8;
- public const int Rev0Magic = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('0' << 24);
- public const int RevMagic = Rev0Magic + (Revision << 24);
-
- // Misc Consts
- public const int BufferAlignment = 0x40;
-
- // Host Consts
- public const int HostSampleRate = 48000;
- public const int HostChannelsCount = 2;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs
deleted file mode 100644
index 2cfbc4b7..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/AudioRendererParameter.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential)]
- struct AudioRendererParameter
- {
- public int SampleRate;
- public int SampleCount;
- public int MixBufferCount;
- public int SubMixCount;
- public int VoiceCount;
- public int SinkCount;
- public int EffectCount;
- public int PerformanceManagerCount;
- public int VoiceDropEnable;
- public int SplitterCount;
- public int SplitterDestinationDataCount;
- public int Unknown2C;
- public int Revision;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BehaviorIn.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BehaviorIn.cs
deleted file mode 100644
index 953b4ce3..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BehaviorIn.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)]
- struct BehaviorIn
- {
- public long Unknown0;
- public long Unknown8;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BiquadFilter.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BiquadFilter.cs
deleted file mode 100644
index d0d8ed9b..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/BiquadFilter.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential, Size = 0xc, Pack = 1)]
- struct BiquadFilter
- {
- public byte Enable;
- public byte Padding;
- public short B0;
- public short B1;
- public short B2;
- public short A1;
- public short A2;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectIn.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectIn.cs
deleted file mode 100644
index 03520475..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectIn.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential, Size = 0xc0, Pack = 1)]
- unsafe struct EffectIn
- {
- public byte Unknown0x0;
- public byte IsNew;
- public fixed byte Unknown[0xbe];
- }
-}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectOut.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectOut.cs
deleted file mode 100644
index 5106ad9e..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectOut.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 1)]
- unsafe struct EffectOut
- {
- public EffectState State;
- public fixed byte Reserved[15];
- }
-}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectState.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectState.cs
deleted file mode 100644
index ed676684..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/EffectState.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- enum EffectState : byte
- {
- None = 0,
- New = 1
- }
-}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolIn.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolIn.cs
deleted file mode 100644
index 8dc53929..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolIn.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 4)]
- struct MemoryPoolIn
- {
- public long Address;
- public long Size;
- public MemoryPoolState State;
- public int Unknown14;
- public long Unknown18;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolOut.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolOut.cs
deleted file mode 100644
index 7581e8a7..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolOut.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)]
- struct MemoryPoolOut
- {
- public MemoryPoolState State;
- public int Unknown14;
- public long Unknown18;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolState.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolState.cs
deleted file mode 100644
index a82747b8..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/MemoryPoolState.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- enum MemoryPoolState
- {
- Invalid = 0,
- Unknown = 1,
- RequestDetach = 2,
- Detached = 3,
- RequestAttach = 4,
- Attached = 5,
- Released = 6
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/PlayState.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/PlayState.cs
deleted file mode 100644
index d63df971..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/PlayState.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- enum PlayState : byte
- {
- Playing = 0,
- Stopped = 1,
- Paused = 2
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/RendererInfoOut.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/RendererInfoOut.cs
deleted file mode 100644
index 0ea89384..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/RendererInfoOut.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)]
- struct RendererInfoOut
- {
- public ulong ElapsedFrameCount;
- public ulong Reserved;
- }
-}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/SupportTags.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/SupportTags.cs
deleted file mode 100644
index a418d89e..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/SupportTags.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- static class SupportTags
- {
- public const int Splitter = 2;
- public const int SplitterBugFix = 5;
- public const int PerformanceMetricsDataFormatVersion2 = 5;
- public const int VariadicCommandBufferSize = 5;
- public const int ElapsedFrameCount = 5;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs
deleted file mode 100644
index 6adb874c..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/UpdateDataHeader.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- struct UpdateDataHeader
- {
-#pragma warning disable CS0649
- public int Revision;
- public int BehaviorSize;
- public int MemoryPoolSize;
- public int VoiceSize;
- public int VoiceResourceSize;
- public int EffectSize;
- public int MixSize;
- public int SinkSize;
- public int PerformanceManagerSize;
- public int Unknown24;
- public int ElapsedFrameCountInfoSize;
- public int Unknown2C;
- public int Unknown30;
- public int Unknown34;
- public int Unknown38;
- public int TotalSize;
-#pragma warning restore CS0649
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceChannelResourceIn.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceChannelResourceIn.cs
deleted file mode 100644
index 4871713e..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceChannelResourceIn.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential, Size = 0x70, Pack = 1)]
- struct VoiceChannelResourceIn
- {
- // ???
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceIn.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceIn.cs
deleted file mode 100644
index dbcd5558..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceIn.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential, Size = 0x170, Pack = 1)]
- struct VoiceIn
- {
- public int VoiceSlot;
- public int NodeId;
-
- public byte FirstUpdate;
- public byte Acquired;
-
- public PlayState PlayState;
-
- public SampleFormat SampleFormat;
-
- public int SampleRate;
-
- public int Priority;
-
- public int Unknown14;
-
- public int ChannelsCount;
-
- public float Pitch;
- public float Volume;
-
- public BiquadFilter BiquadFilter0;
- public BiquadFilter BiquadFilter1;
-
- public int AppendedWaveBuffersCount;
-
- public int BaseWaveBufferIndex;
-
- public int Unknown44;
-
- public long AdpcmCoeffsPosition;
- public long AdpcmCoeffsSize;
-
- public int VoiceDestination;
- public int Padding;
-
- public WaveBuffer WaveBuffer0;
- public WaveBuffer WaveBuffer1;
- public WaveBuffer WaveBuffer2;
- public WaveBuffer WaveBuffer3;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceOut.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceOut.cs
deleted file mode 100644
index 3a295971..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/VoiceOut.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)]
- struct VoiceOut
- {
- public long PlayedSamplesCount;
- public int PlayedWaveBuffersCount;
- public int VoiceDropsCount; //?
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/WaveBuffer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/WaveBuffer.cs
deleted file mode 100644
index 1c0d5630..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/Types/WaveBuffer.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- [StructLayout(LayoutKind.Sequential, Size = 0x38, Pack = 1)]
- struct WaveBuffer
- {
- public long Position;
- public long Size;
- public int FirstSampleOffset;
- public int LastSampleOffset;
- public byte Looping;
- public byte LastBuffer;
- public short Unknown1A;
- public int Unknown1C;
- public long AdpcmLoopContextPosition;
- public long AdpcmLoopContextSize;
- public long Unknown30;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs
deleted file mode 100644
index c14c46b3..00000000
--- a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager/VoiceContext.cs
+++ /dev/null
@@ -1,201 +0,0 @@
-using Ryujinx.Audio.Adpcm;
-using Ryujinx.Cpu;
-using System;
-
-namespace Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager
-{
- class VoiceContext
- {
- private bool _acquired;
- private bool _bufferReload;
-
- private int _resamplerFracPart;
-
- private int _bufferIndex;
- private int _offset;
-
- public int SampleRate { get; set; }
- public int ChannelsCount { get; set; }
-
- public float Volume { get; set; }
-
- public PlayState PlayState { get; set; }
-
- public SampleFormat SampleFormat { get; set; }
-
- public AdpcmDecoderContext AdpcmCtx { get; set; }
-
- public WaveBuffer[] WaveBuffers { get; }
-
- public WaveBuffer CurrentWaveBuffer => WaveBuffers[_bufferIndex];
-
- private VoiceOut _outStatus;
-
- public VoiceOut OutStatus => _outStatus;
-
- private int[] _samples;
-
- public bool Playing => _acquired && PlayState == PlayState.Playing;
-
- public VoiceContext()
- {
- WaveBuffers = new WaveBuffer[4];
- }
-
- public void SetAcquireState(bool newState)
- {
- if (_acquired && !newState)
- {
- // Release.
- Reset();
- }
-
- _acquired = newState;
- }
-
- private void Reset()
- {
- _bufferReload = true;
-
- _bufferIndex = 0;
- _offset = 0;
-
- _outStatus.PlayedSamplesCount = 0;
- _outStatus.PlayedWaveBuffersCount = 0;
- _outStatus.VoiceDropsCount = 0;
- }
-
- public int[] GetBufferData(MemoryManager memory, int maxSamples, out int samplesCount)
- {
- if (!Playing)
- {
- samplesCount = 0;
-
- return null;
- }
-
- if (_bufferReload)
- {
- _bufferReload = false;
-
- UpdateBuffer(memory);
- }
-
- WaveBuffer wb = WaveBuffers[_bufferIndex];
-
- int maxSize = _samples.Length - _offset;
-
- int size = maxSamples * AudioRendererConsts.HostChannelsCount;
-
- if (size > maxSize)
- {
- size = maxSize;
- }
-
- int[] output = new int[size];
-
- Array.Copy(_samples, _offset, output, 0, size);
-
- samplesCount = size / AudioRendererConsts.HostChannelsCount;
-
- _outStatus.PlayedSamplesCount += samplesCount;
-
- _offset += size;
-
- if (_offset == _samples.Length)
- {
- _offset = 0;
-
- if (wb.Looping == 0)
- {
- SetBufferIndex(_bufferIndex + 1);
- }
-
- _outStatus.PlayedWaveBuffersCount++;
-
- if (wb.LastBuffer != 0)
- {
- PlayState = PlayState.Paused;
- }
- }
-
- return output;
- }
-
- private void UpdateBuffer(MemoryManager memory)
- {
- // TODO: Implement conversion for formats other
- // than interleaved stereo (2 channels).
- // As of now, it assumes that HostChannelsCount == 2.
- WaveBuffer wb = WaveBuffers[_bufferIndex];
-
- if (wb.Position == 0)
- {
- _samples = new int[0];
-
- return;
- }
-
- if (SampleFormat == SampleFormat.PcmInt16)
- {
- int samplesCount = (int)(wb.Size / (sizeof(short) * ChannelsCount));
-
- _samples = new int[samplesCount * AudioRendererConsts.HostChannelsCount];
-
- if (ChannelsCount == 1)
- {
- for (int index = 0; index < samplesCount; index++)
- {
- short sample = memory.Read<short>((ulong)(wb.Position + index * 2));
-
- _samples[index * 2 + 0] = sample;
- _samples[index * 2 + 1] = sample;
- }
- }
- else
- {
- for (int index = 0; index < samplesCount * 2; index++)
- {
- _samples[index] = memory.Read<short>((ulong)(wb.Position + index * 2));
- }
- }
- }
- else if (SampleFormat == SampleFormat.Adpcm)
- {
- byte[] buffer = new byte[wb.Size];
-
- memory.Read((ulong)wb.Position, buffer);
-
- _samples = AdpcmDecoder.Decode(buffer, AdpcmCtx);
- }
- else
- {
- throw new InvalidOperationException();
- }
-
- if (SampleRate != AudioRendererConsts.HostSampleRate)
- {
- // TODO: We should keep the frames being discarded (see the 4 below)
- // on a buffer and include it on the next samples buffer, to allow
- // the resampler to do seamless interpolation between wave buffers.
- int samplesCount = _samples.Length / AudioRendererConsts.HostChannelsCount;
-
- samplesCount = Math.Max(samplesCount - 4, 0);
-
- _samples = Resampler.Resample2Ch(
- _samples,
- SampleRate,
- AudioRendererConsts.HostSampleRate,
- samplesCount,
- ref _resamplerFracPart);
- }
- }
-
- public void SetBufferIndex(int index)
- {
- _bufferIndex = index & 3;
-
- _bufferReload = true;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs
new file mode 100644
index 00000000..94972dbf
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs
@@ -0,0 +1,105 @@
+using Ryujinx.Audio.Renderer.Parameter;
+using Ryujinx.Audio.Renderer.Server;
+using Ryujinx.Common;
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer;
+
+namespace Ryujinx.HLE.HOS.Services.Audio
+{
+ [Service("audren:u")]
+ class AudioRendererManagerServer : IpcService
+ {
+ private const int InitialRevision = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('1' << 24);
+
+ private IAudioRendererManager _impl;
+
+ public AudioRendererManagerServer(ServiceCtx context) : this(new AudioRendererManager(context.Device.System.AudioRendererManager, context.Device.System.AudioDeviceSessionRegistry)) { }
+
+ public AudioRendererManagerServer(IAudioRendererManager impl)
+ {
+ _impl = impl;
+ }
+
+ [Command(0)]
+ // OpenAudioRenderer(nn::audio::detail::AudioRendererParameterInternal parameter, u64 workBufferSize, nn::applet::AppletResourceUserId appletResourceId, pid, handle<copy> workBuffer, handle<copy> processHandle)
+ // -> object<nn::audio::detail::IAudioRenderer>
+ public ResultCode OpenAudioRenderer(ServiceCtx context)
+ {
+ AudioRendererConfiguration parameter = context.RequestData.ReadStruct<AudioRendererConfiguration>();
+ ulong workBufferSize = context.RequestData.ReadUInt64();
+ ulong appletResourceUserId = context.RequestData.ReadUInt64();
+
+ KTransferMemory workBufferTransferMemory = context.Process.HandleTable.GetObject<KTransferMemory>(context.Request.HandleDesc.ToCopy[0]);
+ uint processHandle = (uint)context.Request.HandleDesc.ToCopy[1];
+
+ ResultCode result = _impl.OpenAudioRenderer(context, out IAudioRenderer renderer, ref parameter, workBufferSize, appletResourceUserId, workBufferTransferMemory, processHandle);
+
+ if (result == ResultCode.Success)
+ {
+ MakeObject(context, new AudioRendererServer(renderer));
+ }
+
+ return result;
+ }
+
+ [Command(1)]
+ // GetWorkBufferSize(nn::audio::detail::AudioRendererParameterInternal parameter) -> u64 workBufferSize
+ public ResultCode GetAudioRendererWorkBufferSize(ServiceCtx context)
+ {
+ AudioRendererConfiguration parameter = context.RequestData.ReadStruct<AudioRendererConfiguration>();
+
+ if (BehaviourContext.CheckValidRevision(parameter.Revision))
+ {
+ ulong size = _impl.GetWorkBufferSize(ref parameter);
+
+ context.ResponseData.Write(size);
+
+ Logger.Debug?.Print(LogClass.ServiceAudio, $"WorkBufferSize is 0x{size:x16}.");
+
+ return ResultCode.Success;
+ }
+ else
+ {
+ context.ResponseData.Write(0L);
+
+ Logger.Warning?.Print(LogClass.ServiceAudio, $"Library Revision REV{BehaviourContext.GetRevisionNumber(parameter.Revision)} is not supported!");
+
+ return ResultCode.UnsupportedRevision;
+ }
+ }
+
+ [Command(2)]
+ // GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object<nn::audio::detail::IAudioDevice>
+ public ResultCode GetAudioDeviceService(ServiceCtx context)
+ {
+ ulong appletResourceUserId = context.RequestData.ReadUInt64();
+
+ ResultCode result = _impl.GetAudioDeviceServiceWithRevisionInfo(context, out IAudioDevice device, InitialRevision, appletResourceUserId);
+
+ if (result == ResultCode.Success)
+ {
+ MakeObject(context, new AudioDeviceServer(device));
+ }
+
+ return result;
+ }
+
+ [Command(4)] // 4.0.0+
+ // GetAudioDeviceServiceWithRevisionInfo(s32 revision, nn::applet::AppletResourceUserId appletResourceId) -> object<nn::audio::detail::IAudioDevice>
+ public ResultCode GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context)
+ {
+ int revision = context.RequestData.ReadInt32();
+ ulong appletResourceUserId = context.RequestData.ReadUInt64();
+
+ ResultCode result = _impl.GetAudioDeviceServiceWithRevisionInfo(context, out IAudioDevice device, revision, appletResourceUserId);
+
+ if (result == ResultCode.Success)
+ {
+ MakeObject(context, new AudioDeviceServer(device));
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs
index 7e770a78..642e2525 100644
--- a/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs
@@ -1,148 +1,19 @@
-using Ryujinx.Audio;
-using Ryujinx.Common;
-using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager;
+using Ryujinx.Audio.Renderer.Parameter;
+using Ryujinx.HLE.HOS.Kernel.Memory;
+using Ryujinx.HLE.HOS.Services.Audio.AudioRenderer;
namespace Ryujinx.HLE.HOS.Services.Audio
{
- [Service("audren:u")]
- class IAudioRendererManager : IpcService
+ interface IAudioRendererManager
{
- public IAudioRendererManager(ServiceCtx context) { }
+ // TODO: Remove ServiceCtx argument
+ // BODY: This is only needed by the legacy backend. Refactor this when removing the legacy backend.
+ ResultCode GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context, out IAudioDevice outObject, int revision, ulong appletResourceUserId);
- [Command(0)]
- // OpenAudioRenderer(nn::audio::detail::AudioRendererParameterInternal, u64, nn::applet::AppletResourceUserId, pid, handle<copy>, handle<copy>)
- // -> object<nn::audio::detail::IAudioRenderer>
- public ResultCode OpenAudioRenderer(ServiceCtx context)
- {
- IAalOutput audioOut = context.Device.AudioOut;
+ // TODO: Remove ServiceCtx argument
+ // BODY: This is only needed by the legacy backend. Refactor this when removing the legacy backend.
+ ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle);
- AudioRendererParameter Params = GetAudioRendererParameter(context);
-
- MakeObject(context, new IAudioRenderer(
- context.Device.System,
- context.Memory,
- audioOut,
- Params));
-
- return ResultCode.Success;
- }
-
- [Command(1)]
- // GetWorkBufferSize(nn::audio::detail::AudioRendererParameterInternal) -> u64
- public ResultCode GetAudioRendererWorkBufferSize(ServiceCtx context)
- {
- AudioRendererParameter parameters = GetAudioRendererParameter(context);
-
- if (AudioRendererCommon.CheckValidRevision(parameters))
- {
- BehaviorInfo behaviorInfo = new BehaviorInfo();
-
- behaviorInfo.SetUserLibRevision(parameters.Revision);
-
- long size;
-
- int totalMixCount = parameters.SubMixCount + 1;
-
- size = BitUtils.AlignUp(parameters.MixBufferCount * 4, AudioRendererConsts.BufferAlignment) +
- parameters.SubMixCount * 0x400 +
- totalMixCount * 0x940 +
- parameters.VoiceCount * 0x3F0 +
- BitUtils.AlignUp(totalMixCount * 8, 16) +
- BitUtils.AlignUp(parameters.VoiceCount * 8, 16) +
- BitUtils.AlignUp(((parameters.SinkCount + parameters.SubMixCount) * 0x3C0 + parameters.SampleCount * 4) *
- (parameters.MixBufferCount + 6), AudioRendererConsts.BufferAlignment) +
- (parameters.SinkCount + parameters.SubMixCount) * 0x2C0 +
- (parameters.EffectCount + parameters.VoiceCount * 4) * 0x30 +
- 0x50;
-
- if (behaviorInfo.IsSplitterSupported())
- {
- size += BitUtils.AlignUp(NodeStates.GetWorkBufferSize(totalMixCount) + EdgeMatrix.GetWorkBufferSize(totalMixCount), 16);
- }
-
- size = parameters.SinkCount * 0x170 +
- (parameters.SinkCount + parameters.SubMixCount) * 0x280 +
- parameters.EffectCount * 0x4C0 +
- ((size + SplitterContext.CalcWorkBufferSize(behaviorInfo, parameters) + 0x30 * parameters.EffectCount + (4 * parameters.VoiceCount) + 0x8F) & ~0x3FL) +
- ((parameters.VoiceCount << 8) | 0x40);
-
- if (parameters.PerformanceManagerCount >= 1)
- {
- size += (PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(behaviorInfo, parameters) *
- (parameters.PerformanceManagerCount + 1) + 0xFF) & ~0x3FL;
- }
-
- if (behaviorInfo.IsVariadicCommandBufferSizeSupported())
- {
- size += CommandGenerator.CalculateCommandBufferSize(parameters) + 0x7E;
- }
- else
- {
- size += 0x1807E;
- }
-
- size = BitUtils.AlignUp(size, 0x1000);
-
- context.ResponseData.Write(size);
-
- Logger.Debug?.Print(LogClass.ServiceAudio, $"WorkBufferSize is 0x{size:x16}.");
-
- return ResultCode.Success;
- }
- else
- {
- context.ResponseData.Write(0L);
-
- Logger.Warning?.Print(LogClass.ServiceAudio, $"Library Revision REV{AudioRendererCommon.GetRevisionVersion(parameters.Revision)} is not supported!");
-
- return ResultCode.UnsupportedRevision;
- }
- }
-
- private AudioRendererParameter GetAudioRendererParameter(ServiceCtx context)
- {
- AudioRendererParameter Params = new AudioRendererParameter
- {
- SampleRate = context.RequestData.ReadInt32(),
- SampleCount = context.RequestData.ReadInt32(),
- MixBufferCount = context.RequestData.ReadInt32(),
- SubMixCount = context.RequestData.ReadInt32(),
- VoiceCount = context.RequestData.ReadInt32(),
- SinkCount = context.RequestData.ReadInt32(),
- EffectCount = context.RequestData.ReadInt32(),
- PerformanceManagerCount = context.RequestData.ReadInt32(),
- VoiceDropEnable = context.RequestData.ReadInt32(),
- SplitterCount = context.RequestData.ReadInt32(),
- SplitterDestinationDataCount = context.RequestData.ReadInt32(),
- Unknown2C = context.RequestData.ReadInt32(),
- Revision = context.RequestData.ReadInt32()
- };
-
- return Params;
- }
-
- [Command(2)]
- // GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object<nn::audio::detail::IAudioDevice>
- public ResultCode GetAudioDeviceService(ServiceCtx context)
- {
- long appletResourceUserId = context.RequestData.ReadInt64();
-
- MakeObject(context, new IAudioDevice(context.Device.System));
-
- return ResultCode.Success;
- }
-
- [Command(4)] // 4.0.0+
- // GetAudioDeviceServiceWithRevisionInfo(u32 revision_info, nn::applet::AppletResourceUserId) -> object<nn::audio::detail::IAudioDevice>
- public ResultCode GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context)
- {
- int revisionInfo = context.RequestData.ReadInt32();
- long appletResourceUserId = context.RequestData.ReadInt64();
-
- Logger.Stub?.PrintStub(LogClass.ServiceAudio, new { appletResourceUserId, revisionInfo });
-
- return GetAudioDeviceService(context);
- }
+ ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter);
}
}