155 lines · c
1/* SPDX-License-Identifier: GPL-2.0-only */2/*3 * SpanDSP - a series of DSP components for telephony4 *5 * fir.h - General telephony FIR routines6 *7 * Written by Steve Underwood <steveu@coppice.org>8 *9 * Copyright (C) 2002 Steve Underwood10 *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 handling21 history sample offsets that are 16 bit aligned - the dual MAC needs22 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 be29 reduced. A drop in MIPs and memory approaching 50% should be30 possible.31 32 The foreground and background filters currenlty use a total of33 about 10 MIPs/ch as measured with speedtest.c on a 256 TAP echo34 can.35*/36 37/*38 * 16 bit integer FIR descriptor. This defines the working state for a single39 * instance of an FIR filter using 16 bit integer coefficients.40 */41struct 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 single50 * instance of an FIR filter using 32 bit integer coefficients, and filtering51 * 16 bit integer data.52 */53struct 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 single62 * instance of an FIR filter using floating point coefficients and data.63 */64struct fir_float_state_t {65 int taps;66 int curr_pos;67 const float *coeffs;68 float *history;69};70 71static 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 81static inline void fir16_flush(struct fir16_state_t *fir)82{83 memset(fir->history, 0, fir->taps * sizeof(int16_t));84}85 86static inline void fir16_free(struct fir16_state_t *fir)87{88 kfree(fir->history);89}90 91static 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 113static 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 123static inline void fir32_flush(struct fir32_state_t *fir)124{125 memset(fir->history, 0, fir->taps * sizeof(int16_t));126}127 128static inline void fir32_free(struct fir32_state_t *fir)129{130 kfree(fir->history);131}132 133static 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#endif155