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