16-level LUT, now sounds better than modplug at high frequencies
parent
60df49db69
commit
14af2ffeb7
|
@ -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] = {};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue