xref: /linux/drivers/misc/echo/fir.h (revision 22d55f02b8922a097cd4be1e2f131dfa7ef65901)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * SpanDSP - a series of DSP components for telephony
4  *
5  * fir.h - General telephony FIR routines
6  *
7  * Written by Steve Underwood <steveu@coppice.org>
8  *
9  * Copyright (C) 2002 Steve Underwood
10  *
11  * All rights reserved.
12  */
13 
14 #if !defined(_FIR_H_)
15 #define _FIR_H_
16 
17 /*
18    Ideas for improvement:
19 
20    1/ Rewrite filter for dual MAC inner loop.  The issue here is handling
21    history sample offsets that are 16 bit aligned - the dual MAC needs
22    32 bit aligmnent.  There are some good examples in libbfdsp.
23 
24    2/ Use the hardware circular buffer facility tohalve memory usage.
25 
26    3/ Consider using internal memory.
27 
28    Using less memory might also improve speed as cache misses will be
29    reduced. A drop in MIPs and memory approaching 50% should be
30    possible.
31 
32    The foreground and background filters currenlty use a total of
33    about 10 MIPs/ch as measured with speedtest.c on a 256 TAP echo
34    can.
35 */
36 
37 /*
38  * 16 bit integer FIR descriptor. This defines the working state for a single
39  * instance of an FIR filter using 16 bit integer coefficients.
40  */
41 struct fir16_state_t {
42 	int taps;
43 	int curr_pos;
44 	const int16_t *coeffs;
45 	int16_t *history;
46 };
47 
48 /*
49  * 32 bit integer FIR descriptor. This defines the working state for a single
50  * instance of an FIR filter using 32 bit integer coefficients, and filtering
51  * 16 bit integer data.
52  */
53 struct fir32_state_t {
54 	int taps;
55 	int curr_pos;
56 	const int32_t *coeffs;
57 	int16_t *history;
58 };
59 
60 /*
61  * Floating point FIR descriptor. This defines the working state for a single
62  * instance of an FIR filter using floating point coefficients and data.
63  */
64 struct fir_float_state_t {
65 	int taps;
66 	int curr_pos;
67 	const float *coeffs;
68 	float *history;
69 };
70 
71 static inline const int16_t *fir16_create(struct fir16_state_t *fir,
72 					      const int16_t *coeffs, int taps)
73 {
74 	fir->taps = taps;
75 	fir->curr_pos = taps - 1;
76 	fir->coeffs = coeffs;
77 	fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
78 	return fir->history;
79 }
80 
81 static inline void fir16_flush(struct fir16_state_t *fir)
82 {
83 	memset(fir->history, 0, fir->taps * sizeof(int16_t));
84 }
85 
86 static inline void fir16_free(struct fir16_state_t *fir)
87 {
88 	kfree(fir->history);
89 }
90 
91 static inline int16_t fir16(struct fir16_state_t *fir, int16_t sample)
92 {
93 	int32_t y;
94 	int i;
95 	int offset1;
96 	int offset2;
97 
98 	fir->history[fir->curr_pos] = sample;
99 
100 	offset2 = fir->curr_pos;
101 	offset1 = fir->taps - offset2;
102 	y = 0;
103 	for (i = fir->taps - 1; i >= offset1; i--)
104 		y += fir->coeffs[i] * fir->history[i - offset1];
105 	for (; i >= 0; i--)
106 		y += fir->coeffs[i] * fir->history[i + offset2];
107 	if (fir->curr_pos <= 0)
108 		fir->curr_pos = fir->taps;
109 	fir->curr_pos--;
110 	return (int16_t) (y >> 15);
111 }
112 
113 static inline const int16_t *fir32_create(struct fir32_state_t *fir,
114 					      const int32_t *coeffs, int taps)
115 {
116 	fir->taps = taps;
117 	fir->curr_pos = taps - 1;
118 	fir->coeffs = coeffs;
119 	fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
120 	return fir->history;
121 }
122 
123 static inline void fir32_flush(struct fir32_state_t *fir)
124 {
125 	memset(fir->history, 0, fir->taps * sizeof(int16_t));
126 }
127 
128 static inline void fir32_free(struct fir32_state_t *fir)
129 {
130 	kfree(fir->history);
131 }
132 
133 static inline int16_t fir32(struct fir32_state_t *fir, int16_t sample)
134 {
135 	int i;
136 	int32_t y;
137 	int offset1;
138 	int offset2;
139 
140 	fir->history[fir->curr_pos] = sample;
141 	offset2 = fir->curr_pos;
142 	offset1 = fir->taps - offset2;
143 	y = 0;
144 	for (i = fir->taps - 1; i >= offset1; i--)
145 		y += fir->coeffs[i] * fir->history[i - offset1];
146 	for (; i >= 0; i--)
147 		y += fir->coeffs[i] * fir->history[i + offset2];
148 	if (fir->curr_pos <= 0)
149 		fir->curr_pos = fir->taps;
150 	fir->curr_pos--;
151 	return (int16_t) (y >> 15);
152 }
153 
154 #endif
155