18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * SpanDSP - a series of DSP components for telephony
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * ec_disable_detector.h - A detector which should eventually meet the
68c2ecf20Sopenharmony_ci *                         G.164/G.165 requirements for detecting the
78c2ecf20Sopenharmony_ci *                         2100Hz echo cancellor disable tone.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Written by Steve Underwood <steveu@coppice.org>
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Copyright (C) 2001 Steve Underwood
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * All rights reserved.
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "dsp_biquad.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistruct ec_disable_detector_state {
198c2ecf20Sopenharmony_ci	struct biquad2_state notch;
208c2ecf20Sopenharmony_ci	int notch_level;
218c2ecf20Sopenharmony_ci	int channel_level;
228c2ecf20Sopenharmony_ci	int tone_present;
238c2ecf20Sopenharmony_ci	int tone_cycle_duration;
248c2ecf20Sopenharmony_ci	int good_cycles;
258c2ecf20Sopenharmony_ci	int hit;
268c2ecf20Sopenharmony_ci};
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define FALSE 0
308c2ecf20Sopenharmony_ci#define TRUE (!FALSE)
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic inline void
338c2ecf20Sopenharmony_ciecho_can_disable_detector_init(struct ec_disable_detector_state *det)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	/* Elliptic notch */
368c2ecf20Sopenharmony_ci	/* This is actually centred at 2095Hz, but gets the balance we want, due
378c2ecf20Sopenharmony_ci	   to the asymmetric walls of the notch */
388c2ecf20Sopenharmony_ci	biquad2_init(&det->notch,
398c2ecf20Sopenharmony_ci		     (int32_t)(-0.7600000 * 32768.0),
408c2ecf20Sopenharmony_ci		     (int32_t)(-0.1183852 * 32768.0),
418c2ecf20Sopenharmony_ci		     (int32_t)(-0.5104039 * 32768.0),
428c2ecf20Sopenharmony_ci		     (int32_t)(0.1567596 * 32768.0),
438c2ecf20Sopenharmony_ci		     (int32_t)(1.0000000 * 32768.0));
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	det->channel_level = 0;
468c2ecf20Sopenharmony_ci	det->notch_level = 0;
478c2ecf20Sopenharmony_ci	det->tone_present = FALSE;
488c2ecf20Sopenharmony_ci	det->tone_cycle_duration = 0;
498c2ecf20Sopenharmony_ci	det->good_cycles = 0;
508c2ecf20Sopenharmony_ci	det->hit = 0;
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci/*- End of function --------------------------------------------------------*/
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic inline int
558c2ecf20Sopenharmony_ciecho_can_disable_detector_update(struct ec_disable_detector_state *det,
568c2ecf20Sopenharmony_ci				 int16_t amp)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	int16_t notched;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	notched = biquad2(&det->notch, amp);
618c2ecf20Sopenharmony_ci	/* Estimate the overall energy in the channel, and the energy in
628c2ecf20Sopenharmony_ci	   the notch (i.e. overall channel energy - tone energy => noise).
638c2ecf20Sopenharmony_ci	   Use abs instead of multiply for speed (is it really faster?).
648c2ecf20Sopenharmony_ci	   Damp the overall energy a little more for a stable result.
658c2ecf20Sopenharmony_ci	   Damp the notch energy a little less, so we don't damp out the
668c2ecf20Sopenharmony_ci	   blip every time the phase reverses */
678c2ecf20Sopenharmony_ci	det->channel_level += ((abs(amp) - det->channel_level) >> 5);
688c2ecf20Sopenharmony_ci	det->notch_level += ((abs(notched) - det->notch_level) >> 4);
698c2ecf20Sopenharmony_ci	if (det->channel_level > 280) {
708c2ecf20Sopenharmony_ci		/* There is adequate energy in the channel.
718c2ecf20Sopenharmony_ci		   Is it mostly at 2100Hz? */
728c2ecf20Sopenharmony_ci		if (det->notch_level * 6 < det->channel_level) {
738c2ecf20Sopenharmony_ci			/* The notch says yes, so we have the tone. */
748c2ecf20Sopenharmony_ci			if (!det->tone_present) {
758c2ecf20Sopenharmony_ci				/* Do we get a kick every 450+-25ms? */
768c2ecf20Sopenharmony_ci				if (det->tone_cycle_duration >= 425 * 8
778c2ecf20Sopenharmony_ci				    && det->tone_cycle_duration <= 475 * 8) {
788c2ecf20Sopenharmony_ci					det->good_cycles++;
798c2ecf20Sopenharmony_ci					if (det->good_cycles > 2)
808c2ecf20Sopenharmony_ci						det->hit = TRUE;
818c2ecf20Sopenharmony_ci				}
828c2ecf20Sopenharmony_ci				det->tone_cycle_duration = 0;
838c2ecf20Sopenharmony_ci			}
848c2ecf20Sopenharmony_ci			det->tone_present = TRUE;
858c2ecf20Sopenharmony_ci		} else
868c2ecf20Sopenharmony_ci			det->tone_present = FALSE;
878c2ecf20Sopenharmony_ci		det->tone_cycle_duration++;
888c2ecf20Sopenharmony_ci	} else {
898c2ecf20Sopenharmony_ci		det->tone_present = FALSE;
908c2ecf20Sopenharmony_ci		det->tone_cycle_duration = 0;
918c2ecf20Sopenharmony_ci		det->good_cycles = 0;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci	return det->hit;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci/*- End of function --------------------------------------------------------*/
968c2ecf20Sopenharmony_ci/*- End of file ------------------------------------------------------------*/
97