aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs
diff options
context:
space:
mode:
authorMary <me@thog.eu>2020-08-18 21:03:55 +0200
committerGitHub <noreply@github.com>2020-08-18 21:03:55 +0200
commit5b26e4ef94afca8450f07c42393180e3c97f9c00 (patch)
tree5c698591bd557711a487430ba06921b10ce53761 /Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs
parenta389dd59bd881cf2cff09a1f67f5c30de61123e6 (diff)
Misc audio fixes (#1348)
Changes: Implement software surround downmixing (fix #796). Fix a crash when no audio renderer were created when stopping emulation. NOTE: This PR also disable support of 5.1 surround on the OpenAL backend as we cannot detect if the hardware directly support it. (the downmixing applied by OpenAL on Windows is terribly slow)
Diffstat (limited to 'Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs')
-rw-r--r--Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs76
1 files changed, 64 insertions, 12 deletions
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>