📄 capidtmf.c
字号:
#define CAPIDTMF_RECV_INDICATION_DIGIT 0x0001static long capidtmf_recv_goertzel_coef_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] ={ 0xda97L * 2, /* 697 Hz (Low group 697 Hz) */ 0xd299L * 2, /* 770 Hz (Low group 770 Hz) */ 0xc8cbL * 2, /* 852 Hz (Low group 852 Hz) */ 0xbd36L * 2, /* 941 Hz (Low group 941 Hz) */ 0x9501L * 2, /* 1209 Hz (High group 1209 Hz) */ 0x7f89L * 2, /* 1336 Hz (High group 1336 Hz) */ 0x6639L * 2, /* 1477 Hz (High group 1477 Hz) */ 0x48c6L * 2, /* 1633 Hz (High group 1633 Hz) */ 0xe14cL * 2, /* 630 Hz (Lower guard of low group 631 Hz) */ 0xb2e0L * 2, /* 1015 Hz (Upper guard of low group 1039 Hz) */ 0xa1a0L * 2, /* 1130 Hz (Lower guard of high group 1140 Hz) */ 0x8a87L * 2, /* 1272 Hz (Guard between 1209 Hz and 1336 Hz: 1271 Hz) */ 0x7353L * 2, /* 1405 Hz (2nd harmonics of 697 Hz and guard between 1336 Hz and 1477 Hz: 1405 Hz) */ 0x583bL * 2, /* 1552 Hz (2nd harmonics of 770 Hz and guard between 1477 Hz and 1633 Hz: 1553 Hz) */ 0x37d8L * 2, /* 1720 Hz (2nd harmonics of 852 Hz and upper guard of high group: 1715 Hz) */ 0x0000L * 2 /* 100-630 Hz (fundamentals) */};static word capidtmf_recv_guard_snr_low_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] ={ 14, /* Low group peak versus 697 Hz */ 14, /* Low group peak versus 770 Hz */ 16, /* Low group peak versus 852 Hz */ 16, /* Low group peak versus 941 Hz */ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1209 Hz */ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1336 Hz */ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1477 Hz */ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1633 Hz */ 14, /* Low group peak versus 635 Hz */ 16, /* Low group peak versus 1010 Hz */ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1140 Hz */ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1272 Hz */ DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 8, /* Low group peak versus 1405 Hz */ DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 4, /* Low group peak versus 1555 Hz */ DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 4, /* Low group peak versus 1715 Hz */ 12 /* Low group peak versus 100-630 Hz */};static word capidtmf_recv_guard_snr_high_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] ={ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 697 Hz */ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 770 Hz */ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 852 Hz */ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 941 Hz */ 20, /* High group peak versus 1209 Hz */ 20, /* High group peak versus 1336 Hz */ 20, /* High group peak versus 1477 Hz */ 20, /* High group peak versus 1633 Hz */ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 635 Hz */ CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 1010 Hz */ 16, /* High group peak versus 1140 Hz */ 4, /* High group peak versus 1272 Hz */ 6, /* High group peak versus 1405 Hz */ 8, /* High group peak versus 1555 Hz */ 16, /* High group peak versus 1715 Hz */ 12 /* High group peak versus 100-630 Hz */};/*---------------------------------------------------------------------------*/static void capidtmf_recv_init (t_capidtmf_state *p_state){ p_state->recv.min_gap_duration = 1; p_state->recv.min_digit_duration = 1; p_state->recv.cycle_counter = 0; p_state->recv.current_digit_on_time = 0; p_state->recv.current_digit_off_time = 0; p_state->recv.current_digit_value = CAPIDTMF_RECV_NO_DIGIT; p_state->recv.digit_write_pos = 0; p_state->recv.digit_read_pos = 0; p_state->recv.indication_state = 0; p_state->recv.indication_state_ack = 0; p_state->recv.state = CAPIDTMF_RECV_STATE_IDLE;}void capidtmf_recv_enable (t_capidtmf_state *p_state, word min_digit_duration, word min_gap_duration){ p_state->recv.indication_state_ack &= CAPIDTMF_RECV_INDICATION_DIGIT; p_state->recv.min_digit_duration = (word)(((((dword) min_digit_duration) * 8) + ((dword)(CAPIDTMF_RECV_TIME_GRANULARITY / 2))) / ((dword) CAPIDTMF_RECV_TIME_GRANULARITY)); if (p_state->recv.min_digit_duration <= 1) p_state->recv.min_digit_duration = 1; else (p_state->recv.min_digit_duration)--; p_state->recv.min_gap_duration = (word)((((dword) min_gap_duration) * 8) / ((dword) CAPIDTMF_RECV_TIME_GRANULARITY)); if (p_state->recv.min_gap_duration <= 1) p_state->recv.min_gap_duration = 1; else (p_state->recv.min_gap_duration)--; p_state->recv.state |= CAPIDTMF_RECV_STATE_DTMF_ACTIVE;}void capidtmf_recv_disable (t_capidtmf_state *p_state){ p_state->recv.state &= ~CAPIDTMF_RECV_STATE_DTMF_ACTIVE; if (p_state->recv.state == CAPIDTMF_RECV_STATE_IDLE) capidtmf_recv_init (p_state); else { p_state->recv.cycle_counter = 0; p_state->recv.current_digit_on_time = 0; p_state->recv.current_digit_off_time = 0; p_state->recv.current_digit_value = CAPIDTMF_RECV_NO_DIGIT; }}word capidtmf_recv_indication (t_capidtmf_state *p_state, byte *buffer){ word i, j, k, flags; flags = p_state->recv.indication_state ^ p_state->recv.indication_state_ack; p_state->recv.indication_state_ack ^= flags & CAPIDTMF_RECV_INDICATION_DIGIT; if (p_state->recv.digit_write_pos != p_state->recv.digit_read_pos) { i = 0; k = p_state->recv.digit_write_pos; j = p_state->recv.digit_read_pos; do { buffer[i++] = p_state->recv.digit_buffer[j]; j = (j == CAPIDTMF_RECV_DIGIT_BUFFER_SIZE - 1) ? 0 : j + 1; } while (j != k); p_state->recv.digit_read_pos = k; return (i); } p_state->recv.indication_state_ack ^= flags; return (0);}#define CAPIDTMF_RECV_WINDOWED_SAMPLES 32void capidtmf_recv_block (t_capidtmf_state *p_state, byte *buffer, word length){ byte result_digit; word sample_number, cycle_counter, n, i; word low_peak, high_peak; dword lo, hi; byte *p; short *q; byte goertzel_result_buffer[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT]; short windowed_sample_buffer[CAPIDTMF_RECV_WINDOWED_SAMPLES]; if (p_state->recv.state & CAPIDTMF_RECV_STATE_DTMF_ACTIVE) { cycle_counter = p_state->recv.cycle_counter; sample_number = 0; while (sample_number < length) { if (cycle_counter < CAPIDTMF_RECV_ACCUMULATE_CYCLES) { if (cycle_counter == 0) { for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++) { p_state->recv.goertzel_buffer[0][i] = 0; p_state->recv.goertzel_buffer[1][i] = 0; } } n = CAPIDTMF_RECV_ACCUMULATE_CYCLES - cycle_counter; if (n > length - sample_number) n = length - sample_number; if (n > CAPIDTMF_RECV_WINDOWED_SAMPLES) n = CAPIDTMF_RECV_WINDOWED_SAMPLES; p = buffer + sample_number; q = capidtmf_recv_window_function + cycle_counter; if (p_state->ulaw) { for (i = 0; i < n; i++) { windowed_sample_buffer[i] = (short)((capidtmf_expand_table_ulaw[p[i]] * ((long)(q[i]))) >> 15); } } else { for (i = 0; i < n; i++) { windowed_sample_buffer[i] = (short)((capidtmf_expand_table_alaw[p[i]] * ((long)(q[i]))) >> 15); } } capidtmf_recv_goertzel_coef_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT - 1] = CAPIDTMF_RECV_FUNDAMENTAL_OFFSET; capidtmf_goertzel_loop (p_state->recv.goertzel_buffer[0], capidtmf_recv_goertzel_coef_table, windowed_sample_buffer, n); cycle_counter += n; sample_number += n; } else { capidtmf_goertzel_result (p_state->recv.goertzel_buffer[0], capidtmf_recv_goertzel_coef_table); for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++) { lo = (dword)(p_state->recv.goertzel_buffer[0][i]); hi = (dword)(p_state->recv.goertzel_buffer[1][i]); if (hi != 0) { n = capidtmf_dword_leading_zeroes (hi); hi = (hi << n) | (lo >> (32 - n)); } else { n = capidtmf_dword_leading_zeroes (lo); hi = lo << n; n += 32; } n = 195 - 3 * n; if (hi >= 0xcb300000L) n += 2; else if (hi >= 0xa1450000L) n++; goertzel_result_buffer[i] = (byte) n; } low_peak = DSPDTMF_RX_SENSITIVITY_LOW_DEFAULT; result_digit = CAPIDTMF_RECV_NO_DIGIT; for (i = 0; i < CAPIDTMF_LOW_GROUP_FREQUENCIES; i++) { if (goertzel_result_buffer[i] > low_peak) { low_peak = goertzel_result_buffer[i]; result_digit = (byte) i; } } high_peak = DSPDTMF_RX_SENSITIVITY_HIGH_DEFAULT; n = CAPIDTMF_RECV_NO_DIGIT; for (i = CAPIDTMF_LOW_GROUP_FREQUENCIES; i < CAPIDTMF_RECV_BASE_FREQUENCY_COUNT; i++) { if (goertzel_result_buffer[i] > high_peak) { high_peak = goertzel_result_buffer[i]; n = (i - CAPIDTMF_LOW_GROUP_FREQUENCIES) << 2; } } result_digit |= (byte) n; if (low_peak + DSPDTMF_RX_HIGH_EXCEEDING_LOW_DEFAULT < high_peak) result_digit = CAPIDTMF_RECV_NO_DIGIT; if (high_peak + DSPDTMF_RX_LOW_EXCEEDING_HIGH_DEFAULT < low_peak) result_digit = CAPIDTMF_RECV_NO_DIGIT; n = 0; for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++) { if ((((short)(low_peak - goertzel_result_buffer[i] - capidtmf_recv_guard_snr_low_table[i])) < 0) || (((short)(high_peak - goertzel_result_buffer[i] - capidtmf_recv_guard_snr_high_table[i])) < 0)) { n++; } } if (n != 2) result_digit = CAPIDTMF_RECV_NO_DIGIT; if (result_digit == CAPIDTMF_RECV_NO_DIGIT) { if (p_state->recv.current_digit_on_time != 0) { if (++(p_state->recv.current_digit_off_time) >= p_state->recv.min_gap_duration) { p_state->recv.current_digit_on_time = 0; p_state->recv.current_digit_off_time = 0; } } else { if (p_state->recv.current_digit_off_time != 0) (p_state->recv.current_digit_off_time)--; } } else { if ((p_state->recv.current_digit_on_time == 0) && (p_state->recv.current_digit_off_time != 0)) { (p_state->recv.current_digit_off_time)--; } else { n = p_state->recv.current_digit_off_time; if ((p_state->recv.current_digit_on_time != 0) && (result_digit != p_state->recv.current_digit_value)) { p_state->recv.current_digit_on_time = 0; n = 0; } p_state->recv.current_digit_value = result_digit; p_state->recv.current_digit_off_time = 0; if (p_state->recv.current_digit_on_time != 0xffff) { p_state->recv.current_digit_on_time += n + 1; if (p_state->recv.current_digit_on_time >= p_state->recv.min_digit_duration) { p_state->recv.current_digit_on_time = 0xffff; i = (p_state->recv.digit_write_pos == CAPIDTMF_RECV_DIGIT_BUFFER_SIZE - 1) ? 0 : p_state->recv.digit_write_pos + 1; if (i == p_state->recv.digit_read_pos) { trace (dprintf ("%s,%d: Receive digit overrun", (char *)(FILE_), __LINE__)); } else { p_state->recv.digit_buffer[p_state->recv.digit_write_pos] = result_digit; p_state->recv.digit_write_pos = i; p_state->recv.indication_state = (p_state->recv.indication_state & ~CAPIDTMF_RECV_INDICATION_DIGIT) | (~p_state->recv.indication_state_ack & CAPIDTMF_RECV_INDICATION_DIGIT); } } } } } cycle_counter = 0; sample_number++; } } p_state->recv.cycle_counter = cycle_counter; }}void capidtmf_init (t_capidtmf_state *p_state, byte ulaw){ p_state->ulaw = ulaw; capidtmf_recv_init (p_state);}/*---------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -