Bug Summary

File:src/super_tone_rx.c
Warning:line 323, column 24
The right operand of '>' is a garbage value

Annotated Source Code

1/*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * super_tone_rx.c - Flexible telephony supervisory tone detection.
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2003 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
26/*! \file */
27
28#if defined(HAVE_CONFIG_H1)
29#include "config.h"
30#endif
31
32#include <stdlib.h>
33#include <string.h>
34#include <stdio.h>
35#include <fcntl.h>
36#include <ctype.h>
37#include <time.h>
38#include <inttypes.h>
39#if defined(HAVE_TGMATH_H1)
40#include <tgmath.h>
41#endif
42#if defined(HAVE_MATH_H1)
43#include <math.h>
44#endif
45#include "floating_fudge.h"
46
47#include "spandsp/telephony.h"
48#include "spandsp/alloc.h"
49#include "spandsp/fast_convert.h"
50#include "spandsp/complex.h"
51#include "spandsp/vector_float.h"
52#include "spandsp/complex_vector_float.h"
53#include "spandsp/tone_detect.h"
54#include "spandsp/tone_generate.h"
55#include "spandsp/super_tone_rx.h"
56
57#include "spandsp/private/super_tone_rx.h"
58
59#if defined(SPANDSP_USE_FIXED_POINT)
60#if defined(SPANDSP_USE_INTRINSICS_IN_INITIALIZERS)
61static const int detection_threshold = energy_threshold_dbm0(SUPER_TONE_BINS, -42)(float) (((128)*32768.0f*32768.0f/2.0f)*powf(10.0f, ((-42) - (
3.14f))/10.0f))
;
62static const int tone_twist = 4;
63static const int tone_to_total_energy = SUPER_TONE_BINS128*64;
64#else
65static const int detection_threshold = 16439; /* -42dBm0 */
66static const int tone_twist = 4; /* 6dB */
67static const int tone_to_total_energy = 64; /* -3dB */
68#endif
69#else
70#if defined(SPANDSP_USE_INTRINSICS_IN_INITIALIZERS)
71static const float detection_threshold = energy_threshold_dbm0(SUPER_TONE_BINS, -42)(float) (((128)*32768.0f*32768.0f/2.0f)*powf(10.0f, ((-42) - (
3.14f))/10.0f))
;
72static const float tone_twist = db_to_power_ratio(6.0f)powf(10.0f, (6.0f)/10.0f);
73static const float tone_to_total_energy = SUPER_TONE_BINS128*db_to_power_ratio(-3.0f)powf(10.0f, (-3.0f)/10.0f);
74#else
75static const float detection_threshold = 2104205.6f; /* -42dBm0 */
76static const float tone_twist = 3.981f; /* 6dB */
77static const float tone_to_total_energy = 1.995f; /* 3dB */
78#endif
79#endif
80
81static int add_super_tone_freq(super_tone_rx_descriptor_t *desc, int freq)
82{
83 int i;
84
85 if (freq == 0)
86 return -1;
87 /*endif*/
88 /* Look for an existing frequency */
89 for (i = 0; i < desc->used_frequencies; i++)
90 {
91 if (desc->pitches[i][0] == freq)
92 return desc->pitches[i][1];
93 /*endif*/
94 }
95 /*endfor*/
96 /* Look for an existing tone which is very close. We may need to merge
97 the detectors. */
98 for (i = 0; i < desc->used_frequencies; i++)
99 {
100 if ((desc->pitches[i][0] - 10) <= freq && freq <= (desc->pitches[i][0] + 10))
101 {
102 /* Merge these two */
103 desc->pitches[desc->used_frequencies][0] = freq;
104 desc->pitches[desc->used_frequencies][1] = i;
105 make_goertzel_descriptor(&desc->desc[desc->pitches[i][1]], (float) (freq + desc->pitches[i][0])/2, SUPER_TONE_BINS128);
106 desc->used_frequencies++;
107 return desc->pitches[i][1];
108 }
109 /*endif*/
110 }
111 /*endfor*/
112 desc->pitches[i][0] = freq;
113 desc->pitches[i][1] = desc->monitored_frequencies;
114 if (desc->monitored_frequencies%5 == 0)
115 {
116 desc->desc = (goertzel_descriptor_t *) span_realloc(desc->desc, (desc->monitored_frequencies + 5)*sizeof(goertzel_descriptor_t));
117 }
118 /*endif*/
119 make_goertzel_descriptor(&desc->desc[desc->monitored_frequencies++], (float) freq, SUPER_TONE_BINS128);
120 desc->used_frequencies++;
121 return desc->pitches[i][1];
122}
123/*- End of function --------------------------------------------------------*/
124
125SPAN_DECLARE(int)__attribute__((visibility("default"))) int super_tone_rx_add_tone(super_tone_rx_descriptor_t *desc)
126{
127 if (desc->tones%5 == 0)
128 {
129 desc->tone_list = (super_tone_rx_segment_t **) span_realloc(desc->tone_list, (desc->tones + 5)*sizeof(super_tone_rx_segment_t *));
130 desc->tone_segs = (int *) span_realloc(desc->tone_segs, (desc->tones + 5)*sizeof(int));
131 }
132 /*endif*/
133 desc->tone_list[desc->tones] = NULL((void*)0);
134 desc->tone_segs[desc->tones] = 0;
135 desc->tones++;
136 return desc->tones - 1;
137}
138/*- End of function --------------------------------------------------------*/
139
140SPAN_DECLARE(int)__attribute__((visibility("default"))) int super_tone_rx_add_element(super_tone_rx_descriptor_t *desc,
141 int tone,
142 int f1,
143 int f2,
144 int min,
145 int max)
146{
147 int step;
148
149 step = desc->tone_segs[tone];
150 if (step%5 == 0)
151 {
152 desc->tone_list[tone] = (super_tone_rx_segment_t *) span_realloc(desc->tone_list[tone], (step + 5)*sizeof(super_tone_rx_segment_t));
153 }
154 /*endif*/
155 desc->tone_list[tone][step].f1 = add_super_tone_freq(desc, f1);
156 desc->tone_list[tone][step].f2 = add_super_tone_freq(desc, f2);
157 desc->tone_list[tone][step].min_duration = min*8;
158 desc->tone_list[tone][step].max_duration = (max == 0) ? 0x7FFFFFFF : max*8;
159 desc->tone_segs[tone]++;
160 return step;
161}
162/*- End of function --------------------------------------------------------*/
163
164static int test_cadence(super_tone_rx_segment_t *pattern,
165 int steps,
166 super_tone_rx_segment_t *test,
167 int rotation)
168{
169 int i;
170 int j;
171
172 if (rotation >= 0)
173 {
174 /* Check only for the sustaining of a tone in progress. This means
175 we only need to check each block if the latest step is compatible
176 with the tone template. */
177 j = 0;
178 if (steps < 0)
179 {
180 /* A -ve value for steps indicates we just changed step, and need to
181 check the last one ended within spec. If we don't do this
182 extra test a low duration segment might be accepted as OK. */
183 steps = -steps;
184 j = (rotation + steps - 2)%steps;
185 if (pattern[j].f1 != test[8].f1 || pattern[j].f2 != test[8].f2)
186 return 0;
187 /*endif*/
188 if (pattern[j].min_duration > test[8].min_duration*SUPER_TONE_BINS128
189 ||
190 pattern[j].max_duration < test[8].min_duration*SUPER_TONE_BINS128)
191 {
192 return 0;
193 }
194 /*endif*/
195 }
196 /*endif*/
197 if (steps)
198 j = (rotation + steps - 1)%steps;
199 /*endif*/
200 if (pattern[j].f1 != test[9].f1 || pattern[j].f2 != test[9].f2)
201 return 0;
202 /*endif*/
203 if (pattern[j].max_duration < test[9].min_duration*SUPER_TONE_BINS128)
204 return 0;
205 /*endif*/
206 }
207 else
208 {
209 /* Look for a complete template match. */
210 for (i = 0; i < steps; i++)
211 {
212 j = i + 10 - steps;
213 if (pattern[i].f1 != test[j].f1 || pattern[i].f2 != test[j].f2)
214 return 0;
215 /*endif*/
216 if (pattern[i].min_duration > test[j].min_duration*SUPER_TONE_BINS128
217 ||
218 pattern[i].max_duration < test[j].min_duration*SUPER_TONE_BINS128)
219 {
220 return 0;
221 }
222 /*endif*/
223 }
224 /*endfor*/
225 }
226 /*endif*/
227 return 1;
228}
229/*- End of function --------------------------------------------------------*/
230
231SPAN_DECLARE(super_tone_rx_descriptor_t *)__attribute__((visibility("default"))) super_tone_rx_descriptor_t
*
super_tone_rx_make_descriptor(super_tone_rx_descriptor_t *desc)
232{
233 if (desc == NULL((void*)0))
234 {
235 if ((desc = (super_tone_rx_descriptor_t *) span_alloc(sizeof(*desc))) == NULL((void*)0))
236 return NULL((void*)0);
237 /*endif*/
238 }
239 /*endif*/
240 desc->tone_list = NULL((void*)0);
241 desc->tone_segs = NULL((void*)0);
242
243 desc->used_frequencies = 0;
244 desc->monitored_frequencies = 0;
245 desc->desc = NULL((void*)0);
246 desc->tones = 0;
247 return desc;
248}
249/*- End of function --------------------------------------------------------*/
250
251SPAN_DECLARE(int)__attribute__((visibility("default"))) int super_tone_rx_free_descriptor(super_tone_rx_descriptor_t *desc)
252{
253 int i;
254
255 if (desc)
256 {
257 for (i = 0; i < desc->tones; i++)
258 {
259 if (desc->tone_list[i])
260 span_free(desc->tone_list[i]);
261 /*endif*/
262 }
263 /*endfor*/
264 if (desc->tone_list)
265 span_free(desc->tone_list);
266 /*endif*/
267 if (desc->tone_segs)
268 span_free(desc->tone_segs);
269 /*endif*/
270 if (desc->desc)
271 span_free(desc->desc);
272 /*endif*/
273 span_free(desc);
274 }
275 /*endif*/
276 return 0;
277}
278/*- End of function --------------------------------------------------------*/
279
280SPAN_DECLARE(void)__attribute__((visibility("default"))) void super_tone_rx_tone_callback(super_tone_rx_state_t *s,
281 span_tone_report_func_t callback,
282 void *user_data)
283{
284 s->tone_callback = callback;
285 s->callback_data = user_data;
286}
287/*- End of function --------------------------------------------------------*/
288
289static void super_tone_chunk(super_tone_rx_state_t *s)
290{
291 int i;
292 int j;
293 int k1;
294 int k2;
295#if defined(SPANDSP_USE_FIXED_POINT)
296 int32_t res[SUPER_TONE_BINS128/2];
297#else
298 float res[SUPER_TONE_BINS128/2];
299#endif
300
301 if (s->energy < detection_threshold)
1
Taking false branch
302 {
303 /* The total energy is too low to be considered a tone detection. */
304 k1 = -1;
305 k2 = -1;
306 for (i = 0; i < s->desc->monitored_frequencies; i++)
307 goertzel_reset(&s->state[i]);
308 /*endfor*/
309 }
310 else
311 {
312 if (s->desc->monitored_frequencies < 2)
2
Assuming the condition is false
3
Taking false branch
313 {
314 k1 =
315 k2 = 0;
316 }
317 else
318 {
319 /* Find our two best monitored frequencies, which also have adequate energy. */
320 for (i = 0; i < s->desc->monitored_frequencies; i++)
4
Loop condition is true. Entering loop body
5
Assuming the condition is false
6
Loop condition is false. Execution continues on line 323
321 res[i] = goertzel_result(&s->state[i]);
322 /*endfor*/
323 if (res[0] > res[1])
7
The right operand of '>' is a garbage value
324 {
325 k1 = 0;
326 k2 = 1;
327 }
328 else
329 {
330 k1 = 1;
331 k2 = 0;
332 }
333 /*endif*/
334 for (j = 2; j < s->desc->monitored_frequencies; j++)
335 {
336 if (res[j] >= res[k1])
337 {
338 k2 = k1;
339 k1 = j;
340 }
341 else if (res[j] >= res[k2])
342 {
343 k2 = j;
344 }
345 /*endif*/
346 }
347 /*endfor*/
348 if ((res[k1] + res[k2]) < tone_to_total_energy*s->energy)
349 {
350 k1 = -1;
351 k2 = -1;
352 }
353 else if (res[k1] > tone_twist*res[k2])
354 {
355 k2 = -1;
356 }
357 else if (k2 < k1)
358 {
359 j = k1;
360 k1 = k2;
361 k2 = j;
362 }
363 /*endif*/
364 }
365 /*endif*/
366 }
367 /*endif*/
368 /* See if this differs from last time. */
369 if (k1 != s->segments[10].f1 || k2 != s->segments[10].f2)
370 {
371 /* It is different, but this might just be a transitional quirk, or
372 a one shot hiccup (eg due to noise). Only if this same thing is
373 seen a second time should we change state. */
374 s->segments[10].f1 = k1;
375 s->segments[10].f2 = k2;
376 /* While things are hopping around, consider this a continuance of the
377 previous state. */
378 s->segments[9].min_duration++;
379 }
380 else
381 {
382 if (k1 != s->segments[9].f1 || k2 != s->segments[9].f2)
383 {
384 if (s->detected_tone >= 0)
385 {
386 /* Test for the continuance of the existing tone pattern, based on our new knowledge of an
387 entire segment length. */
388 if (!test_cadence(s->desc->tone_list[s->detected_tone], -s->desc->tone_segs[s->detected_tone], s->segments, s->rotation++))
389 {
390 s->detected_tone = -1;
391 s->tone_callback(s->callback_data, s->detected_tone, -10, 0);
392 }
393 /*endif*/
394 }
395 /*endif*/
396 if (s->segment_callback)
397 {
398 s->segment_callback(s->callback_data,
399 s->segments[9].f1,
400 s->segments[9].f2,
401 s->segments[9].min_duration*SUPER_TONE_BINS128/8);
402 }
403 /*endif*/
404 memmove(&s->segments[0], &s->segments[1], 9*sizeof(s->segments[0]));
405 s->segments[9].f1 = k1;
406 s->segments[9].f2 = k2;
407 s->segments[9].min_duration = 1;
408 }
409 else
410 {
411 /* This is a continuance of the previous state */
412 if (s->detected_tone >= 0)
413 {
414 /* Test for the continuance of the existing tone pattern. We must do this here, so we can sense the
415 discontinuance of the tone on an excessively long segment. */
416 if (!test_cadence(s->desc->tone_list[s->detected_tone], s->desc->tone_segs[s->detected_tone], s->segments, s->rotation))
417 {
418 s->detected_tone = -1;
419 s->tone_callback(s->callback_data, s->detected_tone, -10, 0);
420 }
421 /*endif*/
422 }
423 /*endif*/
424 s->segments[9].min_duration++;
425 }
426 /*endif*/
427 }
428 /*endif*/
429 if (s->detected_tone < 0)
430 {
431 /* Test for the start of any of the monitored tone patterns */
432 for (j = 0; j < s->desc->tones; j++)
433 {
434 if (test_cadence(s->desc->tone_list[j], s->desc->tone_segs[j], s->segments, -1))
435 {
436 s->detected_tone = j;
437 s->rotation = 0;
438 s->tone_callback(s->callback_data, s->detected_tone, -10, 0);
439 break;
440 }
441 /*endif*/
442 }
443 /*endfor*/
444 }
445 /*endif*/
446#if defined(SPANDSP_USE_FIXED_POINT)
447 s->energy = 0;
448#else
449 s->energy = 0.0f;
450#endif
451}
452/*- End of function --------------------------------------------------------*/
453
454SPAN_DECLARE(int)__attribute__((visibility("default"))) int super_tone_rx(super_tone_rx_state_t *s, const int16_t amp[], int samples)
455{
456 int i;
457 int x;
458 int sample;
459#if defined(SPANDSP_USE_FIXED_POINT)
460 int16_t xamp;
461#else
462 float xamp;
463#endif
464
465 x = 0;
466 for (sample = 0; sample < samples; sample += x)
467 {
468 for (i = 0; i < s->desc->monitored_frequencies; i++)
469 x = goertzel_update(&s->state[i], &amp[sample], samples - sample);
470 /*endfor*/
471 for (i = 0; i < x; i++)
472 {
473 xamp = goertzel_preadjust_amp(amp[sample + i])((float) amp[sample + i]);
474#if defined(SPANDSP_USE_FIXED_POINT)
475 s->energy += ((int32_t) xamp*xamp);
476#else
477 s->energy += xamp*xamp;
478#endif
479 }
480 /*endfor*/
481 if (s->state[0].current_sample >= SUPER_TONE_BINS128)
482 {
483 /* We have finished a Goertzel block. */
484 super_tone_chunk(s);
485 }
486 /*endif*/
487 }
488 /*endfor*/
489 return samples;
490}
491/*- End of function --------------------------------------------------------*/
492
493SPAN_DECLARE(int)__attribute__((visibility("default"))) int super_tone_rx_fillin(super_tone_rx_state_t *s, int samples)
494{
495 /* TODO: Roll the detector forward without a state change */
496 return 0;
497}
498/*- End of function --------------------------------------------------------*/
499
500SPAN_DECLARE(void)__attribute__((visibility("default"))) void super_tone_rx_segment_callback(super_tone_rx_state_t *s,
501 tone_segment_func_t callback)
502{
503 s->segment_callback = callback;
504}
505/*- End of function --------------------------------------------------------*/
506
507SPAN_DECLARE(super_tone_rx_state_t *)__attribute__((visibility("default"))) super_tone_rx_state_t * super_tone_rx_init(super_tone_rx_state_t *s,
508 super_tone_rx_descriptor_t *desc,
509 span_tone_report_func_t callback,
510 void *user_data)
511{
512 int i;
513
514 if (desc == NULL((void*)0))
515 return NULL((void*)0);
516 /*endif*/
517 if (callback == NULL((void*)0))
518 return NULL((void*)0);
519 /*endif*/
520 if (s == NULL((void*)0))
521 {
522 if ((s = (super_tone_rx_state_t *) span_alloc(sizeof(*s) + desc->monitored_frequencies*sizeof(goertzel_state_t))) == NULL((void*)0))
523 return NULL((void*)0);
524 /*endif*/
525 }
526 /*endif*/
527
528 for (i = 0; i < 11; i++)
529 {
530 s->segments[i].f1 = -1;
531 s->segments[i].f2 = -1;
532 s->segments[i].min_duration = 0;
533 }
534 /*endfor*/
535 s->segment_callback = NULL((void*)0);
536 s->tone_callback = callback;
537 s->callback_data = user_data;
538 if (desc)
539 s->desc = desc;
540 /*endif*/
541 s->detected_tone = -1;
542#if defined(SPANDSP_USE_FIXED_POINT)
543 s->energy = 0;
544#else
545 s->energy = 0.0f;
546#endif
547 for (i = 0; i < desc->monitored_frequencies; i++)
548 goertzel_init(&s->state[i], &s->desc->desc[i]);
549 /*endfor*/
550 return s;
551}
552/*- End of function --------------------------------------------------------*/
553
554SPAN_DECLARE(int)__attribute__((visibility("default"))) int super_tone_rx_release(super_tone_rx_state_t *s)
555{
556 return 0;
557}
558/*- End of function --------------------------------------------------------*/
559
560SPAN_DECLARE(int)__attribute__((visibility("default"))) int super_tone_rx_free(super_tone_rx_state_t *s)
561{
562 if (s)
563 span_free(s);
564 /*endif*/
565 return 0;
566}
567/*- End of function --------------------------------------------------------*/
568/*- End of file ------------------------------------------------------------*/