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