1*74ba9207SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */
2960366cfSKarsten Keil /*
3960366cfSKarsten Keil * SpanDSP - a series of DSP components for telephony
4960366cfSKarsten Keil *
5960366cfSKarsten Keil * ec_disable_detector.h - A detector which should eventually meet the
6960366cfSKarsten Keil * G.164/G.165 requirements for detecting the
7960366cfSKarsten Keil * 2100Hz echo cancellor disable tone.
8960366cfSKarsten Keil *
9960366cfSKarsten Keil * Written by Steve Underwood <steveu@coppice.org>
10960366cfSKarsten Keil *
11960366cfSKarsten Keil * Copyright (C) 2001 Steve Underwood
12960366cfSKarsten Keil *
13960366cfSKarsten Keil * All rights reserved.
14960366cfSKarsten Keil */
15960366cfSKarsten Keil
16960366cfSKarsten Keil #include "dsp_biquad.h"
17960366cfSKarsten Keil
18960366cfSKarsten Keil struct ec_disable_detector_state {
19960366cfSKarsten Keil struct biquad2_state notch;
20960366cfSKarsten Keil int notch_level;
21960366cfSKarsten Keil int channel_level;
22960366cfSKarsten Keil int tone_present;
23960366cfSKarsten Keil int tone_cycle_duration;
24960366cfSKarsten Keil int good_cycles;
25960366cfSKarsten Keil int hit;
26960366cfSKarsten Keil };
27960366cfSKarsten Keil
28960366cfSKarsten Keil
29960366cfSKarsten Keil #define FALSE 0
30960366cfSKarsten Keil #define TRUE (!FALSE)
31960366cfSKarsten Keil
32960366cfSKarsten Keil static inline void
echo_can_disable_detector_init(struct ec_disable_detector_state * det)33960366cfSKarsten Keil echo_can_disable_detector_init(struct ec_disable_detector_state *det)
34960366cfSKarsten Keil {
35960366cfSKarsten Keil /* Elliptic notch */
36960366cfSKarsten Keil /* This is actually centred at 2095Hz, but gets the balance we want, due
37960366cfSKarsten Keil to the asymmetric walls of the notch */
38960366cfSKarsten Keil biquad2_init(&det->notch,
39960366cfSKarsten Keil (int32_t)(-0.7600000 * 32768.0),
40960366cfSKarsten Keil (int32_t)(-0.1183852 * 32768.0),
41960366cfSKarsten Keil (int32_t)(-0.5104039 * 32768.0),
42960366cfSKarsten Keil (int32_t)(0.1567596 * 32768.0),
43960366cfSKarsten Keil (int32_t)(1.0000000 * 32768.0));
44960366cfSKarsten Keil
45960366cfSKarsten Keil det->channel_level = 0;
46960366cfSKarsten Keil det->notch_level = 0;
47960366cfSKarsten Keil det->tone_present = FALSE;
48960366cfSKarsten Keil det->tone_cycle_duration = 0;
49960366cfSKarsten Keil det->good_cycles = 0;
50960366cfSKarsten Keil det->hit = 0;
51960366cfSKarsten Keil }
52960366cfSKarsten Keil /*- End of function --------------------------------------------------------*/
53960366cfSKarsten Keil
54960366cfSKarsten Keil static inline int
echo_can_disable_detector_update(struct ec_disable_detector_state * det,int16_t amp)55960366cfSKarsten Keil echo_can_disable_detector_update(struct ec_disable_detector_state *det,
56960366cfSKarsten Keil int16_t amp)
57960366cfSKarsten Keil {
58960366cfSKarsten Keil int16_t notched;
59960366cfSKarsten Keil
60960366cfSKarsten Keil notched = biquad2(&det->notch, amp);
61960366cfSKarsten Keil /* Estimate the overall energy in the channel, and the energy in
62960366cfSKarsten Keil the notch (i.e. overall channel energy - tone energy => noise).
63960366cfSKarsten Keil Use abs instead of multiply for speed (is it really faster?).
64960366cfSKarsten Keil Damp the overall energy a little more for a stable result.
65960366cfSKarsten Keil Damp the notch energy a little less, so we don't damp out the
66960366cfSKarsten Keil blip every time the phase reverses */
67960366cfSKarsten Keil det->channel_level += ((abs(amp) - det->channel_level) >> 5);
68960366cfSKarsten Keil det->notch_level += ((abs(notched) - det->notch_level) >> 4);
69960366cfSKarsten Keil if (det->channel_level > 280) {
70960366cfSKarsten Keil /* There is adequate energy in the channel.
71960366cfSKarsten Keil Is it mostly at 2100Hz? */
72960366cfSKarsten Keil if (det->notch_level * 6 < det->channel_level) {
73960366cfSKarsten Keil /* The notch says yes, so we have the tone. */
74960366cfSKarsten Keil if (!det->tone_present) {
75960366cfSKarsten Keil /* Do we get a kick every 450+-25ms? */
76960366cfSKarsten Keil if (det->tone_cycle_duration >= 425 * 8
77960366cfSKarsten Keil && det->tone_cycle_duration <= 475 * 8) {
78960366cfSKarsten Keil det->good_cycles++;
79960366cfSKarsten Keil if (det->good_cycles > 2)
80960366cfSKarsten Keil det->hit = TRUE;
81960366cfSKarsten Keil }
82960366cfSKarsten Keil det->tone_cycle_duration = 0;
83960366cfSKarsten Keil }
84960366cfSKarsten Keil det->tone_present = TRUE;
85960366cfSKarsten Keil } else
86960366cfSKarsten Keil det->tone_present = FALSE;
87960366cfSKarsten Keil det->tone_cycle_duration++;
88960366cfSKarsten Keil } else {
89960366cfSKarsten Keil det->tone_present = FALSE;
90960366cfSKarsten Keil det->tone_cycle_duration = 0;
91960366cfSKarsten Keil det->good_cycles = 0;
92960366cfSKarsten Keil }
93960366cfSKarsten Keil return det->hit;
94960366cfSKarsten Keil }
95960366cfSKarsten Keil /*- End of function --------------------------------------------------------*/
96960366cfSKarsten Keil /*- End of file ------------------------------------------------------------*/
97