r2_mf_rx_state_t *r2_mf_rx_init(r2_mf_rx_state_t *s, int fwd) { int i; static int initialised = FALSE; s->fwd = fwd; if (!initialised) { for (i = 0; i < 6; i++) { make_goertzel_descriptor(&mf_fwd_detect_desc[i], r2_mf_fwd_frequencies[i], 133); make_goertzel_descriptor(&mf_back_detect_desc[i], r2_mf_back_frequencies[i], 133); } initialised = TRUE; } if (fwd) { for (i = 0; i < 6; i++) goertzel_init(&s->out[i], &mf_fwd_detect_desc[i]); } else { for (i = 0; i < 6; i++) goertzel_init(&s->out[i], &mf_back_detect_desc[i]); } s->samples = 133; s->current_sample = 0; return s; }
SPAN_DECLARE(ademco_contactid_sender_state_t *) ademco_contactid_sender_init(ademco_contactid_sender_state_t *s, tone_report_func_t callback, void *user_data) { if (s == NULL) { if ((s = (ademco_contactid_sender_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); span_log_init(&s->logging, SPAN_LOG_NONE, NULL); span_log_set_protocol(&s->logging, "Ademco"); if (!tone_rx_init) { make_goertzel_descriptor(&tone_1400_desc, 1400.0f, GOERTZEL_SAMPLES_PER_BLOCK); make_goertzel_descriptor(&tone_2300_desc, 2300.0f, GOERTZEL_SAMPLES_PER_BLOCK); tone_rx_init = true; } goertzel_init(&s->tone_1400, &tone_1400_desc); goertzel_init(&s->tone_2300, &tone_2300_desc); s->current_sample = 0; s->callback = callback; s->callback_user_data = user_data; s->step = 0; s->remaining_samples = ms_to_samples(100); dtmf_tx_init(&s->dtmf, NULL, NULL); /* The specified timing is 50-60ms on, 50-60ms off */ dtmf_tx_set_timing(&s->dtmf, 55, 55); return s; }
TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate) { int i; float theta; dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0; for (i = 0; i < GRID_FACTOR; i++) { theta = (float)(M_TWO_PI*(dtmf_row[i]/(float)sample_rate)); dtmf_detect_row[i].fac = (float)(2.0*cos(theta)); theta = (float)(M_TWO_PI*(dtmf_col[i]/(float)sample_rate)); dtmf_detect_col[i].fac = (float)(2.0*cos(theta)); theta = (float)(M_TWO_PI*(dtmf_row[i]*2.0/(float)sample_rate)); dtmf_detect_row_2nd[i].fac = (float)(2.0*cos(theta)); theta = (float)(M_TWO_PI*(dtmf_col[i]*2.0/(float)sample_rate)); dtmf_detect_col_2nd[i].fac = (float)(2.0*cos(theta)); goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]); goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]); goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]); goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]); dtmf_detect_state->energy = 0.0; } dtmf_detect_state->current_sample = 0; dtmf_detect_state->detected_digits = 0; dtmf_detect_state->lost_digits = 0; dtmf_detect_state->digit = 0; dtmf_detect_state->dur = 0; }
SPAN_DECLARE(dtmf_rx_state_t *) dtmf_rx_init(dtmf_rx_state_t *s, digits_rx_callback_t callback, void *user_data) { int i; static int initialised = FALSE; if (s == NULL) { if ((s = (dtmf_rx_state_t *) malloc(sizeof (*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); span_log_init(&s->logging, SPAN_LOG_NONE, NULL); span_log_set_protocol(&s->logging, "DTMF"); s->digits_callback = callback; s->digits_callback_data = user_data; s->realtime_callback = NULL; s->realtime_callback_data = NULL; s->filter_dialtone = FALSE; s->normal_twist = DTMF_NORMAL_TWIST; s->reverse_twist = DTMF_REVERSE_TWIST; s->threshold = DTMF_THRESHOLD; s->in_digit = 0; s->last_hit = 0; if (!initialised) { for (i = 0; i < 4; i++) { make_goertzel_descriptor(&dtmf_detect_row[i], dtmf_row[i], DTMF_SAMPLES_PER_BLOCK); make_goertzel_descriptor(&dtmf_detect_col[i], dtmf_col[i], DTMF_SAMPLES_PER_BLOCK); } initialised = TRUE; } for (i = 0; i < 4; i++) { goertzel_init(&s->row_out[i], &dtmf_detect_row[i]); goertzel_init(&s->col_out[i], &dtmf_detect_col[i]); } #if defined(SPANDSP_USE_FIXED_POINT) s->energy = 0; #else s->energy = 0.0f; #endif s->current_sample = 0; s->lost_digits = 0; s->current_digits = 0; s->digits[0] = '\0'; return s; }
bell_mf_rx_state_t *bell_mf_rx_init(bell_mf_rx_state_t *s, void (*callback)(void *user_data, const char *digits, int len), void *user_data) { int i; static int initialised = FALSE; if (!initialised) { for (i = 0; i < 6; i++) make_goertzel_descriptor(&bell_mf_detect_desc[i], bell_mf_frequencies[i], 120); initialised = TRUE; } s->callback = callback; s->callback_data = user_data; s->hits[0] = s->hits[1] = s->hits[2] = s->hits[3] = s->hits[4] = 0; for (i = 0; i < 6; i++) goertzel_init(&s->out[i], &bell_mf_detect_desc[i]); s->current_sample = 0; s->lost_digits = 0; s->current_digits = 0; s->digits[0] = '\0'; return s; }
super_tone_rx_state_t *super_tone_rx_init(super_tone_rx_state_t *s, super_tone_rx_descriptor_t *desc, tone_report_func_t callback, void *user_data) { int i; if (desc == NULL) return NULL; if (callback == NULL) return NULL; if (s == NULL) { if ((s = (super_tone_rx_state_t *) malloc(sizeof(*s) + desc->monitored_frequencies*sizeof(goertzel_state_t))) == NULL) return NULL; } for (i = 0; i < 11; i++) { s->segments[i].f1 = -1; s->segments[i].f2 = -1; s->segments[i].min_duration = 0; } s->segment_callback = NULL; s->tone_callback = callback; s->callback_data = user_data; if (desc) s->desc = desc; s->detected_tone = -1; s->energy = 0.0f; for (i = 0; i < desc->monitored_frequencies; i++) goertzel_init(&s->state[i], &s->desc->desc[i]); return s; }
SPAN_DECLARE(r2_mf_rx_state_t *) r2_mf_rx_init(r2_mf_rx_state_t *s, int fwd, tone_report_func_t callback, void *user_data) { int i; static int initialised = FALSE; if (s == NULL) { if ((s = (r2_mf_rx_state_t *) malloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); s->fwd = fwd; if (!initialised) { for (i = 0; i < 6; i++) { make_goertzel_descriptor(&mf_fwd_detect_desc[i], (float) r2_mf_fwd_frequencies[i], R2_MF_SAMPLES_PER_BLOCK); make_goertzel_descriptor(&mf_back_detect_desc[i], (float) r2_mf_back_frequencies[i], R2_MF_SAMPLES_PER_BLOCK); } initialised = TRUE; } if (fwd) { for (i = 0; i < 6; i++) goertzel_init(&s->out[i], &mf_fwd_detect_desc[i]); } else { for (i = 0; i < 6; i++) goertzel_init(&s->out[i], &mf_back_detect_desc[i]); } s->callback = callback; s->callback_data = user_data; s->current_digit = 0; s->current_sample = 0; return s; }
TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map) { float theta = 0; int x = 0; if (!mt->sample_rate) { mt->sample_rate = 8000; } if (!mt->min_samples) { mt->min_samples = 102; } mt->min_samples *= (mt->sample_rate / 8000); if (!mt->positive_factor) { mt->positive_factor = 2; } if(!mt->negative_factor) { mt->negative_factor = 10; } if (!mt->hit_factor) { mt->hit_factor = 2; } for(x = 0; x < TELETONE_MAX_TONES; x++) { if ((int) map->freqs[x] == 0) { break; } mt->tone_count++; theta = (float)(M_TWO_PI*(map->freqs[x]/(float)mt->sample_rate)); mt->tdd[x].fac = (float)(2.0 * cos(theta)); goertzel_init (&mt->gs[x], &mt->tdd[x]); goertzel_init (&mt->gs2[x], &mt->tdd[x]); } }
static void ast_mf_detect_init (mf_detect_state_t *s) { int i; #ifdef OLD_DSP_ROUTINES s->hit1 = s->hit2 = 0; #else s->hits[0] = s->hits[1] = s->hits[2] = s->hits[3] = s->hits[4] = 0; #endif for (i = 0; i < 6; i++) { goertzel_init (&s->tone_out[i], mf_tones[i], 160); #ifdef OLD_DSP_ROUTINES goertzel_init (&s->tone_out2nd[i], mf_tones[i] * 2.0, 160); s->energy = 0.0; #endif } s->current_digits = 0; memset(&s->digits, 0, sizeof(s->digits)); s->current_sample = 0; s->detected_digits = 0; s->lost_digits = 0; s->digits[0] = '\0'; s->mhit = 0; }
SPAN_DECLARE(bell_mf_rx_state_t *) bell_mf_rx_init(bell_mf_rx_state_t *s, digits_rx_callback_t callback, void *user_data) { int i; static int initialised = FALSE; if (s == NULL) { if ((s = (bell_mf_rx_state_t *) malloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); if (!initialised) { for (i = 0; i < 6; i++) make_goertzel_descriptor(&bell_mf_detect_desc[i], (float) bell_mf_frequencies[i], BELL_MF_SAMPLES_PER_BLOCK); initialised = TRUE; } s->digits_callback = callback; s->digits_callback_data = user_data; s->hits[0] = s->hits[1] = s->hits[2] = s->hits[3] = s->hits[4] = 0; for (i = 0; i < 6; i++) goertzel_init(&s->out[i], &bell_mf_detect_desc[i]); s->current_sample = 0; s->lost_digits = 0; s->current_digits = 0; s->digits[0] = '\0'; return s; }
static void ast_dtmf_detect_init (dtmf_detect_state_t *s) { int i; #ifdef OLD_DSP_ROUTINES s->hit1 = s->mhit = s->hit3 = s->hit4 = s->hit2 = 0; #else s->hits[0] = s->hits[1] = s->hits[2] = 0; #endif for (i = 0; i < 4; i++) { goertzel_init (&s->row_out[i], dtmf_row[i], 102); goertzel_init (&s->col_out[i], dtmf_col[i], 102); #ifdef OLD_DSP_ROUTINES goertzel_init (&s->row_out2nd[i], dtmf_row[i] * 2.0, 102); goertzel_init (&s->col_out2nd[i], dtmf_col[i] * 2.0, 102); #endif s->energy = 0.0; } #ifdef FAX_DETECT /* Same for the fax dector */ goertzel_init (&s->fax_tone, fax_freq, 102); #ifdef OLD_DSP_ROUTINES /* Same for the fax dector 2nd harmonic */ goertzel_init (&s->fax_tone2nd, fax_freq * 2.0, 102); #endif #endif /* FAX_DETECT */ s->current_sample = 0; s->detected_digits = 0; s->current_digits = 0; memset(&s->digits, 0, sizeof(s->digits)); s->lost_digits = 0; s->digits[0] = '\0'; }
TELETONE_API(teletone_hit_type_t) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state, int16_t sample_buffer[], int samples) { float row_energy[GRID_FACTOR]; float col_energy[GRID_FACTOR]; float famp; float v1; int i; int j; int sample; int best_row; int best_col; char hit; int limit; teletone_hit_type_t r = 0; hit = 0; for (sample = 0; sample < samples; sample = limit) { /* BLOCK_LEN is optimised to meet the DTMF specs. */ if ((samples - sample) >= (BLOCK_LEN - dtmf_detect_state->current_sample)) { limit = sample + (BLOCK_LEN - dtmf_detect_state->current_sample); } else { limit = samples; } for (j = sample; j < limit; j++) { int x = 0; famp = sample_buffer[j]; dtmf_detect_state->energy += famp*famp; for(x = 0; x < GRID_FACTOR; x++) { v1 = dtmf_detect_state->row_out[x].v2; dtmf_detect_state->row_out[x].v2 = dtmf_detect_state->row_out[x].v3; dtmf_detect_state->row_out[x].v3 = (float)(dtmf_detect_state->row_out[x].fac*dtmf_detect_state->row_out[x].v2 - v1 + famp); v1 = dtmf_detect_state->col_out[x].v2; dtmf_detect_state->col_out[x].v2 = dtmf_detect_state->col_out[x].v3; dtmf_detect_state->col_out[x].v3 = (float)(dtmf_detect_state->col_out[x].fac*dtmf_detect_state->col_out[x].v2 - v1 + famp); v1 = dtmf_detect_state->col_out2nd[x].v2; dtmf_detect_state->col_out2nd[x].v2 = dtmf_detect_state->col_out2nd[x].v3; dtmf_detect_state->col_out2nd[x].v3 = (float)(dtmf_detect_state->col_out2nd[x].fac*dtmf_detect_state->col_out2nd[x].v2 - v1 + famp); v1 = dtmf_detect_state->row_out2nd[x].v2; dtmf_detect_state->row_out2nd[x].v2 = dtmf_detect_state->row_out2nd[x].v3; dtmf_detect_state->row_out2nd[x].v3 = (float)(dtmf_detect_state->row_out2nd[x].fac*dtmf_detect_state->row_out2nd[x].v2 - v1 + famp); } } if (dtmf_detect_state->zc > 0) { if (dtmf_detect_state->energy < LOW_ENG && dtmf_detect_state->lenergy < LOW_ENG) { if (!--dtmf_detect_state->zc) { /* Reinitialise the detector for the next block */ dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0; for (i = 0; i < GRID_FACTOR; i++) { goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]); goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]); goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]); goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]); } dtmf_detect_state->dur -= samples; return TT_HIT_END; } } dtmf_detect_state->dur += samples; dtmf_detect_state->lenergy = dtmf_detect_state->energy; dtmf_detect_state->energy = 0.0; dtmf_detect_state->current_sample = 0; return TT_HIT_MIDDLE; } else if (dtmf_detect_state->digit) { return TT_HIT_END; } dtmf_detect_state->current_sample += (limit - sample); if (dtmf_detect_state->current_sample < BLOCK_LEN) { continue; } /* We are at the end of a DTMF detection block */ /* Find the peak row and the peak column */ row_energy[0] = teletone_goertzel_result (&dtmf_detect_state->row_out[0]); col_energy[0] = teletone_goertzel_result (&dtmf_detect_state->col_out[0]); for (best_row = best_col = 0, i = 1; i < GRID_FACTOR; i++) { row_energy[i] = teletone_goertzel_result (&dtmf_detect_state->row_out[i]); if (row_energy[i] > row_energy[best_row]) { best_row = i; } col_energy[i] = teletone_goertzel_result (&dtmf_detect_state->col_out[i]); if (col_energy[i] > col_energy[best_col]) { best_col = i; } } hit = 0; /* Basic signal level test and the twist test */ if (row_energy[best_row] >= DTMF_THRESHOLD && col_energy[best_col] >= DTMF_THRESHOLD && col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST && col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) { /* Relative peak test */ for (i = 0; i < GRID_FACTOR; i++) { if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) || (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) { break; } } /* ... and second harmonic test */ if (i >= GRID_FACTOR && (row_energy[best_row] + col_energy[best_col]) > 42.0*dtmf_detect_state->energy && teletone_goertzel_result (&dtmf_detect_state->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] && teletone_goertzel_result (&dtmf_detect_state->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) { hit = dtmf_positions[(best_row << 2) + best_col]; /* Look for two successive similar results */ /* The logic in the next test is: We need two successive identical clean detects, with something different preceeding it. This can work with back to back differing digits. More importantly, it can work with nasty phones that give a very wobbly start to a digit. */ if (! r && hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) { dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++; dtmf_detect_state->detected_digits++; if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS) { dtmf_detect_state->digit = hit; } else { dtmf_detect_state->lost_digits++; } if (!dtmf_detect_state->zc) { dtmf_detect_state->zc = ZC; dtmf_detect_state->dur = 0; r = TT_HIT_BEGIN; break; } } } } dtmf_detect_state->hit1 = dtmf_detect_state->hit2; dtmf_detect_state->hit2 = dtmf_detect_state->hit3; dtmf_detect_state->hit3 = hit; dtmf_detect_state->energy = 0.0; dtmf_detect_state->current_sample = 0; } return r; }
TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt, int16_t sample_buffer[], int samples) { int sample, limit = 0, j, x = 0; float v1, famp; float eng_sum = 0, eng_all[TELETONE_MAX_TONES] = {0.0}; int gtest = 0, see_hit = 0; for (sample = 0; sample >= 0 && sample < samples; sample = limit) { mt->total_samples++; if ((samples - sample) >= (mt->min_samples - mt->current_sample)) { limit = sample + (mt->min_samples - mt->current_sample); } else { limit = samples; } if (limit < 0 || limit > samples) { limit = samples; } for (j = sample; j < limit; j++) { famp = sample_buffer[j]; mt->energy += famp*famp; for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) { v1 = mt->gs[x].v2; mt->gs[x].v2 = mt->gs[x].v3; mt->gs[x].v3 = (float)(mt->gs[x].fac * mt->gs[x].v2 - v1 + famp); v1 = mt->gs2[x].v2; mt->gs2[x].v2 = mt->gs2[x].v3; mt->gs2[x].v3 = (float)(mt->gs2[x].fac*mt->gs2[x].v2 - v1 + famp); } } mt->current_sample += (limit - sample); if (mt->current_sample < mt->min_samples) { continue; } eng_sum = 0; for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) { eng_all[x] = (float)(teletone_goertzel_result (&mt->gs[x])); eng_sum += eng_all[x]; } gtest = 0; for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) { gtest += teletone_goertzel_result (&mt->gs2[x]) < eng_all[x] ? 1 : 0; } if ((gtest >= 2 || gtest == mt->tone_count) && eng_sum > 42.0 * mt->energy) { if(mt->negatives) { mt->negatives--; } mt->positives++; if(mt->positives >= mt->positive_factor) { mt->hits++; } if (mt->hits >= mt->hit_factor) { see_hit++; mt->positives = mt->negatives = mt->hits = 0; } } else { mt->negatives++; if(mt->positives) { mt->positives--; } if(mt->negatives > mt->negative_factor) { mt->positives = mt->hits = 0; } } /* Reinitialise the detector for the next block */ for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) { goertzel_init (&mt->gs[x], &mt->tdd[x]); goertzel_init (&mt->gs2[x], &mt->tdd[x]); } mt->energy = 0.0; mt->current_sample = 0; } return see_hit; }