diff options
Diffstat (limited to 'Ryujinx.Audio/Renderers/SoundIo')
| -rw-r--r-- | Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioOut.cs | 12 | ||||
| -rw-r--r-- | Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs | 76 |
2 files changed, 73 insertions, 15 deletions
diff --git a/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioOut.cs b/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioOut.cs index 1e487a6d..fa3961e4 100644 --- a/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioOut.cs +++ b/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioOut.cs @@ -65,14 +65,20 @@ namespace Ryujinx.Audio _trackPool = new SoundIoAudioTrackPool(_audioContext, _audioDevice, MaximumTracks); } + public bool SupportsChannelCount(int channels) + { + return _audioDevice.SupportsChannelCount(channels); + } + /// <summary> /// Creates a new audio track with the specified parameters /// </summary> /// <param name="sampleRate">The requested sample rate</param> - /// <param name="channels">The requested channels</param> + /// <param name="hardwareChannels">The requested hardware channels</param> + /// <param name="virtualChannels">The requested virtual channels</param> /// <param name="callback">A <see cref="ReleaseCallback" /> that represents the delegate to invoke when a buffer has been released by the audio track</param> /// <returns>The created track's Track ID</returns> - public int OpenTrack(int sampleRate, int channels, ReleaseCallback callback) + public int OpenHardwareTrack(int sampleRate, int hardwareChannels, int virtualChannels, ReleaseCallback callback) { if (!_trackPool.TryGet(out SoundIoAudioTrack track)) { @@ -80,7 +86,7 @@ namespace Ryujinx.Audio } // Open the output. We currently only support 16-bit signed LE - track.Open(sampleRate, channels, callback, SoundIOFormat.S16LE); + track.Open(sampleRate, hardwareChannels, virtualChannels, callback, SoundIOFormat.S16LE); return track.TrackID; } diff --git a/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs b/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs index 97ba11d5..6fdeb991 100644 --- a/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs +++ b/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Concurrent; using System.Linq; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Ryujinx.Audio.SoundIo { @@ -53,6 +54,9 @@ namespace Ryujinx.Audio.SoundIo /// </summary> public ConcurrentQueue<long> ReleasedBuffers { get; private set; } + private int _hardwareChannels; + private int _virtualChannels; + /// <summary> /// Constructs a new instance of a <see cref="SoundIoAudioTrack"/> /// </summary> @@ -75,12 +79,14 @@ namespace Ryujinx.Audio.SoundIo /// Opens the audio track with the specified parameters /// </summary> /// <param name="sampleRate">The requested sample rate of the track</param> - /// <param name="channelCount">The requested channel count of the track</param> + /// <param name="hardwareChannels">The requested hardware channels</param> + /// <param name="virtualChannels">The requested virtual channels</param> /// <param name="callback">A <see cref="ReleaseCallback" /> that represents the delegate to invoke when a buffer has been released by the audio track</param> /// <param name="format">The requested sample format of the track</param> public void Open( int sampleRate, - int channelCount, + int hardwareChannels, + int virtualChannels, ReleaseCallback callback, SoundIOFormat format = SoundIOFormat.S16LE) { @@ -100,10 +106,18 @@ namespace Ryujinx.Audio.SoundIo throw new InvalidOperationException($"This sound device does not support SoundIOFormat.{Enum.GetName(typeof(SoundIOFormat), format)}"); } + if (!AudioDevice.SupportsChannelCount(hardwareChannels)) + { + throw new InvalidOperationException($"This sound device does not support channel count {hardwareChannels}"); + } + + _hardwareChannels = hardwareChannels; + _virtualChannels = virtualChannels; + AudioStream = AudioDevice.CreateOutStream(); AudioStream.Name = $"SwitchAudioTrack_{TrackID}"; - AudioStream.Layout = SoundIOChannelLayout.GetDefault(channelCount); + AudioStream.Layout = SoundIOChannelLayout.GetDefault(hardwareChannels); AudioStream.Format = format; AudioStream.SampleRate = sampleRate; @@ -490,24 +504,62 @@ namespace Ryujinx.Audio.SoundIo /// <typeparam name="T">The audio sample type</typeparam> /// <param name="bufferTag">The unqiue tag of the buffer being appended</param> /// <param name="buffer">The buffer to append</param> - public void AppendBuffer<T>(long bufferTag, T[] buffer) + public void AppendBuffer<T>(long bufferTag, T[] buffer) where T: struct { if (AudioStream == null) { return; } - // Calculate the size of the audio samples - int size = Unsafe.SizeOf<T>(); + int sampleSize = Unsafe.SizeOf<T>(); + int targetSize = sampleSize * buffer.Length; + + // Do we need to downmix? + if (_hardwareChannels != _virtualChannels) + { + if (sampleSize != sizeof(short)) + { + throw new NotImplementedException("Downmixing formats other than PCM16 is not supported!"); + } + + short[] downmixedBuffer; + + ReadOnlySpan<short> bufferPCM16 = MemoryMarshal.Cast<T, short>(buffer); + + if (_virtualChannels == 6) + { + downmixedBuffer = Downmixing.DownMixSurroundToStereo(bufferPCM16); + + if (_hardwareChannels == 1) + { + downmixedBuffer = Downmixing.DownMixStereoToMono(downmixedBuffer); + } + } + else if (_virtualChannels == 2) + { + downmixedBuffer = Downmixing.DownMixStereoToMono(bufferPCM16); + } + else + { + throw new NotImplementedException($"Downmixing from {_virtualChannels} to {_hardwareChannels} not implemented!"); + } + + targetSize = sampleSize * downmixedBuffer.Length; - // Calculate the amount of bytes to copy from the buffer - int bytesToCopy = size * buffer.Length; + // Copy the memory to our ring buffer + m_Buffer.Write(downmixedBuffer, 0, targetSize); - // Copy the memory to our ring buffer - m_Buffer.Write(buffer, 0, bytesToCopy); + // Keep track of "buffered" buffers + m_ReservedBuffers.Enqueue(new SoundIoBuffer(bufferTag, targetSize)); + } + else + { + // Copy the memory to our ring buffer + m_Buffer.Write(buffer, 0, targetSize); - // Keep track of "buffered" buffers - m_ReservedBuffers.Enqueue(new SoundIoBuffer(bufferTag, bytesToCopy)); + // Keep track of "buffered" buffers + m_ReservedBuffers.Enqueue(new SoundIoBuffer(bufferTag, targetSize)); + } } /// <summary> |
