1 /*
2  * libteletone
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is tone_detect.c - General telephony tone detection, and specific detection of DTMF.
18  *
19  *
20  * The Initial Developer of the Original Code is
21  * Stephen Underwood <steveu@coppice.org>
22  * Portions created by the Initial Developer are Copyright (C)
23  * the Initial Developer. All Rights Reserved.
24  *
25  * Contributor(s):
26  *
27  * The the original interface designed by Steve Underwood was preserved to retain
28  *the optimizations when considering DTMF tones though the names were changed in the interest
29  * of namespace.
30  *
31  * Much less efficient expansion interface was added to allow for the detection of
32  * a single arbitrary tone combination which may also exceed 2 simultaneous tones.
33  * (controlled by compile time constant TELETONE_MAX_TONES)
34  *
35  * Copyright (C) 2006 Anthony Minessale II <anthm@freeswitch.org>
36  *
37  *
38  * libteletone_detect.c Tone Detection Code
39  *
40  *
41  *********************************************************************************
42  *
43  * Derived from tone_detect.h - General telephony tone detection, and specific
44  * detection of DTMF.
45  *
46  * Copyright (C) 2001  Steve Underwood <steveu@coppice.org>
47  *
48  * Despite my general liking of the GPL, I place this code in the
49  * public domain for the benefit of all mankind - even the slimy
50  * ones who might try to proprietize my work and use it to my
51  * detriment.
52  *
53  *
54  * Exception:
55  * The author hereby grants the use of this source code under the
56  * following license if and only if the source code is distributed
57  * as part of the OpenZAP or FreeTDM library.	Any use or distribution of this
58  * source code outside the scope of the OpenZAP or FreeTDM library will nullify the
59  * following license and reinact the MPL 1.1 as stated above.
60  *
61  * Copyright (c) 2007, Anthony Minessale II
62  * All rights reserved.
63  *
64  * Redistribution and use in source and binary forms, with or without
65  * modification, are permitted provided that the following conditions
66  * are met:
67  *
68  * * Redistributions of source code must retain the above copyright
69  * notice, this list of conditions and the following disclaimer.
70  *
71  * * Redistributions in binary form must reproduce the above copyright
72  * notice, this list of conditions and the following disclaimer in the
73  * documentation and/or other materials provided with the distribution.
74  *
75  * * Neither the name of the original author; nor the names of any contributors
76  * may be used to endorse or promote products derived from this software
77  * without specific prior written permission.
78  *
79  *
80  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
81  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
82  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
83  * A PARTICULAR PURPOSE ARE DISCLAIMED.	 IN NO EVENT SHALL THE COPYRIGHT OWNER
84  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
85  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
86  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
87  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
88  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
89  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
90  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
91  */
92 
93 #ifndef LIBTELETONE_DETECT_H
94 #define LIBTELETONE_DETECT_H
95 
96 #ifdef __cplusplus
97 extern "C" {
98 #endif
99 #include <libteletone.h>
100 
101 	/*! \file libteletone_detect.h
102 	  \brief Tone Detection Routines
103 
104 	  This module is responsible for tone detection specifics
105 	*/
106 
107 #ifndef FALSE
108 #define FALSE	0
109 #ifndef TRUE
110 #define TRUE	(!FALSE)
111 #endif
112 #endif
113 
114 	/* Basic DTMF specs:
115 	 *
116 	 * Minimum tone on = 40ms
117 	 * Minimum tone off = 50ms
118 	 * Maximum digit rate = 10 per second
119 	 * Normal twist <= 8dB accepted
120 	 * Reverse twist <= 4dB accepted
121 	 * S/N >= 15dB will detect OK
122 	 * Attenuation <= 26dB will detect OK
123 	 * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
124 	 */
125 
126 #define DTMF_THRESHOLD				8.0e7
127 #define DTMF_NORMAL_TWIST			6.3		/* 8dB */
128 #define DTMF_REVERSE_TWIST			2.5		/* 4dB */
129 #define DTMF_RELATIVE_PEAK_ROW		6.3		/* 8dB */
130 #define DTMF_RELATIVE_PEAK_COL		6.3		/* 8dB */
131 #define DTMF_2ND_HARMONIC_ROW		2.5		/* 4dB */
132 #define DTMF_2ND_HARMONIC_COL		63.1	/* 18dB */
133 #define GRID_FACTOR 4
134 #define BLOCK_LEN 102
135 #define M_TWO_PI 2.0*M_PI
136 
137 	typedef enum {
138 		TT_HIT_NONE = 0,
139 		TT_HIT_BEGIN = 1,
140 		TT_HIT_MIDDLE = 2,
141 		TT_HIT_END = 3
142 	} teletone_hit_type_t;
143 
144 
145 	/*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */
146 	typedef struct {
147 		float v2;
148 		float v3;
149 		double fac;
150 	} teletone_goertzel_state_t;
151 
152 	/*! \brief A container for a DTMF detection state.*/
153 	typedef struct {
154 		int hit1;
155 		int hit2;
156 		int hit3;
157 		int hit4;
158 		int dur;
159 		int zc;
160 
161 
162 		teletone_goertzel_state_t row_out[GRID_FACTOR];
163 		teletone_goertzel_state_t col_out[GRID_FACTOR];
164 		teletone_goertzel_state_t row_out2nd[GRID_FACTOR];
165 		teletone_goertzel_state_t col_out2nd[GRID_FACTOR];
166 		float energy;
167 		float lenergy;
168 
169 		int current_sample;
170 		char digit;
171 		int current_digits;
172 		int detected_digits;
173 		int lost_digits;
174 		int digit_hits[16];
175 	} teletone_dtmf_detect_state_t;
176 
177 	/*! \brief An abstraction to store the coefficient of a tone frequency */
178 	typedef struct {
179 		float fac;
180 	} teletone_detection_descriptor_t;
181 
182 	/*! \brief A container for a single multi-tone detection
183 	  TELETONE_MAX_TONES dictates the maximum simultaneous tones that can be present
184 	  in a multi-tone representation.
185 	*/
186 	typedef struct {
187 		int sample_rate;
188 
189 		teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES];
190 		teletone_goertzel_state_t gs[TELETONE_MAX_TONES];
191 		teletone_goertzel_state_t gs2[TELETONE_MAX_TONES];
192 		int tone_count;
193 
194 		float energy;
195 		int current_sample;
196 
197 		int min_samples;
198 		int total_samples;
199 
200 		int positives;
201 		int negatives;
202 		int hits;
203 
204 		int positive_factor;
205 		int negative_factor;
206 		int hit_factor;
207 
208 	} teletone_multi_tone_t;
209 
210 
211 	/*!
212 	  \brief Initilize a multi-frequency tone detector
213 	  \param mt the multi-frequency tone descriptor
214 	  \param map a representation of the multi-frequency tone
215 	*/
216 TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map);
217 
218 	/*!
219 	  \brief Check a sample buffer for the presence of the mulit-frequency tone described by mt
220 	  \param mt the multi-frequency tone descriptor
221 	  \param sample_buffer an array aof 16 bit signed linear samples
222 	  \param samples the number of samples present in sample_buffer
223 	  \return true when the tone was detected or false when it is not
224 	*/
225 TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
226 									int16_t sample_buffer[],
227 									int samples);
228 
229 	/*!
230 	  \brief Initilize a DTMF detection state object
231 	  \param dtmf_detect_state the DTMF detection state to initilize
232 	  \param sample_rate the desired sample rate
233 	*/
234 TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate);
235 
236 	/*!
237 	  \brief Check a sample buffer for the presence of DTMF digits
238 	  \param dtmf_detect_state the detection state object to check
239 	  \param sample_buffer an array aof 16 bit signed linear samples
240 	  \param samples the number of samples present in sample_buffer
241 	  \return true when DTMF was detected or false when it is not
242 	*/
243 TELETONE_API(teletone_hit_type_t) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
244 							  int16_t sample_buffer[],
245 							  int samples);
246 	/*!
247 	  \brief retrieve any collected digits into a string buffer
248 	  \param dtmf_detect_state the detection state object to check
249 	  \param buf the string buffer to write to
250 	  \param max the maximum length of buf
251 	  \return the number of characters written to buf
252 	*/
253 TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state, char *buf, unsigned int *dur);
254 
255 	/*!
256 	  \brief Step through the Goertzel Algorithm for each sample in a buffer
257 	  \param goertzel_state the goertzel state to step the samples through
258 	  \param sample_buffer an array aof 16 bit signed linear samples
259 	  \param samples the number of samples present in sample_buffer
260 	*/
261 TELETONE_API(void) teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
262 								  int16_t sample_buffer[],
263 								  int samples);
264 
265 
266 
267 #ifdef __cplusplus
268 }
269 #endif
270 
271 #endif
272 
273 /* For Emacs:
274  * Local Variables:
275  * mode:c
276  * indent-tabs-mode:t
277  * tab-width:4
278  * c-basic-offset:4
279  * End:
280  * For VIM:
281  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
282  */
283