diff options
Diffstat (limited to 'Ryujinx.Audio/Backends')
| -rw-r--r-- | Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs | 51 | ||||
| -rw-r--r-- | Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs | 86 |
2 files changed, 109 insertions, 28 deletions
diff --git a/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs b/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs index b6f45a3e..fbdfe18f 100644 --- a/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs +++ b/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs @@ -51,6 +51,40 @@ namespace Ryujinx.Audio.Backends.CompatLayer }; } + private SampleFormat SelectHardwareSampleFormat(SampleFormat targetSampleFormat) + { + if (_realDriver.SupportsSampleFormat(targetSampleFormat)) + { + return targetSampleFormat; + } + + // Attempt conversion from PCM16. + if (targetSampleFormat == SampleFormat.PcmInt16) + { + // Prefer PCM32 if we need to convert. + if (_realDriver.SupportsSampleFormat(SampleFormat.PcmInt32)) + { + return SampleFormat.PcmInt32; + } + + // If not supported, PCM float provides the best quality with a cost lower than PCM24. + if (_realDriver.SupportsSampleFormat(SampleFormat.PcmFloat)) + { + return SampleFormat.PcmFloat; + } + + // TODO: Implement PCM24 conversion. + + // If nothing is truly supported, attempt PCM8 at the cost of loosing quality. + if (_realDriver.SupportsSampleFormat(SampleFormat.PcmInt8)) + { + return SampleFormat.PcmInt8; + } + } + + throw new ArgumentException("No valid sample format configuration found!"); + } + public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume) { if (channelCount == 0) @@ -77,15 +111,26 @@ namespace Ryujinx.Audio.Backends.CompatLayer throw new NotImplementedException(); } + SampleFormat hardwareSampleFormat = SelectHardwareSampleFormat(sampleFormat); uint hardwareChannelCount = SelectHardwareChannelCount(channelCount); - IHardwareDeviceSession realSession = _realDriver.OpenDeviceSession(direction, memoryManager, sampleFormat, sampleRate, hardwareChannelCount, volume); + IHardwareDeviceSession realSession = _realDriver.OpenDeviceSession(direction, memoryManager, hardwareSampleFormat, sampleRate, hardwareChannelCount, volume); - if (hardwareChannelCount == channelCount) + if (hardwareChannelCount == channelCount && hardwareSampleFormat == sampleFormat) { return realSession; } + if (hardwareSampleFormat != sampleFormat) + { + Logger.Warning?.Print(LogClass.Audio, $"{sampleFormat} isn't supported by the audio device, conversion to {hardwareSampleFormat} will happen."); + + if (hardwareSampleFormat < sampleFormat) + { + Logger.Warning?.Print(LogClass.Audio, $"{hardwareSampleFormat} has lower quality than {sampleFormat}, expect some loss in audio fidelity."); + } + } + if (direction == Direction.Input) { Logger.Warning?.Print(LogClass.Audio, $"The selected audio backend doesn't support the requested audio input configuration, fallback to dummy..."); @@ -103,7 +148,7 @@ namespace Ryujinx.Audio.Backends.CompatLayer } // If we need to do post processing before sending to the hardware device, wrap around it. - return new CompatLayerHardwareDeviceSession(realSessionOutputBase, channelCount); + return new CompatLayerHardwareDeviceSession(realSessionOutputBase, sampleFormat, channelCount); } public bool SupportsChannelCount(uint channelCount) diff --git a/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs b/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs index ff3b0988..ca6090fe 100644 --- a/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs +++ b/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs @@ -1,5 +1,6 @@ using Ryujinx.Audio.Backends.Common; using Ryujinx.Audio.Common; +using Ryujinx.Audio.Renderer.Dsp; using System; using System.Runtime.InteropServices; @@ -8,11 +9,13 @@ namespace Ryujinx.Audio.Backends.CompatLayer class CompatLayerHardwareDeviceSession : HardwareDeviceSessionOutputBase { private HardwareDeviceSessionOutputBase _realSession; + private SampleFormat _userSampleFormat; private uint _userChannelCount; - public CompatLayerHardwareDeviceSession(HardwareDeviceSessionOutputBase realSession, uint userChannelCount) : base(realSession.MemoryManager, realSession.RequestedSampleFormat, realSession.RequestedSampleRate, userChannelCount) + public CompatLayerHardwareDeviceSession(HardwareDeviceSessionOutputBase realSession, SampleFormat userSampleFormat, uint userChannelCount) : base(realSession.MemoryManager, realSession.RequestedSampleFormat, realSession.RequestedSampleRate, userChannelCount) { _realSession = realSession; + _userSampleFormat = userSampleFormat; _userChannelCount = userChannelCount; } @@ -38,53 +41,86 @@ namespace Ryujinx.Audio.Backends.CompatLayer public override void QueueBuffer(AudioBuffer buffer) { + SampleFormat realSampleFormat = _realSession.RequestedSampleFormat; + + if (_userSampleFormat != realSampleFormat) + { + if (_userSampleFormat != SampleFormat.PcmInt16) + { + throw new NotImplementedException("Converting formats other than PCM16 is not supported."); + } + + int userSampleCount = buffer.Data.Length / BackendHelper.GetSampleSize(_userSampleFormat); + + ReadOnlySpan<short> samples = MemoryMarshal.Cast<byte, short>(buffer.Data); + byte[] convertedSamples = new byte[BackendHelper.GetSampleSize(realSampleFormat) * userSampleCount]; + + switch (realSampleFormat) + { + case SampleFormat.PcmInt8: + PcmHelper.Convert(MemoryMarshal.Cast<byte, sbyte>(convertedSamples), samples); + break; + case SampleFormat.PcmInt32: + PcmHelper.Convert(MemoryMarshal.Cast<byte, int>(convertedSamples), samples); + break; + case SampleFormat.PcmFloat: + PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(convertedSamples), samples); + break; + default: + throw new NotImplementedException($"Sample format conversion from {_userSampleFormat} to {realSampleFormat} not implemented."); + } + + buffer.Data = convertedSamples; + } + _realSession.QueueBuffer(buffer); } public override bool RegisterBuffer(AudioBuffer buffer, byte[] samples) { - if (RequestedSampleFormat != SampleFormat.PcmInt16) - { - throw new NotImplementedException("Downmixing formats other than PCM16 is not supported."); - } - if (samples == null) { return false; } - short[] downmixedBufferPCM16; + if (_userChannelCount != _realSession.RequestedChannelCount) + { + if (_userSampleFormat != SampleFormat.PcmInt16) + { + throw new NotImplementedException("Downmixing formats other than PCM16 is not supported."); + } - ReadOnlySpan<short> samplesPCM16 = MemoryMarshal.Cast<byte, short>(samples); + ReadOnlySpan<short> samplesPCM16 = MemoryMarshal.Cast<byte, short>(samples); - if (_userChannelCount == 6) - { - downmixedBufferPCM16 = Downmixing.DownMixSurroundToStereo(samplesPCM16); + if (_userChannelCount == 6) + { + samplesPCM16 = Downmixing.DownMixSurroundToStereo(samplesPCM16); - if (_realSession.RequestedChannelCount == 1) + if (_realSession.RequestedChannelCount == 1) + { + samplesPCM16 = Downmixing.DownMixStereoToMono(samplesPCM16); + } + } + else if (_userChannelCount == 2 && _realSession.RequestedChannelCount == 1) { - downmixedBufferPCM16 = Downmixing.DownMixStereoToMono(downmixedBufferPCM16); + samplesPCM16 = Downmixing.DownMixStereoToMono(samplesPCM16); + } + else + { + throw new NotImplementedException($"Downmixing from {_userChannelCount} to {_realSession.RequestedChannelCount} not implemented."); } - } - else if (_userChannelCount == 2 && _realSession.RequestedChannelCount == 1) - { - downmixedBufferPCM16 = Downmixing.DownMixStereoToMono(samplesPCM16); - } - else - { - throw new NotImplementedException($"Downmixing from {_userChannelCount} to {_realSession.RequestedChannelCount} not implemented."); - } - byte[] downmixedBuffer = MemoryMarshal.Cast<short, byte>(downmixedBufferPCM16).ToArray(); + samples = MemoryMarshal.Cast<short, byte>(samplesPCM16).ToArray(); + } AudioBuffer fakeBuffer = new AudioBuffer { BufferTag = buffer.BufferTag, DataPointer = buffer.DataPointer, - DataSize = (ulong)downmixedBuffer.Length + DataSize = (ulong)samples.Length }; - bool result = _realSession.RegisterBuffer(fakeBuffer, downmixedBuffer); + bool result = _realSession.RegisterBuffer(fakeBuffer, samples); if (result) { |
