From 4cb83acddbe154312b74d2d63985ac1100bad7c5 Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Mon, 28 Nov 2022 20:16:46 +0100 Subject: Initial --- lib/resample_func.h | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 lib/resample_func.h (limited to 'lib/resample_func.h') diff --git a/lib/resample_func.h b/lib/resample_func.h new file mode 100644 index 0000000..9e894d4 --- /dev/null +++ b/lib/resample_func.h @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "resample.h" +#include "filter.h" + +namespace { + template + constexpr result_type dither_truncate(type value, unsigned dither) + { + using limits = std::numeric_limits; + using dither_limits = std::numeric_limits; + if constexpr(std::is_floating_point_v) + { + value += dither * type{1} / type{1ul << dither_limits::digits}; + value = std::floor(value); + } + else + { + static_assert(std::is_integral_v, "Unsupported acc_type"); + + value += dither >> (dither_limits::digits - limits::digits); // 17 for short + value >>= limits::digits; // 15 for short + } + + return std::clamp(value, limits::min(), limits::max()); + } +} + +template +void lfr_resample(lfr_fixed_t& pos, const lfr_fixed_t inv_ratio, unsigned& dither, void* out, std::size_t outlen, const void* in, std::size_t inlen, const lfr_filter& filter) +{ + static_assert(channels > 0, "0 channels do not make any sense"); + + auto inp = reinterpret_cast(in); + auto outp = reinterpret_cast(out); + auto fd = reinterpret_cast(filter.data.data()); + + const auto flen = filter.nsamp; + const auto log2nfilt = filter.log2nfilt; + auto x = pos; + std::array ds{dither}; + for(std::size_t i = 1; i < channels; ++i) + { + ds[i] = LCG_A * ds[i - 1] + LCG_C; + } + + for(std::size_t i = 0; i < outlen; ++i) + { + /* fn: filter number + ff0: filter factor for filter fn + ff1: filter factor for filter fn+1 */ + + const auto fn = (static_cast(x >> 1) >> (31 - log2nfilt)) & ((1u << log2nfilt) - 1); + int ff1 = (static_cast(x >> (32 - log2nfilt - INTERP_BIT))) & ((1u << INTERP_BIT) - 1); + int ff0 = (1u << INTERP_BIT) - ff1; + + /* off: offset in input corresponding to first sample in filter */ + auto off = static_cast(x >> 32); + /* fidx0, fidx1: start, end indexes in FIR data */ + int fidx0 = std::max(-off, 0); + int fidx1 = std::min(inlen - off, flen); + + /* acc: FIR accumulator */ + std::array acc{0}; + + for(int j = fidx0; j < fidx1; ++j) + { + acc_type f = (fd[(fn + 0) * flen + j] * ff0 + fd[(fn + 1) * flen + j] * ff1) / (1 << INTERP_BIT); + for(std::size_t c = 0; c < channels; ++c) + { + acc[c] += inp[(j + off) * channels + c] * f; + } + } + + for(std::size_t c = 0; c < channels; ++c) + { + outp[i * channels + c] = dither_truncate(acc[c], ds[c]); + + ds[c] = LCG_A2 * ds[c] + LCG_C2; + } + + x += inv_ratio; + } + + pos = x; + dither = ds[0]; +} -- cgit v1.2.3-54-g00ecf