From c20f3fbebdfec9ed5b0022fbec7fbe3269ffad88 Mon Sep 17 00:00:00 2001 From: Mary-nyan Date: Wed, 28 Dec 2022 23:34:30 +0100 Subject: haydn: Add support for PCMFloat, PCM32 and PCM8 conversions (#4100) * haydn: Add support for PCMFloat, PCM32 and PCM8 conversions This adds support in the compatibility layer for other sample format than PCM16. This should help extends compatibility with soundio on devices that doesn't expose PCM16. I ommited PCM24 conversion for now as it's not simplest of all. * Address TSRBerry's comment * Address comments * Fix conversion issue and clean up saturation usage * Revert saturation changes * Address gdkchan's comment --- .../CompatLayerHardwareDeviceSession.cs | 86 +++++++++++++++------- 1 file changed, 61 insertions(+), 25 deletions(-) (limited to 'Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs') 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 samples = MemoryMarshal.Cast(buffer.Data); + byte[] convertedSamples = new byte[BackendHelper.GetSampleSize(realSampleFormat) * userSampleCount]; + + switch (realSampleFormat) + { + case SampleFormat.PcmInt8: + PcmHelper.Convert(MemoryMarshal.Cast(convertedSamples), samples); + break; + case SampleFormat.PcmInt32: + PcmHelper.Convert(MemoryMarshal.Cast(convertedSamples), samples); + break; + case SampleFormat.PcmFloat: + PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast(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 samplesPCM16 = MemoryMarshal.Cast(samples); + ReadOnlySpan samplesPCM16 = MemoryMarshal.Cast(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(downmixedBufferPCM16).ToArray(); + samples = MemoryMarshal.Cast(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) { -- cgit v1.2.3