aboutsummaryrefslogtreecommitdiffstats
path: root/lib/filter.h
diff options
context:
space:
mode:
authorMarkus Mittendrein <maxmitti@maxmitti.tk>2022-11-28 20:16:46 +0100
committerMarkus Mittendrein <maxmitti@maxmitti.tk>2022-11-28 20:16:46 +0100
commit4cb83acddbe154312b74d2d63985ac1100bad7c5 (patch)
treed49dc904acc9af57acca8864fb6a40e340accacc /lib/filter.h
downloadfresample-master.tar.gz
fresample-master.zip
InitialHEADmaster
Diffstat (limited to 'lib/filter.h')
-rw-r--r--lib/filter.h181
1 files changed, 181 insertions, 0 deletions
diff --git a/lib/filter.h b/lib/filter.h
new file mode 100644
index 0000000..b6ca66e
--- /dev/null
+++ b/lib/filter.h
@@ -0,0 +1,181 @@
+/* Copyright 2012 Dietrich Epp <depp@zdome.net> */
+#pragma once
+#include "types.h"
+#include "param.h"
+
+#include <vector>
+
+/* Bits used for interpolating between two filters. The scalar
+ implementation supports up to 16 bits, but the SIMD implementations
+ generally only support 14 so the values can fit in a signed 16-bit
+ word. We bring all implementations to the same accuracy in order
+ to ensure that all implementations produce the same results. */
+#define INTERP_BITS 14
+
+/*
+ Filter types
+*/
+enum lfr_ftype_t {
+ LFR_FTYPE_S16,
+ LFR_FTYPE_F32
+};
+
+/*
+ Array of FIR filters.
+
+ Let N=2^log2nfilt, M=nsamp.
+
+ This is an array of N+1 filters, 0..N, with each filter M samples
+ long. Filter number I will be centered on the sample with offset:
+
+ floor(M/2) + I/N
+
+ This means that filter N will be a copy of filter 0, except shifted
+ to the right by one sample. This extra filter makes the
+ interpolation code simpler.
+*/
+
+
+/*
+ Information queries that a filter responds to. Each query gives an
+ integer or floating point result, automatically cast to the type
+ requested.
+*/
+enum LFR_INFO_TYPE {
+ /*
+ The size of the filter, also known as the filter's order. This
+ does not include oversampling. The resampler will read this
+ many samples, starting with the current position (rounded down),
+ whenever it calculates a sample.
+
+ In other words, this is the amount of overlap needed when
+ resampling consecutive buffers.
+ */
+ LFR_INFO_SIZE,
+
+ /*
+ Filter delay. Note that lfr_filter_delay returns a fixed point
+ number and is usually preferable.
+ */
+ LFR_INFO_DELAY,
+
+ /*
+ The is the number of bytes used by filter coefficients.
+ */
+ LFR_INFO_MEMSIZE,
+
+ /*
+ The normalized pass frequency the filter was designed with.
+ */
+ LFR_INFO_FPASS,
+
+ /*
+ The normalized stop frequency the filter was designed with.
+ */
+ LFR_INFO_FSTOP,
+
+ /*
+ The stopband attenuation, in dB, that the filter was designed
+ with.
+ */
+ LFR_INFO_ATTEN,
+
+ LFR_INFO_COUNT
+};
+
+/*
+ * A filter for resampling audio.
+ */
+struct lfr_filter {
+ /*
+ FIR filter coefficient data type.
+ */
+ lfr_ftype_t type;
+
+ /*
+ FIR filter data.
+ */
+ std::vector<char> data;
+
+ /*
+ Length of each filter, in samples. This is chosen to make each
+ filter size a multiple of the SIMD register size. Most SIMD
+ implementations today use 16 byte registers, so this will
+ usually be a multiple of 8 or 4, depending on the coefficient
+ type.
+ */
+ int nsamp;
+
+ /*
+ Base 2 logarithm of the number of different filters. There is
+ always an additional filter at the end of the filter array to
+ simplify interpolation, this extra filter is a copy of the first
+ filter shifted right by one sample.
+ */
+ int log2nfilt;
+
+ /*
+ Filter delay. Filters are causal, so this should be
+ non-negative.
+ */
+ lfr_fixed_t delay;
+
+ /*
+ Design parameters of the filter.
+ */
+ double f_pass, f_stop, atten;
+
+ lfr_filter(lfr_param& param);
+ int geti(LFR_INFO_TYPE iname, bool convert = true) const;
+ double getf(LFR_INFO_TYPE iname, bool convert = true) const;
+
+
+/*
+ Resample an audio buffer. Note that this function may need to
+ create intermediate buffers if there is no function which can
+ directly operate on the input and output formats. No intermediate
+ buffers will be necessary if the following conditions are met:
+
+ - Input and output formats are identical.
+
+ - Sample format is either S16_NATIVE or F32_NATIVE.
+
+ - The number of channels is either 1 (mono) or 2 (stereo).
+
+ pos: Current position relative to the start of the input buffer,
+ expressed as a 32.32 fixed point number. On return, this will
+ contain the updated position. Positions outside the input buffer
+ are acceptable, it will be treated as if the input buffer were
+ padded with an unlimited number of zeroes on either side.
+
+ inv_ratio: Inverse of the resampling ratio, expressed as a 32.32
+ fixed point number. This number is equal to the input sample rate
+ divided by the output sample rate.
+
+ dither: State of the PRNG used for dithering.
+
+ nchan: Number of interleaved channels.
+
+ out, in: Input and output buffers. The buffers are not permitted to
+ alias each other.
+
+ outlen, inlen: Length of buffers, in frames. Note that the length
+ type is 'int' instead of 'size_t'; this matches the precision of
+ buffer positions.
+
+ outfmt, infmt: Format of input and output buffers.
+
+ filter: A suitable low-pass filter for resampling at the given
+ ratio.
+*/
+ void resample(
+ lfr_fixed_t *pos, lfr_fixed_t inv_ratio,
+ unsigned *dither, int nchan,
+ void *out, lfr_fmt_t outfmt, int outlen,
+ const void *in, lfr_fmt_t infmt, int inlen);
+private:
+ /*
+ Create a Kaiser-windowed sinc filter.
+ */
+ void setup_window(double cutoff, double beta);
+}; \ No newline at end of file