audio: Add support for resampling tracks

Uses the resampling algorithm derived from HOS by the Ryujinx team
to resample the stream on the fly to 48KHz.
It is currently used only in audout.
This commit is contained in:
Billy Laws 2020-01-24 22:03:12 +00:00 committed by ◱ PixelyIon
parent 93206d5a3c
commit ddd1fc61ef
5 changed files with 181 additions and 2 deletions

View File

@ -25,6 +25,7 @@ add_library(skyline SHARED
${source_DIR}/main.cpp
${source_DIR}/skyline/audio.cpp
${source_DIR}/skyline/audio/track.cpp
${source_DIR}/skyline/audio/resampler.cpp
${source_DIR}/skyline/common.cpp
${source_DIR}/skyline/nce/guest.S
${source_DIR}/skyline/nce/guest.cpp

View File

@ -0,0 +1,150 @@
#include <array>
#include <common.h>
#include "resampler.h"
namespace skyline::audio {
struct LutEntry {
i32 a;
i32 b;
i32 c;
i32 d;
};
constexpr std::array<LutEntry, 128> curveLut0 = {{
{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}}};
constexpr std::array<LutEntry, 128> curveLut1 = {{
{-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}}};
constexpr std::array<LutEntry, 128> curveLut2 = {{
{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}}};
std::vector<i16> Resampler::ResampleBuffer(std::vector<i16> &inputBuffer, double ratio, int channelCount) {
uint step = static_cast<uint>(ratio * 0x8000);
uint outputSize = static_cast<uint>(static_cast<double>(inputBuffer.size()) / ratio);
std::vector<i16> outputBuffer(static_cast<size_t>(outputSize));
const std::array<skyline::audio::LutEntry, 128> &lut = [step] {
if (step > 0xaaaa) {
return curveLut0;
} else if (step <= 0x8000) {
return curveLut1;
} else {
return curveLut2;
}
} ();
for (uint outIndex = 0, inIndex = 0; outIndex < outputBuffer.size(); outIndex += channelCount) {
uint lutIndex = (fraction >> 8) << 2;
for (int channel = 0; channel < channelCount; channel++) {
int data = inputBuffer[(inIndex + 0) * channelCount + channel] * lut[lutIndex].a +
inputBuffer[(inIndex + 1) * channelCount + channel] * lut[lutIndex].b +
inputBuffer[(inIndex + 2) * channelCount + channel] * lut[lutIndex].c +
inputBuffer[(inIndex + 3) * channelCount + channel] * lut[lutIndex].d;
outputBuffer[outIndex + channel] = static_cast<i16>(std::clamp(data >> 15,
static_cast<int>(std::numeric_limits<i16>::min()), static_cast<int>(std::numeric_limits<i16>::max())));
}
uint newOffset = fraction + step;
inIndex += newOffset >> 15;
fraction = newOffset & 0x7fff;
}
return outputBuffer;
}
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <common.h>
namespace skyline::audio {
/**
* @brief The Resampler class handles resampling audio PCM data
*/
class Resampler {
private:
uint fraction{}; //!< The fractional value used for storing the resamplers last frame
public:
/**
* @brief Resamples the given sample buffer by the given ratio
* @param inputBuffer A buffer containing PCM sample data
* @param ratio The conversion ratio needed
* @param channelCount The amount of channels the buffer contains
*/
std::vector<i16> ResampleBuffer(std::vector<i16> &inputBuffer, double ratio, int channelCount);
};
}

View File

@ -30,7 +30,7 @@ namespace skyline::service::audout {
response.Push(static_cast<u32>(audio::AudioOutState::Stopped));
}
IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, int channelCount, int sampleRate) : releaseEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager, false, Service::audout_IAudioOut, {
IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, int channelCount, int sampleRate) : sampleRate(sampleRate), channelCount(channelCount), releaseEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager, false, Service::audout_IAudioOut, {
{0x0, SFUNC(IAudioOut::GetAudioOutState)},
{0x1, SFUNC(IAudioOut::StartAudioOut)},
{0x2, SFUNC(IAudioOut::StopAudioOut)},
@ -39,7 +39,7 @@ namespace skyline::service::audout {
{0x5, SFUNC(IAudioOut::GetReleasedAudioOutBuffer)},
{0x6, SFUNC(IAudioOut::ContainsAudioOutBuffer)}
}) {
track = state.audio->OpenTrack(channelCount, sampleRate, [this]() { this->releaseEvent->Signal(); });
track = state.audio->OpenTrack(channelCount, audio::constant::SampleRate, [this]() { this->releaseEvent->Signal(); });
}
IAudioOut::~IAudioOut() {
@ -74,6 +74,7 @@ namespace skyline::service::audout {
tmpSampleBuffer.resize(data.sampleSize / sizeof(i16));
state.process->ReadMemory(tmpSampleBuffer.data(), data.sampleBufferPtr, data.sampleSize);
resampler.ResampleBuffer(tmpSampleBuffer, static_cast<double>(sampleRate) / audio::constant::SampleRate, channelCount);
track->AppendBuffer(tmpSampleBuffer, tag);
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <audio/resampler.h>
#include <audio.h>
#include <services/base_service.h>
#include <services/serviceman.h>
@ -33,10 +34,14 @@ namespace skyline::service::audout {
*/
class IAudioOut : public BaseService {
private:
audio::Resampler resampler; //!< The audio resampler object used to resample audio
std::shared_ptr<audio::AudioTrack> track; //!< The audio track associated with the audio out
std::shared_ptr<type::KEvent> releaseEvent; //!< The KEvent that is signalled when a buffer has been released
std::vector<i16> tmpSampleBuffer; //!< A temporary buffer used to store sample data in AppendAudioOutBuffer
int sampleRate; //!< The sample rate of the audio out
int channelCount; //!< The amount of channels in the data sent to the audio out
public:
/**
* @param channelCount The channel count of the audio data the audio out will be fed