Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/bell_r2_mf.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 15:50:58 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * bell_r2_mf.c - Bell MF and MFC/R2 tone generation and detection. | |
5 * | |
6 * Written by Steve Underwood <steveu@coppice.org> | |
7 * | |
8 * Copyright (C) 2001 Steve Underwood | |
9 * | |
10 * All rights reserved. | |
11 * | |
12 * This program is free software; you can redistribute it and/or modify | |
13 * it under the terms of the GNU Lesser General Public License version 2.1, | |
14 * as published by the Free Software Foundation. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU Lesser General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU Lesser General Public | |
22 * License along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 * | |
25 * $Id: bell_r2_mf.c,v 1.39.4.1 2009/12/23 14:23:48 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \file */ | |
29 | |
30 #if defined(HAVE_CONFIG_H) | |
31 #include "config.h" | |
32 #endif | |
33 | |
34 #include <stdlib.h> | |
35 #include <inttypes.h> | |
36 #include <string.h> | |
37 #include <time.h> | |
38 #include <fcntl.h> | |
39 #if defined(HAVE_TGMATH_H) | |
40 #include <tgmath.h> | |
41 #endif | |
42 #if defined(HAVE_MATH_H) | |
43 #include <math.h> | |
44 #endif | |
45 #include "floating_fudge.h" | |
46 | |
47 #include "spandsp/telephony.h" | |
48 #include "spandsp/fast_convert.h" | |
49 #include "spandsp/queue.h" | |
50 #include "spandsp/dc_restore.h" | |
51 #include "spandsp/complex.h" | |
52 #include "spandsp/dds.h" | |
53 #include "spandsp/tone_detect.h" | |
54 #include "spandsp/tone_generate.h" | |
55 #include "spandsp/super_tone_rx.h" | |
56 #include "spandsp/dtmf.h" | |
57 #include "spandsp/bell_r2_mf.h" | |
58 | |
59 #include "spandsp/private/queue.h" | |
60 #include "spandsp/private/tone_generate.h" | |
61 #include "spandsp/private/bell_r2_mf.h" | |
62 | |
63 #if !defined(M_PI) | |
64 /* C99 systems may not define M_PI */ | |
65 #define M_PI 3.14159265358979323846264338327 | |
66 #endif | |
67 | |
68 /*! | |
69 MF tone descriptor. | |
70 */ | |
71 typedef struct | |
72 { | |
73 int f1; /* First freq */ | |
74 int f2; /* Second freq */ | |
75 int8_t level1; /* Level of the first freq (dB) */ | |
76 int8_t level2; /* Level of the second freq (dB) */ | |
77 uint8_t on_time; /* Tone on time (ms) */ | |
78 uint8_t off_time; /* Minimum post tone silence (ms) */ | |
79 } mf_digit_tones_t; | |
80 | |
81 int bell_mf_gen_inited = FALSE; | |
82 tone_gen_descriptor_t bell_mf_digit_tones[15]; | |
83 | |
84 int r2_mf_gen_inited = FALSE; | |
85 tone_gen_descriptor_t r2_mf_fwd_digit_tones[15]; | |
86 tone_gen_descriptor_t r2_mf_back_digit_tones[15]; | |
87 | |
88 #if 0 | |
89 tone_gen_descriptor_t socotel_mf_digit_tones[18]; | |
90 #endif | |
91 | |
92 /* Bell R1 tone generation specs. | |
93 * Power: -7dBm +- 1dB | |
94 * Frequency: within +-1.5% | |
95 * Mismatch between the start time of a pair of tones: <=6ms. | |
96 * Mismatch between the end time of a pair of tones: <=6ms. | |
97 * Tone duration: 68+-7ms, except KP which is 100+-7ms. | |
98 * Inter-tone gap: 68+-7ms. | |
99 */ | |
100 static const mf_digit_tones_t bell_mf_tones[] = | |
101 { | |
102 { 700, 900, -7, -7, 68, 68}, | |
103 { 700, 1100, -7, -7, 68, 68}, | |
104 { 900, 1100, -7, -7, 68, 68}, | |
105 { 700, 1300, -7, -7, 68, 68}, | |
106 { 900, 1300, -7, -7, 68, 68}, | |
107 {1100, 1300, -7, -7, 68, 68}, | |
108 { 700, 1500, -7, -7, 68, 68}, | |
109 { 900, 1500, -7, -7, 68, 68}, | |
110 {1100, 1500, -7, -7, 68, 68}, | |
111 {1300, 1500, -7, -7, 68, 68}, | |
112 { 700, 1700, -7, -7, 68, 68}, /* ST''' - use 'C' */ | |
113 { 900, 1700, -7, -7, 68, 68}, /* ST' - use 'A' */ | |
114 {1100, 1700, -7, -7, 100, 68}, /* KP - use '*' */ | |
115 {1300, 1700, -7, -7, 68, 68}, /* ST'' - use 'B' */ | |
116 {1500, 1700, -7, -7, 68, 68}, /* ST - use '#' */ | |
117 {0, 0, 0, 0, 0, 0} | |
118 }; | |
119 | |
120 /* The order of the digits here must match the list above */ | |
121 static const char bell_mf_tone_codes[] = "1234567890CA*B#"; | |
122 | |
123 /* R2 tone generation specs. | |
124 * Power: -11.5dBm +- 1dB | |
125 * Frequency: within +-4Hz | |
126 * Mismatch between the start time of a pair of tones: <=1ms. | |
127 * Mismatch between the end time of a pair of tones: <=1ms. | |
128 */ | |
129 static const mf_digit_tones_t r2_mf_fwd_tones[] = | |
130 { | |
131 {1380, 1500, -11, -11, 1, 0}, | |
132 {1380, 1620, -11, -11, 1, 0}, | |
133 {1500, 1620, -11, -11, 1, 0}, | |
134 {1380, 1740, -11, -11, 1, 0}, | |
135 {1500, 1740, -11, -11, 1, 0}, | |
136 {1620, 1740, -11, -11, 1, 0}, | |
137 {1380, 1860, -11, -11, 1, 0}, | |
138 {1500, 1860, -11, -11, 1, 0}, | |
139 {1620, 1860, -11, -11, 1, 0}, | |
140 {1740, 1860, -11, -11, 1, 0}, | |
141 {1380, 1980, -11, -11, 1, 0}, | |
142 {1500, 1980, -11, -11, 1, 0}, | |
143 {1620, 1980, -11, -11, 1, 0}, | |
144 {1740, 1980, -11, -11, 1, 0}, | |
145 {1860, 1980, -11, -11, 1, 0}, | |
146 {0, 0, 0, 0, 0, 0} | |
147 }; | |
148 | |
149 static const mf_digit_tones_t r2_mf_back_tones[] = | |
150 { | |
151 {1140, 1020, -11, -11, 1, 0}, | |
152 {1140, 900, -11, -11, 1, 0}, | |
153 {1020, 900, -11, -11, 1, 0}, | |
154 {1140, 780, -11, -11, 1, 0}, | |
155 {1020, 780, -11, -11, 1, 0}, | |
156 { 900, 780, -11, -11, 1, 0}, | |
157 {1140, 660, -11, -11, 1, 0}, | |
158 {1020, 660, -11, -11, 1, 0}, | |
159 { 900, 660, -11, -11, 1, 0}, | |
160 { 780, 660, -11, -11, 1, 0}, | |
161 {1140, 540, -11, -11, 1, 0}, | |
162 {1020, 540, -11, -11, 1, 0}, | |
163 { 900, 540, -11, -11, 1, 0}, | |
164 { 780, 540, -11, -11, 1, 0}, | |
165 { 660, 540, -11, -11, 1, 0}, | |
166 {0, 0, 0, 0, 0, 0} | |
167 }; | |
168 | |
169 /* The order of the digits here must match the lists above */ | |
170 static const char r2_mf_tone_codes[] = "1234567890BCDEF"; | |
171 | |
172 #if 0 | |
173 static const mf_digit_tones_t socotel_tones[] = | |
174 { | |
175 { 700, 900, -11, -11, 1, 0}, | |
176 { 700, 1100, -11, -11, 1, 0}, | |
177 { 900, 1100, -11, -11, 1, 0}, | |
178 { 700, 1300, -11, -11, 1, 0}, | |
179 { 900, 1300, -11, -11, 1, 0}, | |
180 {1100, 1300, -11, -11, 1, 0}, | |
181 { 700, 1500, -11, -11, 1, 0}, | |
182 { 900, 1500, -11, -11, 1, 0}, | |
183 {1100, 1500, -11, -11, 1, 0}, | |
184 {1300, 1500, -11, -11, 1, 0}, | |
185 {1500, 1700, -11, -11, 1, 0}, | |
186 { 700, 1700, -11, -11, 1, 0}, | |
187 { 900, 1700, -11, -11, 1, 0}, | |
188 {1300, 1700, -11, -11, 1, 0}, | |
189 {1100, 1700, -11, -11, 1, 0}, | |
190 {1700, 0, -11, -11, 1, 0}, /* Use 'F' */ | |
191 {1900, 0, -11, -11, 1, 0}, /* Use 'G' */ | |
192 {0, 0, 0, 0, 0, 0} | |
193 }; | |
194 | |
195 /* The order of the digits here must match the list above */ | |
196 static char socotel_mf_tone_codes[] = "1234567890ABCDEFG"; | |
197 #endif | |
198 | |
199 #if defined(SPANDSP_USE_FIXED_POINT) | |
200 #define BELL_MF_THRESHOLD 204089 /* -30.5dBm0 */ | |
201 #define BELL_MF_TWIST 3.981f /* 6dB */ | |
202 #define BELL_MF_RELATIVE_PEAK 12.589f /* 11dB */ | |
203 #define BELL_MF_SAMPLES_PER_BLOCK 120 | |
204 | |
205 #define R2_MF_THRESHOLD 62974 /* -36.5dBm0 */ | |
206 #define R2_MF_TWIST 5.012f /* 7dB */ | |
207 #define R2_MF_RELATIVE_PEAK 12.589f /* 11dB */ | |
208 #define R2_MF_SAMPLES_PER_BLOCK 133 | |
209 #else | |
210 #define BELL_MF_THRESHOLD 3343803100.0f /* -30.5dBm0 [((120.0*32768.0/1.4142)*10^((-30.5 - DBM0_MAX_SINE_POWER)/20.0))^2 => 3343803100.0] */ | |
211 #define BELL_MF_TWIST 3.981f /* 6dB [10^(6/10) => 3.981] */ | |
212 #define BELL_MF_RELATIVE_PEAK 12.589f /* 11dB */ | |
213 #define BELL_MF_SAMPLES_PER_BLOCK 120 | |
214 | |
215 #define R2_MF_THRESHOLD 1031766650.0f /* -36.5dBm0 [((133.0*32768.0/1.4142)*10^((-36.5 - DBM0_MAX_SINE_POWER)/20.0))^2 => 1031766650.0] */ | |
216 #define R2_MF_TWIST 5.012f /* 7dB */ | |
217 #define R2_MF_RELATIVE_PEAK 12.589f /* 11dB */ | |
218 #define R2_MF_SAMPLES_PER_BLOCK 133 | |
219 #endif | |
220 | |
221 static goertzel_descriptor_t bell_mf_detect_desc[6]; | |
222 | |
223 static goertzel_descriptor_t mf_fwd_detect_desc[6]; | |
224 static goertzel_descriptor_t mf_back_detect_desc[6]; | |
225 | |
226 static const int bell_mf_frequencies[] = | |
227 { | |
228 700, 900, 1100, 1300, 1500, 1700 | |
229 }; | |
230 | |
231 /* Use the follow characters for the Bell MF special signals: | |
232 KP - use '*' | |
233 ST - use '#' | |
234 ST' - use 'A' | |
235 ST'' - use 'B' | |
236 ST''' - use 'C' */ | |
237 static const char bell_mf_positions[] = "1247C-358A--69*---0B----#"; | |
238 | |
239 static const int r2_mf_fwd_frequencies[] = | |
240 { | |
241 1380, 1500, 1620, 1740, 1860, 1980 | |
242 }; | |
243 | |
244 static const int r2_mf_back_frequencies[] = | |
245 { | |
246 1140, 1020, 900, 780, 660, 540 | |
247 }; | |
248 | |
249 /* Use codes '1' to 'F' for the R2 signals 1 to 15, except for signal 'A'. | |
250 Use '0' for this, so the codes match the digits 0-9. */ | |
251 static const char r2_mf_positions[] = "1247B-358C--69D---0E----F"; | |
252 | |
253 static void bell_mf_gen_init(void) | |
254 { | |
255 int i; | |
256 const mf_digit_tones_t *tones; | |
257 | |
258 if (bell_mf_gen_inited) | |
259 return; | |
260 i = 0; | |
261 tones = bell_mf_tones; | |
262 while (tones->on_time) | |
263 { | |
264 /* Note: The duration of KP is longer than the other signals. */ | |
265 make_tone_gen_descriptor(&bell_mf_digit_tones[i++], | |
266 tones->f1, | |
267 tones->level1, | |
268 tones->f2, | |
269 tones->level2, | |
270 tones->on_time, | |
271 tones->off_time, | |
272 0, | |
273 0, | |
274 FALSE); | |
275 tones++; | |
276 } | |
277 bell_mf_gen_inited = TRUE; | |
278 } | |
279 /*- End of function --------------------------------------------------------*/ | |
280 | |
281 SPAN_DECLARE(int) bell_mf_tx(bell_mf_tx_state_t *s, int16_t amp[], int max_samples) | |
282 { | |
283 int len; | |
284 const char *cp; | |
285 int digit; | |
286 | |
287 len = 0; | |
288 if (s->tones.current_section >= 0) | |
289 { | |
290 /* Deal with the fragment left over from last time */ | |
291 len = tone_gen(&(s->tones), amp, max_samples); | |
292 } | |
293 while (len < max_samples && (digit = queue_read_byte(&s->queue.queue)) >= 0) | |
294 { | |
295 /* Step to the next digit */ | |
296 if ((cp = strchr(bell_mf_tone_codes, digit)) == NULL) | |
297 continue; | |
298 tone_gen_init(&(s->tones), &bell_mf_digit_tones[cp - bell_mf_tone_codes]); | |
299 len += tone_gen(&(s->tones), amp + len, max_samples - len); | |
300 } | |
301 return len; | |
302 } | |
303 /*- End of function --------------------------------------------------------*/ | |
304 | |
305 SPAN_DECLARE(int) bell_mf_tx_put(bell_mf_tx_state_t *s, const char *digits, int len) | |
306 { | |
307 size_t space; | |
308 | |
309 /* This returns the number of characters that would not fit in the buffer. | |
310 The buffer will only be loaded if the whole string of digits will fit, | |
311 in which case zero is returned. */ | |
312 if (len < 0) | |
313 { | |
314 if ((len = strlen(digits)) == 0) | |
315 return 0; | |
316 } | |
317 if ((space = queue_free_space(&s->queue.queue)) < (size_t) len) | |
318 return len - (int) space; | |
319 if (queue_write(&s->queue.queue, (const uint8_t *) digits, len) >= 0) | |
320 return 0; | |
321 return -1; | |
322 } | |
323 /*- End of function --------------------------------------------------------*/ | |
324 | |
325 SPAN_DECLARE(bell_mf_tx_state_t *) bell_mf_tx_init(bell_mf_tx_state_t *s) | |
326 { | |
327 if (s == NULL) | |
328 { | |
329 if ((s = (bell_mf_tx_state_t *) malloc(sizeof(*s))) == NULL) | |
330 return NULL; | |
331 } | |
332 memset(s, 0, sizeof(*s)); | |
333 | |
334 if (!bell_mf_gen_inited) | |
335 bell_mf_gen_init(); | |
336 tone_gen_init(&(s->tones), &bell_mf_digit_tones[0]); | |
337 s->current_sample = 0; | |
338 queue_init(&s->queue.queue, MAX_BELL_MF_DIGITS, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC); | |
339 s->tones.current_section = -1; | |
340 return s; | |
341 } | |
342 /*- End of function --------------------------------------------------------*/ | |
343 | |
344 SPAN_DECLARE(int) bell_mf_tx_release(bell_mf_tx_state_t *s) | |
345 { | |
346 return 0; | |
347 } | |
348 /*- End of function --------------------------------------------------------*/ | |
349 | |
350 SPAN_DECLARE(int) bell_mf_tx_free(bell_mf_tx_state_t *s) | |
351 { | |
352 free(s); | |
353 return 0; | |
354 } | |
355 /*- End of function --------------------------------------------------------*/ | |
356 | |
357 SPAN_DECLARE(int) r2_mf_tx(r2_mf_tx_state_t *s, int16_t amp[], int samples) | |
358 { | |
359 int len; | |
360 | |
361 if (s->digit == 0) | |
362 { | |
363 len = samples; | |
364 memset(amp, 0, len*sizeof(int16_t)); | |
365 } | |
366 else | |
367 { | |
368 len = tone_gen(&s->tone, amp, samples); | |
369 } | |
370 return len; | |
371 } | |
372 /*- End of function --------------------------------------------------------*/ | |
373 | |
374 SPAN_DECLARE(int) r2_mf_tx_put(r2_mf_tx_state_t *s, char digit) | |
375 { | |
376 char *cp; | |
377 | |
378 if (digit && (cp = strchr(r2_mf_tone_codes, digit))) | |
379 { | |
380 if (s->fwd) | |
381 tone_gen_init(&s->tone, &r2_mf_fwd_digit_tones[cp - r2_mf_tone_codes]); | |
382 else | |
383 tone_gen_init(&s->tone, &r2_mf_back_digit_tones[cp - r2_mf_tone_codes]); | |
384 s->digit = digit; | |
385 } | |
386 else | |
387 { | |
388 s->digit = 0; | |
389 } | |
390 return 0; | |
391 } | |
392 /*- End of function --------------------------------------------------------*/ | |
393 | |
394 SPAN_DECLARE(r2_mf_tx_state_t *) r2_mf_tx_init(r2_mf_tx_state_t *s, int fwd) | |
395 { | |
396 int i; | |
397 const mf_digit_tones_t *tones; | |
398 | |
399 if (s == NULL) | |
400 { | |
401 if ((s = (r2_mf_tx_state_t *) malloc(sizeof(*s))) == NULL) | |
402 return NULL; | |
403 } | |
404 memset(s, 0, sizeof(*s)); | |
405 | |
406 if (!r2_mf_gen_inited) | |
407 { | |
408 i = 0; | |
409 tones = r2_mf_fwd_tones; | |
410 while (tones->on_time) | |
411 { | |
412 make_tone_gen_descriptor(&r2_mf_fwd_digit_tones[i++], | |
413 tones->f1, | |
414 tones->level1, | |
415 tones->f2, | |
416 tones->level2, | |
417 tones->on_time, | |
418 tones->off_time, | |
419 0, | |
420 0, | |
421 (tones->off_time == 0)); | |
422 tones++; | |
423 } | |
424 i = 0; | |
425 tones = r2_mf_back_tones; | |
426 while (tones->on_time) | |
427 { | |
428 make_tone_gen_descriptor(&r2_mf_back_digit_tones[i++], | |
429 tones->f1, | |
430 tones->level1, | |
431 tones->f2, | |
432 tones->level2, | |
433 tones->on_time, | |
434 tones->off_time, | |
435 0, | |
436 0, | |
437 (tones->off_time == 0)); | |
438 tones++; | |
439 } | |
440 r2_mf_gen_inited = TRUE; | |
441 } | |
442 s->fwd = fwd; | |
443 return s; | |
444 } | |
445 /*- End of function --------------------------------------------------------*/ | |
446 | |
447 SPAN_DECLARE(int) r2_mf_tx_release(r2_mf_tx_state_t *s) | |
448 { | |
449 return 0; | |
450 } | |
451 /*- End of function --------------------------------------------------------*/ | |
452 | |
453 SPAN_DECLARE(int) r2_mf_tx_free(r2_mf_tx_state_t *s) | |
454 { | |
455 free(s); | |
456 return 0; | |
457 } | |
458 /*- End of function --------------------------------------------------------*/ | |
459 | |
460 SPAN_DECLARE(int) bell_mf_rx(bell_mf_rx_state_t *s, const int16_t amp[], int samples) | |
461 { | |
462 #if defined(SPANDSP_USE_FIXED_POINT) | |
463 int32_t energy[6]; | |
464 int16_t xamp; | |
465 #else | |
466 float energy[6]; | |
467 float xamp; | |
468 #endif | |
469 int i; | |
470 int j; | |
471 int sample; | |
472 int best; | |
473 int second_best; | |
474 int limit; | |
475 uint8_t hit; | |
476 | |
477 hit = 0; | |
478 for (sample = 0; sample < samples; sample = limit) | |
479 { | |
480 if ((samples - sample) >= (BELL_MF_SAMPLES_PER_BLOCK - s->current_sample)) | |
481 limit = sample + (BELL_MF_SAMPLES_PER_BLOCK - s->current_sample); | |
482 else | |
483 limit = samples; | |
484 for (j = sample; j < limit; j++) | |
485 { | |
486 xamp = goertzel_preadjust_amp(amp[j]); | |
487 goertzel_samplex(&s->out[0], xamp); | |
488 goertzel_samplex(&s->out[1], xamp); | |
489 goertzel_samplex(&s->out[2], xamp); | |
490 goertzel_samplex(&s->out[3], xamp); | |
491 goertzel_samplex(&s->out[4], xamp); | |
492 goertzel_samplex(&s->out[5], xamp); | |
493 } | |
494 s->current_sample += (limit - sample); | |
495 if (s->current_sample < BELL_MF_SAMPLES_PER_BLOCK) | |
496 continue; | |
497 | |
498 /* We are at the end of an MF detection block */ | |
499 /* Find the two highest energies. The spec says to look for | |
500 two tones and two tones only. Taking this literally -ie | |
501 only two tones pass the minimum threshold - doesn't work | |
502 well. The sinc function mess, due to rectangular windowing | |
503 ensure that! Find the two highest energies and ensure they | |
504 are considerably stronger than any of the others. */ | |
505 energy[0] = goertzel_result(&s->out[0]); | |
506 energy[1] = goertzel_result(&s->out[1]); | |
507 if (energy[0] > energy[1]) | |
508 { | |
509 best = 0; | |
510 second_best = 1; | |
511 } | |
512 else | |
513 { | |
514 best = 1; | |
515 second_best = 0; | |
516 } | |
517 for (i = 2; i < 6; i++) | |
518 { | |
519 energy[i] = goertzel_result(&s->out[i]); | |
520 if (energy[i] >= energy[best]) | |
521 { | |
522 second_best = best; | |
523 best = i; | |
524 } | |
525 else if (energy[i] >= energy[second_best]) | |
526 { | |
527 second_best = i; | |
528 } | |
529 } | |
530 /* Basic signal level and twist tests */ | |
531 hit = 0; | |
532 if (energy[best] >= BELL_MF_THRESHOLD | |
533 && | |
534 energy[second_best] >= BELL_MF_THRESHOLD | |
535 && | |
536 energy[best] < energy[second_best]*BELL_MF_TWIST | |
537 && | |
538 energy[best]*BELL_MF_TWIST > energy[second_best]) | |
539 { | |
540 /* Relative peak test */ | |
541 hit = 'X'; | |
542 for (i = 0; i < 6; i++) | |
543 { | |
544 if (i != best && i != second_best) | |
545 { | |
546 if (energy[i]*BELL_MF_RELATIVE_PEAK >= energy[second_best]) | |
547 { | |
548 /* The best two are not clearly the best */ | |
549 hit = 0; | |
550 break; | |
551 } | |
552 } | |
553 } | |
554 } | |
555 if (hit) | |
556 { | |
557 /* Get the values into ascending order */ | |
558 if (second_best < best) | |
559 { | |
560 i = best; | |
561 best = second_best; | |
562 second_best = i; | |
563 } | |
564 best = best*5 + second_best - 1; | |
565 hit = bell_mf_positions[best]; | |
566 /* Look for two successive similar results */ | |
567 /* The logic in the next test is: | |
568 For KP we need 4 successive identical clean detects, with | |
569 two blocks of something different preceeding it. For anything | |
570 else we need two successive identical clean detects, with | |
571 two blocks of something different preceeding it. */ | |
572 if (hit == s->hits[4] | |
573 && | |
574 hit == s->hits[3] | |
575 && | |
576 ((hit != '*' && hit != s->hits[2] && hit != s->hits[1]) | |
577 || | |
578 (hit == '*' && hit == s->hits[2] && hit != s->hits[1] && hit != s->hits[0]))) | |
579 { | |
580 if (s->current_digits < MAX_BELL_MF_DIGITS) | |
581 { | |
582 s->digits[s->current_digits++] = (char) hit; | |
583 s->digits[s->current_digits] = '\0'; | |
584 if (s->digits_callback) | |
585 { | |
586 s->digits_callback(s->digits_callback_data, s->digits, s->current_digits); | |
587 s->current_digits = 0; | |
588 } | |
589 } | |
590 else | |
591 { | |
592 s->lost_digits++; | |
593 } | |
594 } | |
595 } | |
596 s->hits[0] = s->hits[1]; | |
597 s->hits[1] = s->hits[2]; | |
598 s->hits[2] = s->hits[3]; | |
599 s->hits[3] = s->hits[4]; | |
600 s->hits[4] = hit; | |
601 s->current_sample = 0; | |
602 } | |
603 if (s->current_digits && s->digits_callback) | |
604 { | |
605 s->digits_callback(s->digits_callback_data, s->digits, s->current_digits); | |
606 s->digits[0] = '\0'; | |
607 s->current_digits = 0; | |
608 } | |
609 return 0; | |
610 } | |
611 /*- End of function --------------------------------------------------------*/ | |
612 | |
613 SPAN_DECLARE(size_t) bell_mf_rx_get(bell_mf_rx_state_t *s, char *buf, int max) | |
614 { | |
615 if (max > s->current_digits) | |
616 max = s->current_digits; | |
617 if (max > 0) | |
618 { | |
619 memcpy(buf, s->digits, max); | |
620 memmove(s->digits, s->digits + max, s->current_digits - max); | |
621 s->current_digits -= max; | |
622 } | |
623 buf[max] = '\0'; | |
624 return max; | |
625 } | |
626 /*- End of function --------------------------------------------------------*/ | |
627 | |
628 SPAN_DECLARE(bell_mf_rx_state_t *) bell_mf_rx_init(bell_mf_rx_state_t *s, | |
629 digits_rx_callback_t callback, | |
630 void *user_data) | |
631 { | |
632 int i; | |
633 static int initialised = FALSE; | |
634 | |
635 if (s == NULL) | |
636 { | |
637 if ((s = (bell_mf_rx_state_t *) malloc(sizeof(*s))) == NULL) | |
638 return NULL; | |
639 } | |
640 memset(s, 0, sizeof(*s)); | |
641 | |
642 if (!initialised) | |
643 { | |
644 for (i = 0; i < 6; i++) | |
645 make_goertzel_descriptor(&bell_mf_detect_desc[i], (float) bell_mf_frequencies[i], BELL_MF_SAMPLES_PER_BLOCK); | |
646 initialised = TRUE; | |
647 } | |
648 s->digits_callback = callback; | |
649 s->digits_callback_data = user_data; | |
650 | |
651 s->hits[0] = | |
652 s->hits[1] = | |
653 s->hits[2] = | |
654 s->hits[3] = | |
655 s->hits[4] = 0; | |
656 | |
657 for (i = 0; i < 6; i++) | |
658 goertzel_init(&s->out[i], &bell_mf_detect_desc[i]); | |
659 s->current_sample = 0; | |
660 s->lost_digits = 0; | |
661 s->current_digits = 0; | |
662 s->digits[0] = '\0'; | |
663 return s; | |
664 } | |
665 /*- End of function --------------------------------------------------------*/ | |
666 | |
667 SPAN_DECLARE(int) bell_mf_rx_release(bell_mf_rx_state_t *s) | |
668 { | |
669 return 0; | |
670 } | |
671 /*- End of function --------------------------------------------------------*/ | |
672 | |
673 SPAN_DECLARE(int) bell_mf_rx_free(bell_mf_rx_state_t *s) | |
674 { | |
675 free(s); | |
676 return 0; | |
677 } | |
678 /*- End of function --------------------------------------------------------*/ | |
679 | |
680 SPAN_DECLARE(int) r2_mf_rx(r2_mf_rx_state_t *s, const int16_t amp[], int samples) | |
681 { | |
682 #if defined(SPANDSP_USE_FIXED_POINT) | |
683 int32_t energy[6]; | |
684 int16_t xamp; | |
685 #else | |
686 float energy[6]; | |
687 float xamp; | |
688 #endif | |
689 int i; | |
690 int j; | |
691 int sample; | |
692 int best; | |
693 int second_best; | |
694 int hit; | |
695 int hit_digit; | |
696 int limit; | |
697 | |
698 hit = 0; | |
699 hit_digit = 0; | |
700 for (sample = 0; sample < samples; sample = limit) | |
701 { | |
702 if ((samples - sample) >= (R2_MF_SAMPLES_PER_BLOCK - s->current_sample)) | |
703 limit = sample + (R2_MF_SAMPLES_PER_BLOCK - s->current_sample); | |
704 else | |
705 limit = samples; | |
706 for (j = sample; j < limit; j++) | |
707 { | |
708 xamp = goertzel_preadjust_amp(amp[j]); | |
709 goertzel_samplex(&s->out[0], xamp); | |
710 goertzel_samplex(&s->out[1], xamp); | |
711 goertzel_samplex(&s->out[2], xamp); | |
712 goertzel_samplex(&s->out[3], xamp); | |
713 goertzel_samplex(&s->out[4], xamp); | |
714 goertzel_samplex(&s->out[5], xamp); | |
715 } | |
716 s->current_sample += (limit - sample); | |
717 if (s->current_sample < R2_MF_SAMPLES_PER_BLOCK) | |
718 continue; | |
719 | |
720 /* We are at the end of an MF detection block */ | |
721 /* Find the two highest energies */ | |
722 energy[0] = goertzel_result(&s->out[0]); | |
723 energy[1] = goertzel_result(&s->out[1]); | |
724 if (energy[0] > energy[1]) | |
725 { | |
726 best = 0; | |
727 second_best = 1; | |
728 } | |
729 else | |
730 { | |
731 best = 1; | |
732 second_best = 0; | |
733 } | |
734 | |
735 for (i = 2; i < 6; i++) | |
736 { | |
737 energy[i] = goertzel_result(&s->out[i]); | |
738 if (energy[i] >= energy[best]) | |
739 { | |
740 second_best = best; | |
741 best = i; | |
742 } | |
743 else if (energy[i] >= energy[second_best]) | |
744 { | |
745 second_best = i; | |
746 } | |
747 } | |
748 /* Basic signal level and twist tests */ | |
749 hit = FALSE; | |
750 if (energy[best] >= R2_MF_THRESHOLD | |
751 && | |
752 energy[second_best] >= R2_MF_THRESHOLD | |
753 && | |
754 energy[best] < energy[second_best]*R2_MF_TWIST | |
755 && | |
756 energy[best]*R2_MF_TWIST > energy[second_best]) | |
757 { | |
758 /* Relative peak test */ | |
759 hit = TRUE; | |
760 for (i = 0; i < 6; i++) | |
761 { | |
762 if (i != best && i != second_best) | |
763 { | |
764 if (energy[i]*R2_MF_RELATIVE_PEAK >= energy[second_best]) | |
765 { | |
766 /* The best two are not clearly the best */ | |
767 hit = FALSE; | |
768 break; | |
769 } | |
770 } | |
771 } | |
772 } | |
773 if (hit) | |
774 { | |
775 /* Get the values into ascending order */ | |
776 if (second_best < best) | |
777 { | |
778 i = best; | |
779 best = second_best; | |
780 second_best = i; | |
781 } | |
782 best = best*5 + second_best - 1; | |
783 hit_digit = r2_mf_positions[best]; | |
784 } | |
785 else | |
786 { | |
787 hit_digit = 0; | |
788 } | |
789 if (s->current_digit != hit_digit && s->callback) | |
790 { | |
791 i = (hit_digit) ? -99 : -10; | |
792 s->callback(s->callback_data, hit_digit, i, 0); | |
793 } | |
794 s->current_digit = hit_digit; | |
795 s->current_sample = 0; | |
796 } | |
797 return 0; | |
798 } | |
799 /*- End of function --------------------------------------------------------*/ | |
800 | |
801 SPAN_DECLARE(int) r2_mf_rx_get(r2_mf_rx_state_t *s) | |
802 { | |
803 return s->current_digit; | |
804 } | |
805 /*- End of function --------------------------------------------------------*/ | |
806 | |
807 SPAN_DECLARE(r2_mf_rx_state_t *) r2_mf_rx_init(r2_mf_rx_state_t *s, | |
808 int fwd, | |
809 tone_report_func_t callback, | |
810 void *user_data) | |
811 { | |
812 int i; | |
813 static int initialised = FALSE; | |
814 | |
815 if (s == NULL) | |
816 { | |
817 if ((s = (r2_mf_rx_state_t *) malloc(sizeof(*s))) == NULL) | |
818 return NULL; | |
819 } | |
820 memset(s, 0, sizeof(*s)); | |
821 | |
822 s->fwd = fwd; | |
823 | |
824 if (!initialised) | |
825 { | |
826 for (i = 0; i < 6; i++) | |
827 { | |
828 make_goertzel_descriptor(&mf_fwd_detect_desc[i], (float) r2_mf_fwd_frequencies[i], R2_MF_SAMPLES_PER_BLOCK); | |
829 make_goertzel_descriptor(&mf_back_detect_desc[i], (float) r2_mf_back_frequencies[i], R2_MF_SAMPLES_PER_BLOCK); | |
830 } | |
831 initialised = TRUE; | |
832 } | |
833 if (fwd) | |
834 { | |
835 for (i = 0; i < 6; i++) | |
836 goertzel_init(&s->out[i], &mf_fwd_detect_desc[i]); | |
837 } | |
838 else | |
839 { | |
840 for (i = 0; i < 6; i++) | |
841 goertzel_init(&s->out[i], &mf_back_detect_desc[i]); | |
842 } | |
843 s->callback = callback; | |
844 s->callback_data = user_data; | |
845 s->current_digit = 0; | |
846 s->current_sample = 0; | |
847 return s; | |
848 } | |
849 /*- End of function --------------------------------------------------------*/ | |
850 | |
851 SPAN_DECLARE(int) r2_mf_rx_release(r2_mf_rx_state_t *s) | |
852 { | |
853 return 0; | |
854 } | |
855 /*- End of function --------------------------------------------------------*/ | |
856 | |
857 SPAN_DECLARE(int) r2_mf_rx_free(r2_mf_rx_state_t *s) | |
858 { | |
859 free(s); | |
860 return 0; | |
861 } | |
862 /*- End of function --------------------------------------------------------*/ | |
863 /*- End of file ------------------------------------------------------------*/ |