Implemented audren resampler (based on original impl)
This commit is contained in:
parent
d77c77f3b9
commit
6a6aa21ec9
5 changed files with 290 additions and 82 deletions
|
@ -5,11 +5,11 @@ namespace Ryujinx.Audio.Adpcm
|
|||
private const int SamplesPerFrame = 14;
|
||||
private const int BytesPerFrame = 8;
|
||||
|
||||
public static short[] Decode(byte[] Buffer, AdpcmDecoderContext Context)
|
||||
public static int[] Decode(byte[] Buffer, AdpcmDecoderContext Context)
|
||||
{
|
||||
int Samples = GetSamplesCountFromSize(Buffer.Length);
|
||||
|
||||
short[] Pcm = new short[Samples * 2];
|
||||
int[] Pcm = new int[Samples * 2];
|
||||
|
||||
short History0 = Context.History0;
|
||||
short History1 = Context.History1;
|
||||
|
@ -23,7 +23,7 @@ namespace Ryujinx.Audio.Adpcm
|
|||
|
||||
int Scale = 0x800 << (Header & 0xf);
|
||||
|
||||
int CoeffIndex = Header >> 4;
|
||||
int CoeffIndex = (Header >> 4) & 7;
|
||||
|
||||
short Coeff0 = Context.Coefficients[CoeffIndex * 2 + 0];
|
||||
short Coeff1 = Context.Coefficients[CoeffIndex * 2 + 1];
|
||||
|
|
8
Ryujinx.HLE/OsHle/Services/Aud/AudioConsts.cs
Normal file
8
Ryujinx.HLE/OsHle/Services/Aud/AudioConsts.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.OsHle.Services.Aud
|
||||
{
|
||||
static class AudioConsts
|
||||
{
|
||||
public const int HostSampleRate = 48000;
|
||||
public const int HostChannelsCount = 2;
|
||||
}
|
||||
}
|
|
@ -13,15 +13,11 @@ namespace Ryujinx.HLE.OsHle.Services.Aud
|
|||
{
|
||||
class IAudioRenderer : IpcService, IDisposable
|
||||
{
|
||||
private const int DeviceChannelsCount = 2;
|
||||
|
||||
//This is the amount of samples that are going to be appended
|
||||
//each time that RequestUpdateAudioRenderer is called. Ideally,
|
||||
//this value shouldn't be neither too small (to avoid the player
|
||||
//starving due to running out of samples) or too large (to avoid
|
||||
//high latency).
|
||||
//Additionally, due to ADPCM having 14 samples per frame, this value
|
||||
//needs to be a multiple of 14.
|
||||
private const int MixBufferSamplesCount = 770;
|
||||
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
@ -58,7 +54,10 @@ namespace Ryujinx.HLE.OsHle.Services.Aud
|
|||
this.AudioOut = AudioOut;
|
||||
this.Params = Params;
|
||||
|
||||
Track = AudioOut.OpenTrack(48000, 2, AudioCallback, out _);
|
||||
Track = AudioOut.OpenTrack(
|
||||
AudioConsts.HostSampleRate,
|
||||
AudioConsts.HostChannelsCount,
|
||||
AudioCallback, out _);
|
||||
|
||||
MemoryPools = CreateArray<MemoryPoolContext>(Params.EffectCount + Params.VoiceCount * 4);
|
||||
|
||||
|
@ -133,7 +132,9 @@ namespace Ryujinx.HLE.OsHle.Services.Aud
|
|||
{
|
||||
VoiceIn Voice = VoicesIn[Index];
|
||||
|
||||
Voices[Index].SetAcquireState(Voice.Acquired != 0);
|
||||
VoiceContext VoiceCtx = Voices[Index];
|
||||
|
||||
VoiceCtx.SetAcquireState(Voice.Acquired != 0);
|
||||
|
||||
if (Voice.Acquired == 0)
|
||||
{
|
||||
|
@ -142,21 +143,23 @@ namespace Ryujinx.HLE.OsHle.Services.Aud
|
|||
|
||||
if (Voice.FirstUpdate != 0)
|
||||
{
|
||||
Voices[Index].AdpcmCtx = GetAdpcmDecoderContext(
|
||||
VoiceCtx.AdpcmCtx = GetAdpcmDecoderContext(
|
||||
Voice.AdpcmCoeffsPosition,
|
||||
Voice.AdpcmCoeffsSize);
|
||||
|
||||
Voices[Index].SampleFormat = Voice.SampleFormat;
|
||||
Voices[Index].ChannelsCount = Voice.ChannelsCount;
|
||||
Voices[Index].BufferIndex = Voice.BaseWaveBufferIndex;
|
||||
VoiceCtx.SampleFormat = Voice.SampleFormat;
|
||||
VoiceCtx.SampleRate = Voice.SampleRate;
|
||||
VoiceCtx.ChannelsCount = Voice.ChannelsCount;
|
||||
|
||||
VoiceCtx.SetBufferIndex(Voice.BaseWaveBufferIndex);
|
||||
}
|
||||
|
||||
Voices[Index].WaveBuffers[0] = Voice.WaveBuffer0;
|
||||
Voices[Index].WaveBuffers[1] = Voice.WaveBuffer1;
|
||||
Voices[Index].WaveBuffers[2] = Voice.WaveBuffer2;
|
||||
Voices[Index].WaveBuffers[3] = Voice.WaveBuffer3;
|
||||
Voices[Index].Volume = Voice.Volume;
|
||||
Voices[Index].PlayState = Voice.PlayState;
|
||||
VoiceCtx.WaveBuffers[0] = Voice.WaveBuffer0;
|
||||
VoiceCtx.WaveBuffers[1] = Voice.WaveBuffer1;
|
||||
VoiceCtx.WaveBuffers[2] = Voice.WaveBuffer2;
|
||||
VoiceCtx.WaveBuffers[3] = Voice.WaveBuffer3;
|
||||
VoiceCtx.Volume = Voice.Volume;
|
||||
VoiceCtx.PlayState = Voice.PlayState;
|
||||
}
|
||||
|
||||
UpdateAudio();
|
||||
|
@ -249,7 +252,7 @@ namespace Ryujinx.HLE.OsHle.Services.Aud
|
|||
|
||||
private void AppendMixedBuffer(long Tag)
|
||||
{
|
||||
int[] MixBuffer = new int[MixBufferSamplesCount * DeviceChannelsCount];
|
||||
int[] MixBuffer = new int[MixBufferSamplesCount * AudioConsts.HostChannelsCount];
|
||||
|
||||
foreach (VoiceContext Voice in Voices)
|
||||
{
|
||||
|
@ -264,7 +267,7 @@ namespace Ryujinx.HLE.OsHle.Services.Aud
|
|||
|
||||
while (PendingSamples > 0)
|
||||
{
|
||||
short[] Samples = Voice.GetBufferData(Memory, PendingSamples, out int ReturnedSamples);
|
||||
int[] Samples = Voice.GetBufferData(Memory, PendingSamples, out int ReturnedSamples);
|
||||
|
||||
if (ReturnedSamples == 0)
|
||||
{
|
||||
|
|
191
Ryujinx.HLE/OsHle/Services/Aud/Resampler.cs
Normal file
191
Ryujinx.HLE/OsHle/Services/Aud/Resampler.cs
Normal file
|
@ -0,0 +1,191 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.OsHle.Services.Aud
|
||||
{
|
||||
static class Resampler
|
||||
{
|
||||
#region "LookUp Tables"
|
||||
private static short[] CurveLut0 = new short[]
|
||||
{
|
||||
6600, 19426, 6722, 3, 6479, 19424, 6845, 9, 6359, 19419, 6968, 15, 6239, 19412, 7093, 22,
|
||||
6121, 19403, 7219, 28, 6004, 19391, 7345, 34, 5888, 19377, 7472, 41, 5773, 19361, 7600, 48,
|
||||
5659, 19342, 7728, 55, 5546, 19321, 7857, 62, 5434, 19298, 7987, 69, 5323, 19273, 8118, 77,
|
||||
5213, 19245, 8249, 84, 5104, 19215, 8381, 92, 4997, 19183, 8513, 101, 4890, 19148, 8646, 109,
|
||||
4785, 19112, 8780, 118, 4681, 19073, 8914, 127, 4579, 19031, 9048, 137, 4477, 18988, 9183, 147,
|
||||
4377, 18942, 9318, 157, 4277, 18895, 9454, 168, 4179, 18845, 9590, 179, 4083, 18793, 9726, 190,
|
||||
3987, 18738, 9863, 202, 3893, 18682, 10000, 215, 3800, 18624, 10137, 228, 3709, 18563, 10274, 241,
|
||||
3618, 18500, 10411, 255, 3529, 18436, 10549, 270, 3441, 18369, 10687, 285, 3355, 18300, 10824, 300,
|
||||
3269, 18230, 10962, 317, 3186, 18157, 11100, 334, 3103, 18082, 11238, 351, 3022, 18006, 11375, 369,
|
||||
2942, 17927, 11513, 388, 2863, 17847, 11650, 408, 2785, 17765, 11788, 428, 2709, 17681, 11925, 449,
|
||||
2635, 17595, 12062, 471, 2561, 17507, 12198, 494, 2489, 17418, 12334, 517, 2418, 17327, 12470, 541,
|
||||
2348, 17234, 12606, 566, 2280, 17140, 12741, 592, 2213, 17044, 12876, 619, 2147, 16946, 13010, 647,
|
||||
2083, 16846, 13144, 675, 2020, 16745, 13277, 704, 1958, 16643, 13409, 735, 1897, 16539, 13541, 766,
|
||||
1838, 16434, 13673, 798, 1780, 16327, 13803, 832, 1723, 16218, 13933, 866, 1667, 16109, 14062, 901,
|
||||
1613, 15998, 14191, 937, 1560, 15885, 14318, 975, 1508, 15772, 14445, 1013, 1457, 15657, 14571, 1052,
|
||||
1407, 15540, 14695, 1093, 1359, 15423, 14819, 1134, 1312, 15304, 14942, 1177, 1266, 15185, 15064, 1221,
|
||||
1221, 15064, 15185, 1266, 1177, 14942, 15304, 1312, 1134, 14819, 15423, 1359, 1093, 14695, 15540, 1407,
|
||||
1052, 14571, 15657, 1457, 1013, 14445, 15772, 1508, 975, 14318, 15885, 1560, 937, 14191, 15998, 1613,
|
||||
901, 14062, 16109, 1667, 866, 13933, 16218, 1723, 832, 13803, 16327, 1780, 798, 13673, 16434, 1838,
|
||||
766, 13541, 16539, 1897, 735, 13409, 16643, 1958, 704, 13277, 16745, 2020, 675, 13144, 16846, 2083,
|
||||
647, 13010, 16946, 2147, 619, 12876, 17044, 2213, 592, 12741, 17140, 2280, 566, 12606, 17234, 2348,
|
||||
541, 12470, 17327, 2418, 517, 12334, 17418, 2489, 494, 12198, 17507, 2561, 471, 12062, 17595, 2635,
|
||||
449, 11925, 17681, 2709, 428, 11788, 17765, 2785, 408, 11650, 17847, 2863, 388, 11513, 17927, 2942,
|
||||
369, 11375, 18006, 3022, 351, 11238, 18082, 3103, 334, 11100, 18157, 3186, 317, 10962, 18230, 3269,
|
||||
300, 10824, 18300, 3355, 285, 10687, 18369, 3441, 270, 10549, 18436, 3529, 255, 10411, 18500, 3618,
|
||||
241, 10274, 18563, 3709, 228, 10137, 18624, 3800, 215, 10000, 18682, 3893, 202, 9863, 18738, 3987,
|
||||
190, 9726, 18793, 4083, 179, 9590, 18845, 4179, 168, 9454, 18895, 4277, 157, 9318, 18942, 4377,
|
||||
147, 9183, 18988, 4477, 137, 9048, 19031, 4579, 127, 8914, 19073, 4681, 118, 8780, 19112, 4785,
|
||||
109, 8646, 19148, 4890, 101, 8513, 19183, 4997, 92, 8381, 19215, 5104, 84, 8249, 19245, 5213,
|
||||
77, 8118, 19273, 5323, 69, 7987, 19298, 5434, 62, 7857, 19321, 5546, 55, 7728, 19342, 5659,
|
||||
48, 7600, 19361, 5773, 41, 7472, 19377, 5888, 34, 7345, 19391, 6004, 28, 7219, 19403, 6121,
|
||||
22, 7093, 19412, 6239, 15, 6968, 19419, 6359, 9, 6845, 19424, 6479, 3, 6722, 19426, 6600
|
||||
};
|
||||
|
||||
private static short[] CurveLut1 = new short[]
|
||||
{
|
||||
-68, 32639, 69, -5, -200, 32630, 212, -15, -328, 32613, 359, -26, -450, 32586, 512, -36,
|
||||
-568, 32551, 669, -47, -680, 32507, 832, -58, -788, 32454, 1000, -69, -891, 32393, 1174, -80,
|
||||
-990, 32323, 1352, -92, -1084, 32244, 1536, -103, -1173, 32157, 1724, -115, -1258, 32061, 1919, -128,
|
||||
-1338, 31956, 2118, -140, -1414, 31844, 2322, -153, -1486, 31723, 2532, -167, -1554, 31593, 2747, -180,
|
||||
-1617, 31456, 2967, -194, -1676, 31310, 3192, -209, -1732, 31157, 3422, -224, -1783, 30995, 3657, -240,
|
||||
-1830, 30826, 3897, -256, -1874, 30649, 4143, -272, -1914, 30464, 4393, -289, -1951, 30272, 4648, -307,
|
||||
-1984, 30072, 4908, -325, -2014, 29866, 5172, -343, -2040, 29652, 5442, -362, -2063, 29431, 5716, -382,
|
||||
-2083, 29203, 5994, -403, -2100, 28968, 6277, -424, -2114, 28727, 6565, -445, -2125, 28480, 6857, -468,
|
||||
-2133, 28226, 7153, -490, -2139, 27966, 7453, -514, -2142, 27700, 7758, -538, -2142, 27428, 8066, -563,
|
||||
-2141, 27151, 8378, -588, -2136, 26867, 8694, -614, -2130, 26579, 9013, -641, -2121, 26285, 9336, -668,
|
||||
-2111, 25987, 9663, -696, -2098, 25683, 9993, -724, -2084, 25375, 10326, -753, -2067, 25063, 10662, -783,
|
||||
-2049, 24746, 11000, -813, -2030, 24425, 11342, -844, -2009, 24100, 11686, -875, -1986, 23771, 12033, -907,
|
||||
-1962, 23438, 12382, -939, -1937, 23103, 12733, -972, -1911, 22764, 13086, -1005, -1883, 22422, 13441, -1039,
|
||||
-1855, 22077, 13798, -1072, -1825, 21729, 14156, -1107, -1795, 21380, 14516, -1141, -1764, 21027, 14877, -1176,
|
||||
-1732, 20673, 15239, -1211, -1700, 20317, 15602, -1246, -1667, 19959, 15965, -1282, -1633, 19600, 16329, -1317,
|
||||
-1599, 19239, 16694, -1353, -1564, 18878, 17058, -1388, -1530, 18515, 17423, -1424, -1495, 18151, 17787, -1459,
|
||||
-1459, 17787, 18151, -1495, -1424, 17423, 18515, -1530, -1388, 17058, 18878, -1564, -1353, 16694, 19239, -1599,
|
||||
-1317, 16329, 19600, -1633, -1282, 15965, 19959, -1667, -1246, 15602, 20317, -1700, -1211, 15239, 20673, -1732,
|
||||
-1176, 14877, 21027, -1764, -1141, 14516, 21380, -1795, -1107, 14156, 21729, -1825, -1072, 13798, 22077, -1855,
|
||||
-1039, 13441, 22422, -1883, -1005, 13086, 22764, -1911, -972, 12733, 23103, -1937, -939, 12382, 23438, -1962,
|
||||
-907, 12033, 23771, -1986, -875, 11686, 24100, -2009, -844, 11342, 24425, -2030, -813, 11000, 24746, -2049,
|
||||
-783, 10662, 25063, -2067, -753, 10326, 25375, -2084, -724, 9993, 25683, -2098, -696, 9663, 25987, -2111,
|
||||
-668, 9336, 26285, -2121, -641, 9013, 26579, -2130, -614, 8694, 26867, -2136, -588, 8378, 27151, -2141,
|
||||
-563, 8066, 27428, -2142, -538, 7758, 27700, -2142, -514, 7453, 27966, -2139, -490, 7153, 28226, -2133,
|
||||
-468, 6857, 28480, -2125, -445, 6565, 28727, -2114, -424, 6277, 28968, -2100, -403, 5994, 29203, -2083,
|
||||
-382, 5716, 29431, -2063, -362, 5442, 29652, -2040, -343, 5172, 29866, -2014, -325, 4908, 30072, -1984,
|
||||
-307, 4648, 30272, -1951, -289, 4393, 30464, -1914, -272, 4143, 30649, -1874, -256, 3897, 30826, -1830,
|
||||
-240, 3657, 30995, -1783, -224, 3422, 31157, -1732, -209, 3192, 31310, -1676, -194, 2967, 31456, -1617,
|
||||
-180, 2747, 31593, -1554, -167, 2532, 31723, -1486, -153, 2322, 31844, -1414, -140, 2118, 31956, -1338,
|
||||
-128, 1919, 32061, -1258, -115, 1724, 32157, -1173, -103, 1536, 32244, -1084, -92, 1352, 32323, -990,
|
||||
-80, 1174, 32393, -891, -69, 1000, 32454, -788, -58, 832, 32507, -680, -47, 669, 32551, -568,
|
||||
-36, 512, 32586, -450, -26, 359, 32613, -328, -15, 212, 32630, -200, -5, 69, 32639, -68
|
||||
};
|
||||
|
||||
private static short[] CurveLut2 = new short[]
|
||||
{
|
||||
3195, 26287, 3329, -32, 3064, 26281, 3467, -34, 2936, 26270, 3608, -38, 2811, 26253, 3751, -42,
|
||||
2688, 26230, 3897, -46, 2568, 26202, 4046, -50, 2451, 26169, 4199, -54, 2338, 26130, 4354, -58,
|
||||
2227, 26085, 4512, -63, 2120, 26035, 4673, -67, 2015, 25980, 4837, -72, 1912, 25919, 5004, -76,
|
||||
1813, 25852, 5174, -81, 1716, 25780, 5347, -87, 1622, 25704, 5522, -92, 1531, 25621, 5701, -98,
|
||||
1442, 25533, 5882, -103, 1357, 25440, 6066, -109, 1274, 25342, 6253, -115, 1193, 25239, 6442, -121,
|
||||
1115, 25131, 6635, -127, 1040, 25018, 6830, -133, 967, 24899, 7027, -140, 897, 24776, 7227, -146,
|
||||
829, 24648, 7430, -153, 764, 24516, 7635, -159, 701, 24379, 7842, -166, 641, 24237, 8052, -174,
|
||||
583, 24091, 8264, -181, 526, 23940, 8478, -187, 472, 23785, 8695, -194, 420, 23626, 8914, -202,
|
||||
371, 23462, 9135, -209, 324, 23295, 9358, -215, 279, 23123, 9583, -222, 236, 22948, 9809, -230,
|
||||
194, 22769, 10038, -237, 154, 22586, 10269, -243, 117, 22399, 10501, -250, 81, 22208, 10735, -258,
|
||||
47, 22015, 10970, -265, 15, 21818, 11206, -271, -16, 21618, 11444, -277, -44, 21415, 11684, -283,
|
||||
-71, 21208, 11924, -290, -97, 20999, 12166, -296, -121, 20786, 12409, -302, -143, 20571, 12653, -306,
|
||||
-163, 20354, 12898, -311, -183, 20134, 13143, -316, -201, 19911, 13389, -321, -218, 19686, 13635, -325,
|
||||
-234, 19459, 13882, -328, -248, 19230, 14130, -332, -261, 18998, 14377, -335, -273, 18765, 14625, -337,
|
||||
-284, 18531, 14873, -339, -294, 18295, 15121, -341, -302, 18057, 15369, -341, -310, 17817, 15617, -341,
|
||||
-317, 17577, 15864, -340, -323, 17335, 16111, -340, -328, 17092, 16357, -338, -332, 16848, 16603, -336,
|
||||
-336, 16603, 16848, -332, -338, 16357, 17092, -328, -340, 16111, 17335, -323, -340, 15864, 17577, -317,
|
||||
-341, 15617, 17817, -310, -341, 15369, 18057, -302, -341, 15121, 18295, -294, -339, 14873, 18531, -284,
|
||||
-337, 14625, 18765, -273, -335, 14377, 18998, -261, -332, 14130, 19230, -248, -328, 13882, 19459, -234,
|
||||
-325, 13635, 19686, -218, -321, 13389, 19911, -201, -316, 13143, 20134, -183, -311, 12898, 20354, -163,
|
||||
-306, 12653, 20571, -143, -302, 12409, 20786, -121, -296, 12166, 20999, -97, -290, 11924, 21208, -71,
|
||||
-283, 11684, 21415, -44, -277, 11444, 21618, -16, -271, 11206, 21818, 15, -265, 10970, 22015, 47,
|
||||
-258, 10735, 22208, 81, -250, 10501, 22399, 117, -243, 10269, 22586, 154, -237, 10038, 22769, 194,
|
||||
-230, 9809, 22948, 236, -222, 9583, 23123, 279, -215, 9358, 23295, 324, -209, 9135, 23462, 371,
|
||||
-202, 8914, 23626, 420, -194, 8695, 23785, 472, -187, 8478, 23940, 526, -181, 8264, 24091, 583,
|
||||
-174, 8052, 24237, 641, -166, 7842, 24379, 701, -159, 7635, 24516, 764, -153, 7430, 24648, 829,
|
||||
-146, 7227, 24776, 897, -140, 7027, 24899, 967, -133, 6830, 25018, 1040, -127, 6635, 25131, 1115,
|
||||
-121, 6442, 25239, 1193, -115, 6253, 25342, 1274, -109, 6066, 25440, 1357, -103, 5882, 25533, 1442,
|
||||
-98, 5701, 25621, 1531, -92, 5522, 25704, 1622, -87, 5347, 25780, 1716, -81, 5174, 25852, 1813,
|
||||
-76, 5004, 25919, 1912, -72, 4837, 25980, 2015, -67, 4673, 26035, 2120, -63, 4512, 26085, 2227,
|
||||
-58, 4354, 26130, 2338, -54, 4199, 26169, 2451, -50, 4046, 26202, 2568, -46, 3897, 26230, 2688,
|
||||
-42, 3751, 26253, 2811, -38, 3608, 26270, 2936, -34, 3467, 26281, 3064, -32, 3329, 26287, 3195
|
||||
};
|
||||
#endregion
|
||||
|
||||
public static int[] Resample2Ch(
|
||||
int[] Buffer,
|
||||
int SrcSampleRate,
|
||||
int DstSampleRate,
|
||||
int SamplesCount,
|
||||
ref int FracPart)
|
||||
{
|
||||
if (Buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Buffer));
|
||||
}
|
||||
|
||||
if (SrcSampleRate <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(SrcSampleRate));
|
||||
}
|
||||
|
||||
if (DstSampleRate <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(DstSampleRate));
|
||||
}
|
||||
|
||||
double Ratio = (double)SrcSampleRate / DstSampleRate;
|
||||
|
||||
int NewSamplesCount = (int)(SamplesCount / Ratio);
|
||||
|
||||
int Step = (int)(Ratio * 0x8000);
|
||||
|
||||
int[] Output = new int[NewSamplesCount * 2];
|
||||
|
||||
short[] Lut;
|
||||
|
||||
if (Step > 0xaaaa)
|
||||
{
|
||||
Lut = CurveLut0;
|
||||
}
|
||||
else if (Step <= 0x8000)
|
||||
{
|
||||
Lut = CurveLut1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Lut = CurveLut2;
|
||||
}
|
||||
|
||||
int InOffs = 0;
|
||||
|
||||
for (int OutOffs = 0; OutOffs < Output.Length; OutOffs += 2)
|
||||
{
|
||||
int LutIndex = (FracPart >> 8) * 4;
|
||||
|
||||
int Sample0 = Buffer[(InOffs + 0) * 2 + 0] * Lut[LutIndex + 0] +
|
||||
Buffer[(InOffs + 1) * 2 + 0] * Lut[LutIndex + 1] +
|
||||
Buffer[(InOffs + 2) * 2 + 0] * Lut[LutIndex + 2] +
|
||||
Buffer[(InOffs + 3) * 2 + 0] * Lut[LutIndex + 3];
|
||||
|
||||
int Sample1 = Buffer[(InOffs + 0) * 2 + 1] * Lut[LutIndex + 0] +
|
||||
Buffer[(InOffs + 1) * 2 + 1] * Lut[LutIndex + 1] +
|
||||
Buffer[(InOffs + 2) * 2 + 1] * Lut[LutIndex + 2] +
|
||||
Buffer[(InOffs + 3) * 2 + 1] * Lut[LutIndex + 3];
|
||||
|
||||
int NewOffset = FracPart + Step;
|
||||
|
||||
InOffs += NewOffset >> 15;
|
||||
|
||||
FracPart = NewOffset & 0x7fff;
|
||||
|
||||
Output[OutOffs + 0] = Sample0 >> 15;
|
||||
Output[OutOffs + 1] = Sample1 >> 15;
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,10 +7,15 @@ namespace Ryujinx.HLE.OsHle.Services.Aud
|
|||
class VoiceContext
|
||||
{
|
||||
private bool Acquired;
|
||||
private bool BufferReload;
|
||||
|
||||
public int ChannelsCount;
|
||||
public int BufferIndex;
|
||||
public long Offset;
|
||||
private int ResamplerFracPart;
|
||||
|
||||
private int BufferIndex;
|
||||
private int Offset;
|
||||
|
||||
public int SampleRate;
|
||||
public int ChannelsCount;
|
||||
|
||||
public float Volume;
|
||||
|
||||
|
@ -24,6 +29,8 @@ namespace Ryujinx.HLE.OsHle.Services.Aud
|
|||
|
||||
public VoiceOut OutStatus;
|
||||
|
||||
private int[] Samples;
|
||||
|
||||
public bool Playing => Acquired && PlayState == PlayState.Playing;
|
||||
|
||||
public VoiceContext()
|
||||
|
@ -52,117 +59,116 @@ namespace Ryujinx.HLE.OsHle.Services.Aud
|
|||
OutStatus.VoiceDropsCount = 0;
|
||||
}
|
||||
|
||||
public short[] GetBufferData(AMemory Memory, int MaxSamples, out int Samples)
|
||||
public int[] GetBufferData(AMemory Memory, int MaxSamples, out int SamplesCount)
|
||||
{
|
||||
if (BufferReload)
|
||||
{
|
||||
BufferReload = false;
|
||||
|
||||
UpdateBuffer(Memory);
|
||||
}
|
||||
|
||||
WaveBuffer Wb = WaveBuffers[BufferIndex];
|
||||
|
||||
long Position = Wb.Position + Offset;
|
||||
int MaxSize = Samples.Length - Offset;
|
||||
|
||||
long MaxSize = Wb.Size - Offset;
|
||||
|
||||
long Size = GetSizeFromSamplesCount(MaxSamples);
|
||||
int Size = MaxSamples * AudioConsts.HostChannelsCount;
|
||||
|
||||
if (Size > MaxSize)
|
||||
{
|
||||
Size = MaxSize;
|
||||
}
|
||||
|
||||
Samples = GetSamplesCountFromSize(Size);
|
||||
int[] Output = new int[Size];
|
||||
|
||||
OutStatus.PlayedSamplesCount += Samples;
|
||||
Array.Copy(Samples, Offset, Output, 0, Size);
|
||||
|
||||
SamplesCount = Size / AudioConsts.HostChannelsCount;
|
||||
|
||||
OutStatus.PlayedSamplesCount += SamplesCount;
|
||||
|
||||
Offset += Size;
|
||||
|
||||
if (Offset == Wb.Size)
|
||||
if (Offset == Samples.Length)
|
||||
{
|
||||
Offset = 0;
|
||||
|
||||
if (Wb.Looping == 0)
|
||||
{
|
||||
BufferIndex = (BufferIndex + 1) & 3;
|
||||
SetBufferIndex((BufferIndex + 1) & 3);
|
||||
}
|
||||
|
||||
OutStatus.PlayedWaveBuffersCount++;
|
||||
}
|
||||
|
||||
return Decode(Memory.ReadBytes(Position, Size));
|
||||
return Output;
|
||||
}
|
||||
|
||||
private long GetSizeFromSamplesCount(int SamplesCount)
|
||||
private void UpdateBuffer(AMemory Memory)
|
||||
{
|
||||
//TODO: Implement conversion for formats other
|
||||
//than interleaved stereo (2 channels).
|
||||
//As of now, it assumes that HostChannelsCount == 2.
|
||||
WaveBuffer Wb = WaveBuffers[BufferIndex];
|
||||
|
||||
if (SampleFormat == SampleFormat.PcmInt16)
|
||||
{
|
||||
return SamplesCount * sizeof(short) * ChannelsCount;
|
||||
}
|
||||
else if (SampleFormat == SampleFormat.Adpcm)
|
||||
{
|
||||
return AdpcmDecoder.GetSizeFromSamplesCount(SamplesCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
int SamplesCount = (int)(Wb.Size / (sizeof(short) * ChannelsCount));
|
||||
|
||||
private int GetSamplesCountFromSize(long Size)
|
||||
{
|
||||
if (SampleFormat == SampleFormat.PcmInt16)
|
||||
{
|
||||
return (int)(Size / (sizeof(short) * ChannelsCount));
|
||||
}
|
||||
else if (SampleFormat == SampleFormat.Adpcm)
|
||||
{
|
||||
return AdpcmDecoder.GetSamplesCountFromSize(Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private short[] Decode(byte[] Buffer)
|
||||
{
|
||||
if (SampleFormat == SampleFormat.PcmInt16)
|
||||
{
|
||||
int Samples = GetSamplesCountFromSize(Buffer.Length);
|
||||
|
||||
short[] Output = new short[Samples * 2];
|
||||
Samples = new int[SamplesCount * AudioConsts.HostChannelsCount];
|
||||
|
||||
if (ChannelsCount == 1)
|
||||
{
|
||||
//Duplicate samples to convert the mono stream to stereo.
|
||||
for (int Offset = 0; Offset < Buffer.Length; Offset += 2)
|
||||
for (int Index = 0; Index < SamplesCount; Index++)
|
||||
{
|
||||
short Sample = GetShort(Buffer, Offset);
|
||||
short Sample = Memory.ReadInt16(Wb.Position + Index * 2);
|
||||
|
||||
Output[Offset + 0] = Sample;
|
||||
Output[Offset + 1] = Sample;
|
||||
Samples[Index * 2 + 0] = Sample;
|
||||
Samples[Index * 2 + 1] = Sample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int Offset = 0; Offset < Buffer.Length; Offset += 2)
|
||||
for (int Index = 0; Index < SamplesCount * 2; Index++)
|
||||
{
|
||||
Output[Offset >> 1] = GetShort(Buffer, Offset);
|
||||
Samples[Index] = Memory.ReadInt16(Wb.Position + Index * 2);
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
else if (SampleFormat == SampleFormat.Adpcm)
|
||||
{
|
||||
return AdpcmDecoder.Decode(Buffer, AdpcmCtx);
|
||||
byte[] Buffer = Memory.ReadBytes(Wb.Position, Wb.Size);
|
||||
|
||||
Samples = AdpcmDecoder.Decode(Buffer, AdpcmCtx);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (SampleRate != AudioConsts.HostSampleRate)
|
||||
{
|
||||
//TODO: We should keep the frames being discarded (see the 4 below)
|
||||
//on a buffer and include it on the next samples buffer, to allow
|
||||
//the resampler to do seamless interpolation between wave buffers.
|
||||
int SamplesCount = Samples.Length / AudioConsts.HostChannelsCount;
|
||||
|
||||
SamplesCount = Math.Max(SamplesCount - 4, 0);
|
||||
|
||||
Samples = Resampler.Resample2Ch(
|
||||
Samples,
|
||||
SampleRate,
|
||||
AudioConsts.HostSampleRate,
|
||||
SamplesCount,
|
||||
ref ResamplerFracPart);
|
||||
}
|
||||
}
|
||||
|
||||
private static short GetShort(byte[] Buffer, int Offset)
|
||||
public void SetBufferIndex(int Index)
|
||||
{
|
||||
return (short)((Buffer[Offset + 0] << 0) |
|
||||
(Buffer[Offset + 1] << 8));
|
||||
BufferIndex = Index;
|
||||
|
||||
BufferReload = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue