From 1d477ab92d268e7b3094c6a625d3feeb8d5559e8 Mon Sep 17 00:00:00 2001 From: Nusan <> Date: Sun, 14 Jul 2024 09:38:21 +0200 Subject: [PATCH] audio resampler now uses 16 taps lanczos filter (the old lerp was intrucing a wide low pass filter that was bleeding everwhere) --- include/lol/private/audio/stream.h | 37 +++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/include/lol/private/audio/stream.h b/include/lol/private/audio/stream.h index 4262ec69..676f0f16 100644 --- a/include/lol/private/audio/stream.h +++ b/include/lol/private/audio/stream.h @@ -19,6 +19,7 @@ // #include // std::floor +#include "../math/constants.h" // F_PI #include // std::function #include // std::numeric_limits #include // std::shared_ptr @@ -337,10 +338,33 @@ public: if (in_rate == out_rate) return m_in->get(buf, frames); + // 16 taps lanczos filter + const size_t window_size = 16; + const float window_center = 8.0f; + + const size_t constexpr lanczos_size = window_size * 64; + const float lanczos_lut_scale = (lanczos_size - 1) / (window_center + 1.0f); + + static auto build_lanczos = [&]() + { + std::array ret; + for (int k = 0; k < lanczos_size; ++k) + { + float dist = float(k) * F_PI / lanczos_lut_scale; + float lanczos = 1.0f; + if (dist > 0.0f) lanczos = window_center * std::sinf(dist) * std::sinf(dist / window_center) / (dist * dist); + ret[k] = lanczos; + } + return ret; + }; + + static auto const lanczos_lut = build_lanczos(); + + for (size_t n = 0; n < frames; ++n, m_pos += in_rate) { // Fill internal buffer if we don’t have enough data - while (m_cache.size() / channels < m_pos / out_rate + 2) + while (m_cache.size() / channels < m_pos / out_rate + window_size) { // Remove obsolete frames on the left size_t todelete = std::min(m_pos / out_rate, m_cache.size() / channels); @@ -358,8 +382,15 @@ public: for (size_t ch = 0; ch < channels; ++ch) { - *buf++ = m_cache[n0 * channels + ch] * (1.f - alpha) - + m_cache[(n0 + 1) * channels + ch] * alpha; + // lanczos upsampling + T value = T(); + for (size_t wi = 0; wi < window_size; ++wi) + { + float dist = std::abs(wi - window_center - alpha); + float lanczos = lanczos_lut[int(dist * lanczos_lut_scale)]; + value += m_cache[(n0 + wi) * channels + ch] * lanczos; + } + *buf++ = value; } }