xref: /linux/drivers/isdn/mISDN/dsp_ecdis.h (revision 74ba9207e1adf1966c57450340534ae9742d00af)
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
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
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