aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Audio
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-07-14 23:57:41 -0300
committerGitHub <noreply@github.com>2018-07-14 23:57:41 -0300
commit98c6ceede564eda4aed528e51219a9b0d6bea1c4 (patch)
tree2fabe99e761098b6cafb49fb0ab4e90f6f9ef106 /Ryujinx.Audio
parentbe31f5b46d16f0f8730d9a9ec71f938eee97524a (diff)
Audio Renderer improvements (#210)
* Partial voice implementation on audio renderer * Implemented audren resampler (based on original impl) * Fix BiquadFilter struct * Pause audio playback on last stream buffer * Split audren/audout files into separate folders, some minor cleanup * Use AudioRendererParameter on GetWorkBufferSize aswell * Bump audren version to REV4, name a few things, increase sample buffer size * Remove useless new lines
Diffstat (limited to 'Ryujinx.Audio')
-rw-r--r--Ryujinx.Audio/Adpcm/AdpcmDecoder.cs91
-rw-r--r--Ryujinx.Audio/Adpcm/AdpcmDecoderContext.cs10
-rw-r--r--Ryujinx.Audio/AudioFormat.cs13
-rw-r--r--Ryujinx.Audio/DspUtils.cs16
-rw-r--r--Ryujinx.Audio/IAalOutput.cs8
-rw-r--r--Ryujinx.Audio/OpenAL/OpenALAudioOut.cs53
6 files changed, 132 insertions, 59 deletions
diff --git a/Ryujinx.Audio/Adpcm/AdpcmDecoder.cs b/Ryujinx.Audio/Adpcm/AdpcmDecoder.cs
new file mode 100644
index 00000000..24455b41
--- /dev/null
+++ b/Ryujinx.Audio/Adpcm/AdpcmDecoder.cs
@@ -0,0 +1,91 @@
+namespace Ryujinx.Audio.Adpcm
+{
+ public static class AdpcmDecoder
+ {
+ private const int SamplesPerFrame = 14;
+ private const int BytesPerFrame = 8;
+
+ public static int[] Decode(byte[] Buffer, AdpcmDecoderContext Context)
+ {
+ int Samples = GetSamplesCountFromSize(Buffer.Length);
+
+ int[] Pcm = new int[Samples * 2];
+
+ short History0 = Context.History0;
+ short History1 = Context.History1;
+
+ int InputOffset = 0;
+ int OutputOffset = 0;
+
+ while (InputOffset < Buffer.Length)
+ {
+ byte Header = Buffer[InputOffset++];
+
+ int Scale = 0x800 << (Header & 0xf);
+
+ int CoeffIndex = (Header >> 4) & 7;
+
+ short Coeff0 = Context.Coefficients[CoeffIndex * 2 + 0];
+ short Coeff1 = Context.Coefficients[CoeffIndex * 2 + 1];
+
+ int FrameSamples = SamplesPerFrame;
+
+ if (FrameSamples > Samples)
+ {
+ FrameSamples = Samples;
+ }
+
+ int Value = 0;
+
+ for (int SampleIndex = 0; SampleIndex < FrameSamples; SampleIndex++)
+ {
+ int Sample;
+
+ if ((SampleIndex & 1) == 0)
+ {
+ Value = Buffer[InputOffset++];
+
+ Sample = (Value << 24) >> 28;
+ }
+ else
+ {
+ Sample = (Value << 28) >> 28;
+ }
+
+ int Prediction = Coeff0 * History0 + Coeff1 * History1;
+
+ Sample = (Sample * Scale + Prediction + 0x400) >> 11;
+
+ short SaturatedSample = DspUtils.Saturate(Sample);
+
+ History1 = History0;
+ History0 = SaturatedSample;
+
+ Pcm[OutputOffset++] = SaturatedSample;
+ Pcm[OutputOffset++] = SaturatedSample;
+ }
+
+ Samples -= FrameSamples;
+ }
+
+ Context.History0 = History0;
+ Context.History1 = History1;
+
+ return Pcm;
+ }
+
+ public static long GetSizeFromSamplesCount(int SamplesCount)
+ {
+ int Frames = SamplesCount / SamplesPerFrame;
+
+ return Frames * BytesPerFrame;
+ }
+
+ public static int GetSamplesCountFromSize(long Size)
+ {
+ int Frames = (int)(Size / BytesPerFrame);
+
+ return Frames * SamplesPerFrame;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio/Adpcm/AdpcmDecoderContext.cs b/Ryujinx.Audio/Adpcm/AdpcmDecoderContext.cs
new file mode 100644
index 00000000..91730333
--- /dev/null
+++ b/Ryujinx.Audio/Adpcm/AdpcmDecoderContext.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Audio.Adpcm
+{
+ public class AdpcmDecoderContext
+ {
+ public short[] Coefficients;
+
+ public short History0;
+ public short History1;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio/AudioFormat.cs b/Ryujinx.Audio/AudioFormat.cs
deleted file mode 100644
index 8250d136..00000000
--- a/Ryujinx.Audio/AudioFormat.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Ryujinx.Audio
-{
- public enum AudioFormat
- {
- Invalid = 0,
- PcmInt8 = 1,
- PcmInt16 = 2,
- PcmImt24 = 3,
- PcmImt32 = 4,
- PcmFloat = 5,
- Adpcm = 6
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Audio/DspUtils.cs b/Ryujinx.Audio/DspUtils.cs
new file mode 100644
index 00000000..c048161d
--- /dev/null
+++ b/Ryujinx.Audio/DspUtils.cs
@@ -0,0 +1,16 @@
+namespace Ryujinx.Audio.Adpcm
+{
+ public static class DspUtils
+ {
+ public static short Saturate(int Value)
+ {
+ if (Value > short.MaxValue)
+ Value = short.MaxValue;
+
+ if (Value < short.MinValue)
+ Value = short.MinValue;
+
+ return (short)Value;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio/IAalOutput.cs b/Ryujinx.Audio/IAalOutput.cs
index f9978ee4..e903c5c5 100644
--- a/Ryujinx.Audio/IAalOutput.cs
+++ b/Ryujinx.Audio/IAalOutput.cs
@@ -2,11 +2,7 @@ namespace Ryujinx.Audio
{
public interface IAalOutput
{
- int OpenTrack(
- int SampleRate,
- int Channels,
- ReleaseCallback Callback,
- out AudioFormat Format);
+ int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback);
void CloseTrack(int Track);
@@ -14,7 +10,7 @@ namespace Ryujinx.Audio
long[] GetReleasedBuffers(int Track, int MaxCount);
- void AppendBuffer(int Track, long Tag, byte[] Buffer);
+ void AppendBuffer<T>(int Track, long Tag, T[] Buffer) where T : struct;
void Start(int Track);
void Stop(int Track);
diff --git a/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs b/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs
index 2860dc2e..1dd63202 100644
--- a/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs
+++ b/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs
@@ -3,6 +3,7 @@ using OpenTK.Audio.OpenAL;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Runtime.InteropServices;
using System.Threading;
namespace Ryujinx.Audio.OpenAL
@@ -226,15 +227,9 @@ namespace Ryujinx.Audio.OpenAL
while (KeepPolling);
}
- public int OpenTrack(
- int SampleRate,
- int Channels,
- ReleaseCallback Callback,
- out AudioFormat Format)
+ public int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback)
{
- Format = AudioFormat.PcmInt16;
-
- Track Td = new Track(SampleRate, GetALFormat(Channels, Format), Callback);
+ Track Td = new Track(SampleRate, GetALFormat(Channels), Callback);
for (int Id = 0; Id < MaxTracks; Id++)
{
@@ -247,38 +242,16 @@ namespace Ryujinx.Audio.OpenAL
return -1;
}
- private ALFormat GetALFormat(int Channels, AudioFormat Format)
+ private ALFormat GetALFormat(int Channels)
{
- if (Channels == 1)
- {
- switch (Format)
- {
- case AudioFormat.PcmInt8: return ALFormat.Mono8;
- case AudioFormat.PcmInt16: return ALFormat.Mono16;
- }
- }
- else if (Channels == 2)
- {
- switch (Format)
- {
- case AudioFormat.PcmInt8: return ALFormat.Stereo8;
- case AudioFormat.PcmInt16: return ALFormat.Stereo16;
- }
- }
- else if (Channels == 6)
- {
- switch (Format)
- {
- case AudioFormat.PcmInt8: return ALFormat.Multi51Chn8Ext;
- case AudioFormat.PcmInt16: return ALFormat.Multi51Chn16Ext;
- }
- }
- else
+ switch (Channels)
{
- throw new ArgumentOutOfRangeException(nameof(Channels));
+ case 1: return ALFormat.Mono16;
+ case 2: return ALFormat.Stereo16;
+ case 6: return ALFormat.Multi51Chn16Ext;
}
- throw new ArgumentException(nameof(Format));
+ throw new ArgumentOutOfRangeException(nameof(Channels));
}
public void CloseTrack(int Track)
@@ -309,13 +282,15 @@ namespace Ryujinx.Audio.OpenAL
return null;
}
- public void AppendBuffer(int Track, long Tag, byte[] Buffer)
+ public void AppendBuffer<T>(int Track, long Tag, T[] Buffer) where T : struct
{
if (Tracks.TryGetValue(Track, out Track Td))
{
int BufferId = Td.AppendBuffer(Tag);
- AL.BufferData(BufferId, Td.Format, Buffer, Buffer.Length, Td.SampleRate);
+ int Size = Buffer.Length * Marshal.SizeOf<T>();
+
+ AL.BufferData<T>(BufferId, Td.Format, Buffer, Size, Td.SampleRate);
AL.SourceQueueBuffer(Td.SourceId, BufferId);
@@ -366,7 +341,5 @@ namespace Ryujinx.Audio.OpenAL
return PlaybackState.Stopped;
}
-
-
}
} \ No newline at end of file