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