16-level LUT, now sounds better than modplug at high frequencies

master
zetaPRIME 2021-11-10 23:26:54 -05:00
parent 60df49db69
commit 14af2ffeb7
2 changed files with 20 additions and 26 deletions

View File

@ -17,8 +17,8 @@ using std::cyl_bessel_i;
namespace {
const constexpr double PI = 3.141592653589793238462643383279502884197169399375105820974;
// 5.5 for downrate
const constexpr double KAISER_ALPHA = 5.5; //7.5;
// 5.5 for downrate; example gave 7.5
const constexpr double KAISER_ALPHA = 5.5;
const constexpr double KAISER_BETA = PI * KAISER_ALPHA;
inline constexpr double sinc(double x) {
@ -31,11 +31,11 @@ namespace {
// generate
const std::array<std::array<std::array<double, LUT_TAPS>, 2>, LUT_STEPS> Xybrid::NodeLib::resamplerLUT = [] {
const std::array<std::array<std::array<double, LUT_TAPS>, LUT_LEVELS>, LUT_STEPS> Xybrid::NodeLib::resamplerLUT = [] {
double denom = cyl_bessel_i(0, KAISER_BETA);
std::array<std::array<std::array<double, LUT_TAPS>, 2>, LUT_STEPS> t;
std::array<std::array<std::array<double, LUT_TAPS>, LUT_LEVELS>, LUT_STEPS> t;
//t[0] = {0, 0, 0, 1, 0, 0, 0, 0}; // we already know the ideal integer step
for (size_t step = 0; step < LUT_STEPS; step++) {
double sv = static_cast<double>(step) / LUT_STEPS; // subvalue (offset of tap position)
@ -50,12 +50,16 @@ const std::array<std::array<std::array<double, LUT_TAPS>, 2>, LUT_STEPS> Xybrid:
//kaiser = std::max(kaiser, 0.0);
t[step][0][tap] = sinc(sx) * kaiser; // sinc function centered on main tap, offset by subvalue, multiplied by window
// uprate table
t[step][1][tap] = sinc(sx*0.5) * 0.5;// * kaiser; // for some reason this sounds cleaner (nearly identical to modplug polyphase)
// uprate tables
for (size_t i = 1; i < LUT_LEVELS; i++) {
double m = 1.0/static_cast<double>(i);
double om = m;
if (i == 1) om *= kaiser; // add kaiser to output mult on first level to smooth things
t[step][i][tap] = sinc(sx*m) * om; // we're squishing the waveform here so we want to "expand" the sinc function
if (t[step][i][tap] != t[step][i][tap]) t[step][i][tap] = 0; // NaN guard
}
// NaN guards
if (t[step][0][tap] != t[step][0][tap]) t[step][0][tap] = 0;
if (t[step][1][tap] != t[step][1][tap]) t[step][1][tap] = 0;
if (t[step][0][tap] != t[step][0][tap]) t[step][0][tap] = 0; // NaN guard
}
}
/*t[0] = {};

View File

@ -8,10 +8,11 @@
#include "data/sample.h"
namespace Xybrid::NodeLib {
const constexpr size_t LUT_LEVELS = 16;
const constexpr size_t LUT_TAPS = 8;
const constexpr ptrdiff_t LUT_HTAPS = LUT_TAPS/2-1;//static_cast<ptrdiff_t>(LUT_TAPS - (LUT_TAPS+0.5)/2);
const constexpr size_t LUT_STEPS = 1024;
extern const std::array<std::array<std::array<double, LUT_TAPS>, 2>, LUT_STEPS> resamplerLUT;
extern const std::array<std::array<std::array<double, LUT_TAPS>, LUT_LEVELS>, LUT_STEPS> resamplerLUT;
inline Data::AudioFrame resamp(Data::Sample* smp, double pos, double rate [[maybe_unused]]) {
auto loop = smp->loopStart >= 0;
@ -21,28 +22,17 @@ namespace Xybrid::NodeLib {
auto ll = le - ls;
double ip = std::floor(pos);
auto& pt = NodeLib::resamplerLUT[static_cast<size_t>((pos - ip)*NodeLib::LUT_STEPS) % NodeLib::LUT_STEPS][rate > 1.0 ? 1 : 0];
auto& pt = NodeLib::resamplerLUT[static_cast<size_t>((pos - ip)*NodeLib::LUT_STEPS) % NodeLib::LUT_STEPS][static_cast<size_t>(std::clamp(std::floor(rate - 0.00001), 0.0, LUT_LEVELS*1.0))];
Data::AudioFrame out(0.0);
if (false && rate > 1.0) {
//*
auto ii = static_cast<ptrdiff_t>(ip);
if (loop && ii > le) ii = (ii - ls) % ll + ls;
if (ii >= 0 && ii < len) out += (*smp)[static_cast<size_t>(ii)] * (1.0-(pos-ip));
auto ii = static_cast<ptrdiff_t>(ip) - LUT_HTAPS;
for (size_t i = 0; i < 8; i++) {
if (loop && ii >= le) ii = ((ii - ls) % ll) + ls;
if (ii >= 0 && ii < len) out += (*smp)[static_cast<size_t>(ii)] * pt[i];
ii++;
if (loop && ii > le) ii = (ii - ls) % ll + ls;
if (ii >= 0 && ii < len) out += (*smp)[static_cast<size_t>(ii)] * (1.0*(pos-ip));//*/
} else {
auto ii = static_cast<ptrdiff_t>(ip) - LUT_HTAPS;
for (size_t i = 0; i < 8; i++) {
if (loop && ii >= le) ii = ((ii - ls) % ll) + ls;
if (ii >= 0 && ii < len) out += (*smp)[static_cast<size_t>(ii)] * pt[i];
ii++;
}
}
return out;
}
}