aboutsummaryrefslogtreecommitdiffstats
path: root/lib/filter.h
blob: b6ca66e062fd17f9af56e1deb0b4faedfa3fde2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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);
};