193 lines
4.8 KiB
C
193 lines
4.8 KiB
C
/*
|
|
* DTMF demodulator, inspirated from the multimon project of Thomas
|
|
* Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu). It is different
|
|
* in the sense that it uses a true block based DFT estimator.
|
|
*
|
|
* Copyright (c) 1999 Fabrice Bellard.
|
|
*
|
|
* This code is released under the GNU General Public License version
|
|
* 2. Please read the file COPYING to know the exact terms of the
|
|
* license.
|
|
*/
|
|
|
|
#include "lm.h"
|
|
|
|
/*
|
|
* DTMF frequencies
|
|
*
|
|
* 1209 1336 1477 1633
|
|
* 697 1 2 3 A
|
|
* 770 4 5 6 B
|
|
* 852 7 8 9 C
|
|
* 941 * 0 # D
|
|
* */
|
|
|
|
static const char *dtmf_transl = "123A456B789C*0#D";
|
|
|
|
static int dtmf_freq[] = {
|
|
1209, 1336, 1477, 1633,
|
|
697, 770, 852, 941,
|
|
};
|
|
|
|
#define SAMPLE_RATE 8000
|
|
|
|
/* Each DTMF digit is estimed on N samples by estimating the DFT of
|
|
the signal. It is quite reliable, but the frequency resolution is
|
|
not accurate enough to meet the very strict ITU requirements. */
|
|
|
|
/* DTMF modulation */
|
|
|
|
void DTMF_mod_init(DTMF_mod_state *s)
|
|
{
|
|
s->t1 = s->t2 = 0;
|
|
s->omega1 = 0;
|
|
s->samples_left = 0;
|
|
}
|
|
|
|
/* compute parameters for a new digit */
|
|
static void compute_params(DTMF_mod_state *s)
|
|
{
|
|
const char *p;
|
|
int v,digit,f1,f2;
|
|
|
|
/* if we were playing a digit, we make a pause */
|
|
if (s->omega1 != 0)
|
|
goto nodigit;
|
|
|
|
digit = s->get_digit(s->opaque);
|
|
if (digit == -1)
|
|
goto nodigit;
|
|
p = dtmf_transl;
|
|
while (*p != digit && *p) p++;
|
|
if (*p) {
|
|
v = p - dtmf_transl;
|
|
f1 = dtmf_freq[v & 3];
|
|
f2 = dtmf_freq[4 + (v >> 2)];
|
|
s->omega1 = (PHASE_BASE * f1) / SAMPLE_RATE;
|
|
s->omega2 = (PHASE_BASE * f2) / SAMPLE_RATE;
|
|
/* amplitude */
|
|
s->amp = (int) (pow(10, s->dtmf_level / 20.0) * 32768.0);
|
|
/* number of samples to play */
|
|
s->samples_left = (s->digit_length_ms * SAMPLE_RATE) / 1000;
|
|
} else {
|
|
nodigit:
|
|
s->omega1 = 0;
|
|
s->samples_left = (s->digit_pause_ms * SAMPLE_RATE) / 1000;
|
|
}
|
|
}
|
|
|
|
void DTMF_mod(DTMF_mod_state *s, s16 *samples, unsigned int nb)
|
|
{
|
|
int len, t1, t2, amp, i;
|
|
|
|
while (nb > 0) {
|
|
if (s->samples_left == 0) {
|
|
compute_params(s);
|
|
}
|
|
|
|
len = nb;
|
|
if (len > s->samples_left)
|
|
len = s->samples_left;
|
|
|
|
if (s->omega1 != 0) {
|
|
t1 = s->t1;
|
|
t2 = s->t2;
|
|
amp = s->amp;
|
|
for(i=0;i<len;i++) {
|
|
int v;
|
|
v = ((dsp_cos(t1) + dsp_cos(t2)) * amp) >> COS_BITS;
|
|
samples[i] = v;
|
|
t1 += s->omega1;
|
|
t2 += s->omega2;
|
|
}
|
|
s->t1 = t1;
|
|
s->t2 = t2;
|
|
} else {
|
|
memset(samples, 0, nb * 2); /* silence between digits */
|
|
}
|
|
|
|
nb -= len;
|
|
samples += len;
|
|
s->samples_left -= len;
|
|
}
|
|
}
|
|
|
|
/* DTMF demodulation */
|
|
|
|
void DTMF_demod_init(DTMF_demod_state *s)
|
|
{
|
|
int i;
|
|
for(i=0;i<DTMF_N;i++) {
|
|
s->cos_tab[i] = (int) (cos( 2 * M_PI * i / DTMF_N) * COS_BASE);
|
|
s->sin_tab[i] = (int) (sin( 2 * M_PI * i / DTMF_N) * COS_BASE);
|
|
}
|
|
for(i=0;i<8;i++) {
|
|
float v;
|
|
v = (float)dtmf_freq[i] / (float)SAMPLE_RATE * (float)DTMF_N;
|
|
s->dtmf_coefs[i] = (int)rint(v);
|
|
}
|
|
|
|
s->buf_ptr = 0;
|
|
s->last_digit = 0;
|
|
}
|
|
|
|
int find_max(int *val,int n)
|
|
{
|
|
int i,j,max;
|
|
|
|
j = 0;
|
|
max = val[0];
|
|
for(i=1;i<n;i++) {
|
|
if (val[i] > max) {
|
|
j = i;
|
|
max = val[i];
|
|
}
|
|
}
|
|
return j;
|
|
}
|
|
|
|
void DTMF_demod(DTMF_demod_state *s,
|
|
const s16 *samples, unsigned int nb)
|
|
{
|
|
int i, j, power[8], power0, v1, v2, digit, bits, p1, p2, p0;
|
|
|
|
for(j=0;j<nb;j++) {
|
|
s->buf[s->buf_ptr++] = samples[j];
|
|
|
|
if (s->buf_ptr >= DTMF_N) {
|
|
/* decision based on one block */
|
|
bits = dsp_max_bits(s->buf, DTMF_N);
|
|
if (bits < 8) bits = 8;
|
|
dsp_sar_tab(s->buf, DTMF_N, bits - 8);
|
|
|
|
power0 = dsp_norm2(s->buf, DTMF_N, 0);
|
|
|
|
for(i=0;i<8;i++) {
|
|
power[i] = compute_DFT(s->cos_tab, s->sin_tab, s->buf,
|
|
s->dtmf_coefs[i], DTMF_N);
|
|
}
|
|
|
|
v1 = find_max(power, 4);
|
|
v2 = find_max(power + 4, 4);
|
|
p0 = (int)(power0 * 0.3);
|
|
p1 = (2 * power[v1]) / DTMF_N;
|
|
p2 = (2 * power[v2 + 4]) / DTMF_N;
|
|
#if 0
|
|
printf("%d %d %d %f %f\n",p0, v1, v2, (float) p1 / p0,(float) p2 / p0);
|
|
#endif
|
|
if (p1 > p0 && p2 > p0)
|
|
digit = dtmf_transl[v1 | (v2 << 2)];
|
|
else
|
|
digit = 0;
|
|
|
|
if (digit != s->last_digit) {
|
|
if (digit != 0) {
|
|
s->put_digit(s->opaque, digit);
|
|
}
|
|
s->last_digit = digit;
|
|
}
|
|
s->buf_ptr = 0;
|
|
}
|
|
}
|
|
}
|