^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) * echo.c - A line echo canceller. This code is being developed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * against and partially complies with G168.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Written by Steve Underwood <steveu@coppice.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * and David Rowe <david_at_rowetel_dot_com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Copyright (C) 2001, 2003 Steve Underwood, 2007 David Rowe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Based on a bit from here, a bit from there, eye of toad, ear of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * bat, 15 years of failed attempts by David and a few fried brain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * cells.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /*! \file */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /* Implementation Notes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) David Rowe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) April 2007
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) This code started life as Steve's NLMS algorithm with a tap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) rotation algorithm to handle divergence during double talk. I
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) added a Geigel Double Talk Detector (DTD) [2] and performed some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) G168 tests. However I had trouble meeting the G168 requirements,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) especially for double talk - there were always cases where my DTD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) failed, for example where near end speech was under the 6dB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) threshold required for declaring double talk.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) So I tried a two path algorithm [1], which has so far given better
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) results. The original tap rotation/Geigel algorithm is available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) in SVN http://svn.rowetel.com/software/oslec/tags/before_16bit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) It's probably possible to make it work if some one wants to put some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) serious work into it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) At present no special treatment is provided for tones, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) generally cause NLMS algorithms to diverge. Initial runs of a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) subset of the G168 tests for tones (e.g ./echo_test 6) show the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) current algorithm is passing OK, which is kind of surprising. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) full set of tests needs to be performed to confirm this result.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) One other interesting change is that I have managed to get the NLMS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) code to work with 16 bit coefficients, rather than the original 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) bit coefficents. This reduces the MIPs and storage required.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) I evaulated the 16 bit port using g168_tests.sh and listening tests
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) on 4 real-world samples.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) I also attempted the implementation of a block based NLMS update
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) [2] but although this passes g168_tests.sh it didn't converge well
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) on the real-world samples. I have no idea why, perhaps a scaling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) problem. The block based code is also available in SVN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) http://svn.rowetel.com/software/oslec/tags/before_16bit. If this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) code can be debugged, it will lead to further reduction in MIPS, as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) the block update code maps nicely onto DSP instruction sets (it's a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) dot product) compared to the current sample-by-sample update.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) Steve also has some nice notes on echo cancellers in echo.h
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) References:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) [1] Ochiai, Areseki, and Ogihara, "Echo Canceller with Two Echo
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) Path Models", IEEE Transactions on communications, COM-25,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) No. 6, June
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) 1977.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) https://www.rowetel.com/images/echo/dual_path_paper.pdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) [2] The classic, very useful paper that tells you how to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) actually build a real world echo canceller:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) Messerschmitt, Hedberg, Cole, Haoui, Winship, "Digital Voice
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) Echo Canceller with a TMS320020,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) https://www.rowetel.com/images/echo/spra129.pdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) [3] I have written a series of blog posts on this work, here is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) Part 1: http://www.rowetel.com/blog/?p=18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) [4] The source code http://svn.rowetel.com/software/oslec/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) [5] A nice reference on LMS filters:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) https://en.wikipedia.org/wiki/Least_mean_squares_filter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) Credits:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) Thanks to Steve Underwood, Jean-Marc Valin, and Ramakrishnan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) Muthukrishnan for their suggestions and email discussions. Thanks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) also to those people who collected echo samples for me such as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) Mark, Pawel, and Pavel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #include "echo.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #define MIN_TX_POWER_FOR_ADAPTION 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #define MIN_RX_POWER_FOR_ADAPTION 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define DTD_HANGOVER 600 /* 600 samples, or 75ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define DC_LOG2BETA 3 /* log2() of DC filter Beta */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /* adapting coeffs using the traditional stochastic descent (N)LMS algorithm */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static inline void lms_adapt_bg(struct oslec_state *ec, int clean, int shift)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) int offset1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) int offset2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) int factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) int exp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (shift > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) factor = clean << shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) factor = clean >> -shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* Update the FIR taps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) offset2 = ec->curr_pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) offset1 = ec->taps - offset2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) for (i = ec->taps - 1; i >= offset1; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) exp = (ec->fir_state_bg.history[i - offset1] * factor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) for (; i >= 0; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) exp = (ec->fir_state_bg.history[i + offset2] * factor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static inline int top_bit(unsigned int bits)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (bits == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return (int)fls((int32_t) bits) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct oslec_state *oslec_create(int len, int adaption_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct oslec_state *ec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) const int16_t *history;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) ec = kzalloc(sizeof(*ec), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (!ec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) ec->taps = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) ec->log2taps = top_bit(len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) ec->curr_pos = ec->taps - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) ec->fir_taps16[0] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (!ec->fir_taps16[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) goto error_oom_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) ec->fir_taps16[1] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (!ec->fir_taps16[1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) goto error_oom_1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) history = fir16_create(&ec->fir_state, ec->fir_taps16[0], ec->taps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (!history)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) goto error_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) history = fir16_create(&ec->fir_state_bg, ec->fir_taps16[1], ec->taps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (!history)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) goto error_state_bg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) for (i = 0; i < 5; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) ec->xvtx[i] = ec->yvtx[i] = ec->xvrx[i] = ec->yvrx[i] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) ec->cng_level = 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) oslec_adaption_mode(ec, adaption_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) ec->snapshot = kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (!ec->snapshot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) goto error_snap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) ec->cond_met = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) ec->pstates = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) ec->ltxacc = ec->lrxacc = ec->lcleanacc = ec->lclean_bgacc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) ec->ltx = ec->lrx = ec->lclean = ec->lclean_bg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) ec->lbgn = ec->lbgn_acc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) ec->lbgn_upper = 200;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) ec->lbgn_upper_acc = ec->lbgn_upper << 13;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return ec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) error_snap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) fir16_free(&ec->fir_state_bg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) error_state_bg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) fir16_free(&ec->fir_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) error_state:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) kfree(ec->fir_taps16[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) error_oom_1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) kfree(ec->fir_taps16[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) error_oom_0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) kfree(ec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) EXPORT_SYMBOL_GPL(oslec_create);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) void oslec_free(struct oslec_state *ec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) fir16_free(&ec->fir_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) fir16_free(&ec->fir_state_bg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) for (i = 0; i < 2; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) kfree(ec->fir_taps16[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) kfree(ec->snapshot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) kfree(ec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) EXPORT_SYMBOL_GPL(oslec_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) void oslec_adaption_mode(struct oslec_state *ec, int adaption_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) ec->adaption_mode = adaption_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) EXPORT_SYMBOL_GPL(oslec_adaption_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) void oslec_flush(struct oslec_state *ec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) ec->ltxacc = ec->lrxacc = ec->lcleanacc = ec->lclean_bgacc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) ec->ltx = ec->lrx = ec->lclean = ec->lclean_bg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) ec->lbgn = ec->lbgn_acc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) ec->lbgn_upper = 200;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) ec->lbgn_upper_acc = ec->lbgn_upper << 13;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) ec->nonupdate_dwell = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) fir16_flush(&ec->fir_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) fir16_flush(&ec->fir_state_bg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) ec->fir_state.curr_pos = ec->taps - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) ec->fir_state_bg.curr_pos = ec->taps - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) for (i = 0; i < 2; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) ec->curr_pos = ec->taps - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) ec->pstates = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) EXPORT_SYMBOL_GPL(oslec_flush);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) void oslec_snapshot(struct oslec_state *ec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps * sizeof(int16_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) EXPORT_SYMBOL_GPL(oslec_snapshot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) /* Dual Path Echo Canceller */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) int32_t echo_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) int clean_bg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) int tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) int tmp1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * Input scaling was found be required to prevent problems when tx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * starts clipping. Another possible way to handle this would be the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * filter coefficent scaling.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) ec->tx = tx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) ec->rx = rx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) tx >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) rx >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) * Filter DC, 3dB point is 160Hz (I think), note 32 bit precision
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * required otherwise values do not track down to 0. Zero at DC, Pole
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * at (1-Beta) on real axis. Some chip sets (like Si labs) don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * need this, but something like a $10 X100P card does. Any DC really
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * slows down convergence.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) * Note: removes some low frequency from the signal, this reduces the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) * speech quality when listening to samples through headphones but may
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * not be obvious through a telephone handset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) * Note that the 3dB frequency in radians is approx Beta, e.g. for Beta
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) * = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) tmp = rx << 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) * Make sure the gain of the HPF is 1.0. This can still
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) * saturate a little under impulse conditions, and it might
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) * roll to 32768 and need clipping on sustained peak level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) * signals. However, the scale of such clipping is small, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) * the error due to any saturation should not markedly affect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) * the downstream processing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) tmp -= (tmp >> 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) ec->rx_1 += -(ec->rx_1 >> DC_LOG2BETA) + tmp - ec->rx_2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * hard limit filter to prevent clipping. Note that at this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * stage rx should be limited to +/- 16383 due to right shift
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) * above
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) tmp1 = ec->rx_1 >> 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) if (tmp1 > 16383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) tmp1 = 16383;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (tmp1 < -16383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) tmp1 = -16383;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) rx = tmp1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) ec->rx_2 = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /* Block average of power in the filter states. Used for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) adaption power calculation. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) int new, old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) /* efficient "out with the old and in with the new" algorithm so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) we don't have to recalculate over the whole block of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) samples. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) new = (int)tx * (int)tx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) old = (int)ec->fir_state.history[ec->fir_state.curr_pos] *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) (int)ec->fir_state.history[ec->fir_state.curr_pos];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) ec->pstates +=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) ((new - old) + (1 << (ec->log2taps - 1))) >> ec->log2taps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (ec->pstates < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) ec->pstates = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) /* Calculate short term average levels using simple single pole IIRs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) ec->ltxacc += abs(tx) - ec->ltx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) ec->ltx = (ec->ltxacc + (1 << 4)) >> 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) ec->lrxacc += abs(rx) - ec->lrx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) ec->lrx = (ec->lrxacc + (1 << 4)) >> 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) /* Foreground filter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) ec->fir_state.coeffs = ec->fir_taps16[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) echo_value = fir16(&ec->fir_state, tx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) ec->clean = rx - echo_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) ec->lcleanacc += abs(ec->clean) - ec->lclean;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) ec->lclean = (ec->lcleanacc + (1 << 4)) >> 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) /* Background filter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) echo_value = fir16(&ec->fir_state_bg, tx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) clean_bg = rx - echo_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) ec->lclean_bgacc += abs(clean_bg) - ec->lclean_bg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) ec->lclean_bg = (ec->lclean_bgacc + (1 << 4)) >> 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) /* Background Filter adaption */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) /* Almost always adap bg filter, just simple DT and energy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) detection to minimise adaption in cases of strong double talk.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) However this is not critical for the dual path algorithm.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) ec->factor = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) ec->shift = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (!ec->nonupdate_dwell) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) int p, logp, shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) /* Determine:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) f = Beta * clean_bg_rx/P ------ (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) where P is the total power in the filter states.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) The Boffins have shown that if we obey (1) we converge
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) quickly and avoid instability.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) The correct factor f must be in Q30, as this is the fixed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) point format required by the lms_adapt_bg() function,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) therefore the scaled version of (1) is:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) (2^30) * f = (2^30) * Beta * clean_bg_rx/P
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) factor = (2^30) * Beta * clean_bg_rx/P ----- (2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) We have chosen Beta = 0.25 by experiment, so:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) factor = (2^30) * (2^-2) * clean_bg_rx/P
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) (30 - 2 - log2(P))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) factor = clean_bg_rx 2 ----- (3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) To avoid a divide we approximate log2(P) as top_bit(P),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) which returns the position of the highest non-zero bit in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) P. This approximation introduces an error as large as a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) factor of 2, but the algorithm seems to handle it OK.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) Come to think of it a divide may not be a big deal on a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) modern DSP, so its probably worth checking out the cycles
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) for a divide versus a top_bit() implementation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) p = MIN_TX_POWER_FOR_ADAPTION + ec->pstates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) logp = top_bit(p) + ec->log2taps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) shift = 30 - 2 - logp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) ec->shift = shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) lms_adapt_bg(ec, clean_bg, shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) /* very simple DTD to make sure we dont try and adapt with strong
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) near end speech */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) ec->adapt = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if ((ec->lrx > MIN_RX_POWER_FOR_ADAPTION) && (ec->lrx > ec->ltx))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) ec->nonupdate_dwell = DTD_HANGOVER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) if (ec->nonupdate_dwell)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) ec->nonupdate_dwell--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) /* Transfer logic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /* These conditions are from the dual path paper [1], I messed with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) them a bit to improve performance. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) (ec->nonupdate_dwell == 0) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) /* (ec->Lclean_bg < 0.875*ec->Lclean) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) (8 * ec->lclean_bg < 7 * ec->lclean) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) /* (ec->Lclean_bg < 0.125*ec->Ltx) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) (8 * ec->lclean_bg < ec->ltx)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (ec->cond_met == 6) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * BG filter has had better results for 6 consecutive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * samples
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) ec->adapt = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) memcpy(ec->fir_taps16[0], ec->fir_taps16[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) ec->taps * sizeof(int16_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) ec->cond_met++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) ec->cond_met = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) /* Non-Linear Processing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) ec->clean_nlp = ec->clean;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if (ec->adaption_mode & ECHO_CAN_USE_NLP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) * Non-linear processor - a fancy way to say "zap small
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) * signals, to avoid residual echo due to (uLaw/ALaw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) * non-linearity in the channel.".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if ((16 * ec->lclean < ec->ltx)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) * Our e/c has improved echo by at least 24 dB (each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) * factor of 2 is 6dB, so 2*2*2*2=16 is the same as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) * 6+6+6+6=24dB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) if (ec->adaption_mode & ECHO_CAN_USE_CNG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) ec->cng_level = ec->lbgn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) * Very elementary comfort noise generation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) * Just random numbers rolled off very vaguely
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) * Hoth-like. DR: This noise doesn't sound
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) * quite right to me - I suspect there are some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) * overflow issues in the filtering as it's too
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) * "crackly".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) * TODO: debug this, maybe just play noise at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) * high level or look at spectrum.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) ec->cng_rndnum =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 1664525U * ec->cng_rndnum + 1013904223U;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) ec->cng_filter =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) ((ec->cng_rndnum & 0xFFFF) - 32768 +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 5 * ec->cng_filter) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) ec->clean_nlp =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) (ec->cng_filter * ec->cng_level * 8) >> 14;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) } else if (ec->adaption_mode & ECHO_CAN_USE_CLIP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) /* This sounds much better than CNG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (ec->clean_nlp > ec->lbgn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) ec->clean_nlp = ec->lbgn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (ec->clean_nlp < -ec->lbgn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) ec->clean_nlp = -ec->lbgn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) * just mute the residual, doesn't sound very
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) * good, used mainly in G168 tests
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) ec->clean_nlp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) * Background noise estimator. I tried a few
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) * algorithms here without much luck. This very simple
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) * one seems to work best, we just average the level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) * using a slow (1 sec time const) filter if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) * current level is less than a (experimentally
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) * derived) constant. This means we dont include high
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) * level signals like near end speech. When combined
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) * with CNG or especially CLIP seems to work OK.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) if (ec->lclean < 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) ec->lbgn_acc += abs(ec->clean) - ec->lbgn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) ec->lbgn = (ec->lbgn_acc + (1 << 11)) >> 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /* Roll around the taps buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (ec->curr_pos <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) ec->curr_pos = ec->taps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) ec->curr_pos--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) if (ec->adaption_mode & ECHO_CAN_DISABLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) ec->clean_nlp = rx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) /* Output scaled back up again to match input scaling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) return (int16_t) ec->clean_nlp << 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) EXPORT_SYMBOL_GPL(oslec_update);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) /* This function is separated from the echo canceller is it is usually called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) as part of the tx process. See rx HP (DC blocking) filter above, it's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) the same design.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) Some soft phones send speech signals with a lot of low frequency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) energy, e.g. down to 20Hz. This can make the hybrid non-linear
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) which causes the echo canceller to fall over. This filter can help
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) by removing any low frequency before it gets to the tx port of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) hybrid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) It can also help by removing and DC in the tx signal. DC is bad
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) for LMS algorithms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) This is one of the classic DC removal filters, adjusted to provide
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) sufficient bass rolloff to meet the above requirement to protect hybrids
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) from things that upset them. The difference between successive samples
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) produces a lousy HPF, and then a suitably placed pole flattens things out.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) The final result is a nicely rolled off bass end. The filtering is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) implemented with extended fractional precision, which noise shapes things,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) giving very clean DC removal.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) int16_t oslec_hpf_tx(struct oslec_state *ec, int16_t tx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) int tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) int tmp1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) tmp = tx << 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * Make sure the gain of the HPF is 1.0. The first can still
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) * saturate a little under impulse conditions, and it might
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) * roll to 32768 and need clipping on sustained peak level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * signals. However, the scale of such clipping is small, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) * the error due to any saturation should not markedly affect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) * the downstream processing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) tmp -= (tmp >> 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) ec->tx_1 += -(ec->tx_1 >> DC_LOG2BETA) + tmp - ec->tx_2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) tmp1 = ec->tx_1 >> 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (tmp1 > 32767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) tmp1 = 32767;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (tmp1 < -32767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) tmp1 = -32767;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) tx = tmp1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) ec->tx_2 = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return tx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) EXPORT_SYMBOL_GPL(oslec_hpf_tx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) MODULE_AUTHOR("David Rowe");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) MODULE_DESCRIPTION("Open Source Line Echo Canceller");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) MODULE_VERSION("0.3.0");