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 ------------------------------------------------------------*/ |
