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  
fir16_create(struct fir16_state_t * fir,const int16_t * coeffs,int taps)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  
fir16_flush(struct fir16_state_t * fir)81  static inline void fir16_flush(struct fir16_state_t *fir)
82  {
83  	memset(fir->history, 0, fir->taps * sizeof(int16_t));
84  }
85  
fir16_free(struct fir16_state_t * fir)86  static inline void fir16_free(struct fir16_state_t *fir)
87  {
88  	kfree(fir->history);
89  }
90  
fir16(struct fir16_state_t * fir,int16_t sample)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  
fir32_create(struct fir32_state_t * fir,const int32_t * coeffs,int taps)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  
fir32_flush(struct fir32_state_t * fir)123  static inline void fir32_flush(struct fir32_state_t *fir)
124  {
125  	memset(fir->history, 0, fir->taps * sizeof(int16_t));
126  }
127  
fir32_free(struct fir32_state_t * fir)128  static inline void fir32_free(struct fir32_state_t *fir)
129  {
130  	kfree(fir->history);
131  }
132  
fir32(struct fir32_state_t * fir,int16_t sample)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