dtmf: reindent

This commit is contained in:
David Schleef 2010-12-30 18:19:47 -08:00
parent 0073550300
commit 5fed7a264c

View file

@ -60,12 +60,12 @@
#define DTMF_THRESHOLD 8.0e7 #define DTMF_THRESHOLD 8.0e7
#define FAX_THRESHOLD 8.0e7 #define FAX_THRESHOLD 8.0e7
#define FAX_2ND_HARMONIC 2.0 /* 4dB */ #define FAX_2ND_HARMONIC 2.0 /* 4dB */
#define DTMF_NORMAL_TWIST 6.3 /* 8dB */ #define DTMF_NORMAL_TWIST 6.3 /* 8dB */
#define DTMF_REVERSE_TWIST ((isradio) ? 4.0 : 2.5) /* 4dB normal */ #define DTMF_REVERSE_TWIST ((isradio) ? 4.0 : 2.5) /* 4dB normal */
#define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ #define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */
#define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ #define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */
#define DTMF_2ND_HARMONIC_ROW ((isradio) ? 1.7 : 2.5) /* 4dB normal */ #define DTMF_2ND_HARMONIC_ROW ((isradio) ? 1.7 : 2.5) /* 4dB normal */
#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */ #define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */
static tone_detection_descriptor_t dtmf_detect_row[4]; static tone_detection_descriptor_t dtmf_detect_row[4];
static tone_detection_descriptor_t dtmf_detect_col[4]; static tone_detection_descriptor_t dtmf_detect_col[4];
@ -74,443 +74,426 @@ static tone_detection_descriptor_t dtmf_detect_col_2nd[4];
static tone_detection_descriptor_t fax_detect; static tone_detection_descriptor_t fax_detect;
static tone_detection_descriptor_t fax_detect_2nd; static tone_detection_descriptor_t fax_detect_2nd;
static float dtmf_row[] = static float dtmf_row[] = {
{ 697.0, 770.0, 852.0, 941.0
697.0, 770.0, 852.0, 941.0
}; };
static float dtmf_col[] =
{ static float dtmf_col[] = {
1209.0, 1336.0, 1477.0, 1633.0 1209.0, 1336.0, 1477.0, 1633.0
}; };
static float fax_freq = 1100.0; static float fax_freq = 1100.0;
static char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
static void goertzel_init(goertzel_state_t *s, static void
tone_detection_descriptor_t *t) goertzel_init (goertzel_state_t * s, tone_detection_descriptor_t * t)
{ {
s->v2 = s->v2 = s->v3 = 0.0;
s->v3 = 0.0; s->fac = t->fac;
s->fac = t->fac;
} }
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
#if defined(USE_3DNOW) #if defined(USE_3DNOW)
static inline void _dtmf_goertzel_update(goertzel_state_t *s, static inline void
float x[], _dtmf_goertzel_update (goertzel_state_t * s, float x[], int samples)
int samples)
{ {
int n; int n;
float v; float v;
int i; int i;
float vv[16]; float vv[16];
vv[4] = s[0].v2; vv[4] = s[0].v2;
vv[5] = s[1].v2; vv[5] = s[1].v2;
vv[6] = s[2].v2; vv[6] = s[2].v2;
vv[7] = s[3].v2; vv[7] = s[3].v2;
vv[8] = s[0].v3; vv[8] = s[0].v3;
vv[9] = s[1].v3; vv[9] = s[1].v3;
vv[10] = s[2].v3; vv[10] = s[2].v3;
vv[11] = s[3].v3; vv[11] = s[3].v3;
vv[12] = s[0].fac; vv[12] = s[0].fac;
vv[13] = s[1].fac; vv[13] = s[1].fac;
vv[14] = s[2].fac; vv[14] = s[2].fac;
vv[15] = s[3].fac; vv[15] = s[3].fac;
//v1 = s->v2; //v1 = s->v2;
//s->v2 = s->v3; //s->v2 = s->v3;
//s->v3 = s->fac*s->v2 - v1 + x[0]; //s->v3 = s->fac*s->v2 - v1 + x[0];
__asm__ __volatile__ ( __asm__ __volatile__ (" femms;\n"
" femms;\n" " movq 16(%%edx),%%mm2;\n"
" movq 24(%%edx),%%mm3;\n"
" movq 32(%%edx),%%mm4;\n"
" movq 40(%%edx),%%mm5;\n"
" movq 48(%%edx),%%mm6;\n"
" movq 56(%%edx),%%mm7;\n"
" jmp 1f;\n"
" .align 32;\n"
" 1: ;\n"
" prefetch (%%eax);\n"
" movq %%mm3,%%mm1;\n"
" movq %%mm2,%%mm0;\n"
" movq %%mm5,%%mm3;\n"
" movq %%mm4,%%mm2;\n"
" pfmul %%mm7,%%mm5;\n"
" pfmul %%mm6,%%mm4;\n"
" pfsub %%mm1,%%mm5;\n"
" pfsub %%mm0,%%mm4;\n"
" movq (%%eax),%%mm0;\n"
" movq %%mm0,%%mm1;\n"
" punpckldq %%mm0,%%mm1;\n"
" add $4,%%eax;\n"
" pfadd %%mm1,%%mm5;\n"
" pfadd %%mm1,%%mm4;\n"
" dec %%ecx;\n"
" jnz 1b;\n"
" movq %%mm2,16(%%edx);\n"
" movq %%mm3,24(%%edx);\n"
" movq %%mm4,32(%%edx);\n"
" movq %%mm5,40(%%edx);\n"
" femms;\n"::"c" (samples), "a" (x), "d" (vv)
:"memory", "eax", "ecx");
" movq 16(%%edx),%%mm2;\n" s[0].v2 = vv[4];
" movq 24(%%edx),%%mm3;\n" s[1].v2 = vv[5];
" movq 32(%%edx),%%mm4;\n" s[2].v2 = vv[6];
" movq 40(%%edx),%%mm5;\n" s[3].v2 = vv[7];
" movq 48(%%edx),%%mm6;\n" s[0].v3 = vv[8];
" movq 56(%%edx),%%mm7;\n" s[1].v3 = vv[9];
s[2].v3 = vv[10];
" jmp 1f;\n" s[3].v3 = vv[11];
" .align 32;\n"
" 1: ;\n"
" prefetch (%%eax);\n"
" movq %%mm3,%%mm1;\n"
" movq %%mm2,%%mm0;\n"
" movq %%mm5,%%mm3;\n"
" movq %%mm4,%%mm2;\n"
" pfmul %%mm7,%%mm5;\n"
" pfmul %%mm6,%%mm4;\n"
" pfsub %%mm1,%%mm5;\n"
" pfsub %%mm0,%%mm4;\n"
" movq (%%eax),%%mm0;\n"
" movq %%mm0,%%mm1;\n"
" punpckldq %%mm0,%%mm1;\n"
" add $4,%%eax;\n"
" pfadd %%mm1,%%mm5;\n"
" pfadd %%mm1,%%mm4;\n"
" dec %%ecx;\n"
" jnz 1b;\n"
" movq %%mm2,16(%%edx);\n"
" movq %%mm3,24(%%edx);\n"
" movq %%mm4,32(%%edx);\n"
" movq %%mm5,40(%%edx);\n"
" femms;\n"
:
: "c" (samples), "a" (x), "d" (vv)
: "memory", "eax", "ecx");
s[0].v2 = vv[4];
s[1].v2 = vv[5];
s[2].v2 = vv[6];
s[3].v2 = vv[7];
s[0].v3 = vv[8];
s[1].v3 = vv[9];
s[2].v3 = vv[10];
s[3].v3 = vv[11];
} }
#endif #endif
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
void zap_goertzel_update(goertzel_state_t *s, void
int16_t x[], zap_goertzel_update (goertzel_state_t * s, int16_t x[], int samples)
int samples)
{ {
int i; int i;
float v1; float v1;
for (i = 0; i < samples; i++) for (i = 0; i < samples; i++) {
{ v1 = s->v2;
v1 = s->v2; s->v2 = s->v3;
s->v2 = s->v3; s->v3 = s->fac * s->v2 - v1 + x[i];
s->v3 = s->fac*s->v2 - v1 + x[i]; }
}
} }
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
float zap_goertzel_result (goertzel_state_t *s) float
zap_goertzel_result (goertzel_state_t * s)
{ {
return s->v3*s->v3 + s->v2*s->v2 - s->v2*s->v3*s->fac; return s->v3 * s->v3 + s->v2 * s->v2 - s->v2 * s->v3 * s->fac;
} }
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
void zap_dtmf_detect_init (dtmf_detect_state_t *s) void
zap_dtmf_detect_init (dtmf_detect_state_t * s)
{ {
int i; int i;
float theta; float theta;
s->hit1 = s->hit1 = s->hit2 = 0;
s->hit2 = 0;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++) {
{ theta = 2.0 * M_PI * (dtmf_row[i] / SAMPLE_RATE);
theta = 2.0*M_PI*(dtmf_row[i]/SAMPLE_RATE); dtmf_detect_row[i].fac = 2.0 * cos (theta);
dtmf_detect_row[i].fac = 2.0*cos(theta);
theta = 2.0*M_PI*(dtmf_col[i]/SAMPLE_RATE); theta = 2.0 * M_PI * (dtmf_col[i] / SAMPLE_RATE);
dtmf_detect_col[i].fac = 2.0*cos(theta); dtmf_detect_col[i].fac = 2.0 * cos (theta);
theta = 2.0*M_PI*(dtmf_row[i]*2.0/SAMPLE_RATE);
dtmf_detect_row_2nd[i].fac = 2.0*cos(theta);
theta = 2.0*M_PI*(dtmf_col[i]*2.0/SAMPLE_RATE); theta = 2.0 * M_PI * (dtmf_row[i] * 2.0 / SAMPLE_RATE);
dtmf_detect_col_2nd[i].fac = 2.0*cos(theta); dtmf_detect_row_2nd[i].fac = 2.0 * cos (theta);
goertzel_init (&s->row_out[i], &dtmf_detect_row[i]);
goertzel_init (&s->col_out[i], &dtmf_detect_col[i]);
goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]);
goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]);
s->energy = 0.0;
}
/* Same for the fax dector */ theta = 2.0 * M_PI * (dtmf_col[i] * 2.0 / SAMPLE_RATE);
theta = 2.0*M_PI*(fax_freq/SAMPLE_RATE); dtmf_detect_col_2nd[i].fac = 2.0 * cos (theta);
fax_detect.fac = 2.0 * cos(theta);
goertzel_init (&s->fax_tone, &fax_detect);
/* Same for the fax dector 2nd harmonic */ goertzel_init (&s->row_out[i], &dtmf_detect_row[i]);
theta = 2.0*M_PI*(fax_freq * 2.0/SAMPLE_RATE); goertzel_init (&s->col_out[i], &dtmf_detect_col[i]);
fax_detect_2nd.fac = 2.0 * cos(theta); goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]);
goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]);
s->current_sample = 0; s->energy = 0.0;
s->detected_digits = 0; }
s->lost_digits = 0;
s->digits[0] = '\0'; /* Same for the fax dector */
s->mhit = 0; theta = 2.0 * M_PI * (fax_freq / SAMPLE_RATE);
fax_detect.fac = 2.0 * cos (theta);
goertzel_init (&s->fax_tone, &fax_detect);
/* Same for the fax dector 2nd harmonic */
theta = 2.0 * M_PI * (fax_freq * 2.0 / SAMPLE_RATE);
fax_detect_2nd.fac = 2.0 * cos (theta);
goertzel_init (&s->fax_tone2nd, &fax_detect_2nd);
s->current_sample = 0;
s->detected_digits = 0;
s->lost_digits = 0;
s->digits[0] = '\0';
s->mhit = 0;
} }
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
int zap_dtmf_detect (dtmf_detect_state_t *s, int
int16_t amp[], zap_dtmf_detect (dtmf_detect_state_t * s,
int samples, int16_t amp[], int samples, int isradio)
int isradio)
{ {
float row_energy[4]; float row_energy[4];
float col_energy[4]; float col_energy[4];
float fax_energy; float fax_energy;
float fax_energy_2nd; float fax_energy_2nd;
float famp; float famp;
float v1; float v1;
int i; int i;
int j; int j;
int sample; int sample;
int best_row; int best_row;
int best_col; int best_col;
int hit; int hit;
int limit; int limit;
hit = 0; hit = 0;
for (sample = 0; sample < samples; sample = limit) for (sample = 0; sample < samples; sample = limit) {
{ /* 102 is optimised to meet the DTMF specs. */
/* 102 is optimised to meet the DTMF specs. */ if ((samples - sample) >= (102 - s->current_sample))
if ((samples - sample) >= (102 - s->current_sample)) limit = sample + (102 - s->current_sample);
limit = sample + (102 - s->current_sample); else
else limit = samples;
limit = samples;
#if defined(USE_3DNOW) #if defined(USE_3DNOW)
_dtmf_goertzel_update (s->row_out, amp + sample, limit - sample); _dtmf_goertzel_update (s->row_out, amp + sample, limit - sample);
_dtmf_goertzel_update (s->col_out, amp + sample, limit - sample); _dtmf_goertzel_update (s->col_out, amp + sample, limit - sample);
_dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample); _dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample);
_dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample); _dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample);
/* XXX Need to fax detect for 3dnow too XXX */ /* XXX Need to fax detect for 3dnow too XXX */
#warning "Fax Support Broken" #warning "Fax Support Broken"
#else #else
/* The following unrolled loop takes only 35% (rough estimate) of the /* The following unrolled loop takes only 35% (rough estimate) of the
time of a rolled loop on the machine on which it was developed */ time of a rolled loop on the machine on which it was developed */
for (j = sample; j < limit; j++) for (j = sample; j < limit; j++) {
{ famp = amp[j];
famp = amp[j];
s->energy += famp*famp;
/* With GCC 2.95, the following unrolled code seems to take about 35%
(rough estimate) as long as a neat little 0-3 loop */
v1 = s->row_out[0].v2;
s->row_out[0].v2 = s->row_out[0].v3;
s->row_out[0].v3 = s->row_out[0].fac*s->row_out[0].v2 - v1 + famp;
v1 = s->col_out[0].v2;
s->col_out[0].v2 = s->col_out[0].v3;
s->col_out[0].v3 = s->col_out[0].fac*s->col_out[0].v2 - v1 + famp;
v1 = s->row_out[1].v2;
s->row_out[1].v2 = s->row_out[1].v3;
s->row_out[1].v3 = s->row_out[1].fac*s->row_out[1].v2 - v1 + famp;
v1 = s->col_out[1].v2;
s->col_out[1].v2 = s->col_out[1].v3;
s->col_out[1].v3 = s->col_out[1].fac*s->col_out[1].v2 - v1 + famp;
v1 = s->row_out[2].v2;
s->row_out[2].v2 = s->row_out[2].v3;
s->row_out[2].v3 = s->row_out[2].fac*s->row_out[2].v2 - v1 + famp;
v1 = s->col_out[2].v2;
s->col_out[2].v2 = s->col_out[2].v3;
s->col_out[2].v3 = s->col_out[2].fac*s->col_out[2].v2 - v1 + famp;
v1 = s->row_out[3].v2;
s->row_out[3].v2 = s->row_out[3].v3;
s->row_out[3].v3 = s->row_out[3].fac*s->row_out[3].v2 - v1 + famp;
v1 = s->col_out[3].v2; s->energy += famp * famp;
s->col_out[3].v2 = s->col_out[3].v3;
s->col_out[3].v3 = s->col_out[3].fac*s->col_out[3].v2 - v1 + famp;
v1 = s->col_out2nd[0].v2; /* With GCC 2.95, the following unrolled code seems to take about 35%
s->col_out2nd[0].v2 = s->col_out2nd[0].v3; (rough estimate) as long as a neat little 0-3 loop */
s->col_out2nd[0].v3 = s->col_out2nd[0].fac*s->col_out2nd[0].v2 - v1 + famp; v1 = s->row_out[0].v2;
s->row_out[0].v2 = s->row_out[0].v3;
v1 = s->row_out2nd[0].v2; s->row_out[0].v3 = s->row_out[0].fac * s->row_out[0].v2 - v1 + famp;
s->row_out2nd[0].v2 = s->row_out2nd[0].v3;
s->row_out2nd[0].v3 = s->row_out2nd[0].fac*s->row_out2nd[0].v2 - v1 + famp;
v1 = s->col_out2nd[1].v2;
s->col_out2nd[1].v2 = s->col_out2nd[1].v3;
s->col_out2nd[1].v3 = s->col_out2nd[1].fac*s->col_out2nd[1].v2 - v1 + famp;
v1 = s->row_out2nd[1].v2;
s->row_out2nd[1].v2 = s->row_out2nd[1].v3;
s->row_out2nd[1].v3 = s->row_out2nd[1].fac*s->row_out2nd[1].v2 - v1 + famp;
v1 = s->col_out2nd[2].v2;
s->col_out2nd[2].v2 = s->col_out2nd[2].v3;
s->col_out2nd[2].v3 = s->col_out2nd[2].fac*s->col_out2nd[2].v2 - v1 + famp;
v1 = s->row_out2nd[2].v2;
s->row_out2nd[2].v2 = s->row_out2nd[2].v3;
s->row_out2nd[2].v3 = s->row_out2nd[2].fac*s->row_out2nd[2].v2 - v1 + famp;
v1 = s->col_out2nd[3].v2;
s->col_out2nd[3].v2 = s->col_out2nd[3].v3;
s->col_out2nd[3].v3 = s->col_out2nd[3].fac*s->col_out2nd[3].v2 - v1 + famp;
v1 = s->row_out2nd[3].v2;
s->row_out2nd[3].v2 = s->row_out2nd[3].v3;
s->row_out2nd[3].v3 = s->row_out2nd[3].fac*s->row_out2nd[3].v2 - v1 + famp;
/* Update fax tone */ v1 = s->col_out[0].v2;
v1 = s->fax_tone.v2; s->col_out[0].v2 = s->col_out[0].v3;
s->fax_tone.v2 = s->fax_tone.v3; s->col_out[0].v3 = s->col_out[0].fac * s->col_out[0].v2 - v1 + famp;
s->fax_tone.v3 = s->fax_tone.fac*s->fax_tone.v2 - v1 + famp;
v1 = s->fax_tone.v2; v1 = s->row_out[1].v2;
s->fax_tone2nd.v2 = s->fax_tone2nd.v3; s->row_out[1].v2 = s->row_out[1].v3;
s->fax_tone2nd.v3 = s->fax_tone2nd.fac*s->fax_tone2nd.v2 - v1 + famp; s->row_out[1].v3 = s->row_out[1].fac * s->row_out[1].v2 - v1 + famp;
}
v1 = s->col_out[1].v2;
s->col_out[1].v2 = s->col_out[1].v3;
s->col_out[1].v3 = s->col_out[1].fac * s->col_out[1].v2 - v1 + famp;
v1 = s->row_out[2].v2;
s->row_out[2].v2 = s->row_out[2].v3;
s->row_out[2].v3 = s->row_out[2].fac * s->row_out[2].v2 - v1 + famp;
v1 = s->col_out[2].v2;
s->col_out[2].v2 = s->col_out[2].v3;
s->col_out[2].v3 = s->col_out[2].fac * s->col_out[2].v2 - v1 + famp;
v1 = s->row_out[3].v2;
s->row_out[3].v2 = s->row_out[3].v3;
s->row_out[3].v3 = s->row_out[3].fac * s->row_out[3].v2 - v1 + famp;
v1 = s->col_out[3].v2;
s->col_out[3].v2 = s->col_out[3].v3;
s->col_out[3].v3 = s->col_out[3].fac * s->col_out[3].v2 - v1 + famp;
v1 = s->col_out2nd[0].v2;
s->col_out2nd[0].v2 = s->col_out2nd[0].v3;
s->col_out2nd[0].v3 =
s->col_out2nd[0].fac * s->col_out2nd[0].v2 - v1 + famp;
v1 = s->row_out2nd[0].v2;
s->row_out2nd[0].v2 = s->row_out2nd[0].v3;
s->row_out2nd[0].v3 =
s->row_out2nd[0].fac * s->row_out2nd[0].v2 - v1 + famp;
v1 = s->col_out2nd[1].v2;
s->col_out2nd[1].v2 = s->col_out2nd[1].v3;
s->col_out2nd[1].v3 =
s->col_out2nd[1].fac * s->col_out2nd[1].v2 - v1 + famp;
v1 = s->row_out2nd[1].v2;
s->row_out2nd[1].v2 = s->row_out2nd[1].v3;
s->row_out2nd[1].v3 =
s->row_out2nd[1].fac * s->row_out2nd[1].v2 - v1 + famp;
v1 = s->col_out2nd[2].v2;
s->col_out2nd[2].v2 = s->col_out2nd[2].v3;
s->col_out2nd[2].v3 =
s->col_out2nd[2].fac * s->col_out2nd[2].v2 - v1 + famp;
v1 = s->row_out2nd[2].v2;
s->row_out2nd[2].v2 = s->row_out2nd[2].v3;
s->row_out2nd[2].v3 =
s->row_out2nd[2].fac * s->row_out2nd[2].v2 - v1 + famp;
v1 = s->col_out2nd[3].v2;
s->col_out2nd[3].v2 = s->col_out2nd[3].v3;
s->col_out2nd[3].v3 =
s->col_out2nd[3].fac * s->col_out2nd[3].v2 - v1 + famp;
v1 = s->row_out2nd[3].v2;
s->row_out2nd[3].v2 = s->row_out2nd[3].v3;
s->row_out2nd[3].v3 =
s->row_out2nd[3].fac * s->row_out2nd[3].v2 - v1 + famp;
/* Update fax tone */
v1 = s->fax_tone.v2;
s->fax_tone.v2 = s->fax_tone.v3;
s->fax_tone.v3 = s->fax_tone.fac * s->fax_tone.v2 - v1 + famp;
v1 = s->fax_tone.v2;
s->fax_tone2nd.v2 = s->fax_tone2nd.v3;
s->fax_tone2nd.v3 = s->fax_tone2nd.fac * s->fax_tone2nd.v2 - v1 + famp;
}
#endif #endif
s->current_sample += (limit - sample); s->current_sample += (limit - sample);
if (s->current_sample < 102) if (s->current_sample < 102)
continue; continue;
/* Detect the fax energy, too */ /* Detect the fax energy, too */
fax_energy = zap_goertzel_result(&s->fax_tone); fax_energy = zap_goertzel_result (&s->fax_tone);
/* We are at the end of a DTMF detection block */
/* Find the peak row and the peak column */
row_energy[0] = zap_goertzel_result (&s->row_out[0]);
col_energy[0] = zap_goertzel_result (&s->col_out[0]);
for (best_row = best_col = 0, i = 1; i < 4; i++) /* We are at the end of a DTMF detection block */
{ /* Find the peak row and the peak column */
row_energy[i] = zap_goertzel_result (&s->row_out[i]); row_energy[0] = zap_goertzel_result (&s->row_out[0]);
if (row_energy[i] > row_energy[best_row]) col_energy[0] = zap_goertzel_result (&s->col_out[0]);
best_row = i;
col_energy[i] = zap_goertzel_result (&s->col_out[i]); for (best_row = best_col = 0, i = 1; i < 4; i++) {
if (col_energy[i] > col_energy[best_col]) row_energy[i] = zap_goertzel_result (&s->row_out[i]);
best_col = i; if (row_energy[i] > row_energy[best_row])
} best_row = i;
hit = 0; col_energy[i] = zap_goertzel_result (&s->col_out[i]);
/* Basic signal level test and the twist test */ if (col_energy[i] > col_energy[best_col])
if (row_energy[best_row] >= DTMF_THRESHOLD best_col = i;
&& }
col_energy[best_col] >= DTMF_THRESHOLD hit = 0;
&& /* Basic signal level test and the twist test */
col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST if (row_energy[best_row] >= DTMF_THRESHOLD
&& &&
col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) col_energy[best_col] >= DTMF_THRESHOLD
{ &&
/* Relative peak test */ col_energy[best_col] < row_energy[best_row] * DTMF_REVERSE_TWIST
for (i = 0; i < 4; i++) && col_energy[best_col] * DTMF_NORMAL_TWIST > row_energy[best_row]) {
{ /* Relative peak test */
if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) for (i = 0; i < 4; i++) {
|| if ((i != best_col
(i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) && col_energy[i] * DTMF_RELATIVE_PEAK_COL >
{ col_energy[best_col])
break; || (i != best_row
} && row_energy[i] * DTMF_RELATIVE_PEAK_ROW >
} row_energy[best_row])) {
/* ... and second harmonic test */ break;
if (i >= 4
&&
(row_energy[best_row] + col_energy[best_col]) > 42.0*s->energy
&&
zap_goertzel_result (&s->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col]
&&
zap_goertzel_result (&s->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 (hit == s->hit3 && s->hit3 != s->hit2)
{
s->mhit = hit;
s->digit_hits[(best_row << 2) + best_col]++;
s->detected_digits++;
if (s->current_digits < MAX_DTMF_DIGITS)
{
s->digits[s->current_digits++] = hit;
s->digits[s->current_digits] = '\0';
}
else
{
s->lost_digits++;
}
}
}
}
if (!hit && (fax_energy >= FAX_THRESHOLD) && (fax_energy > s->energy * 21.0)) {
fax_energy_2nd = zap_goertzel_result(&s->fax_tone2nd);
if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy) {
#if 0
printf("Fax energy/Second Harmonic: %f/%f\n", fax_energy, fax_energy_2nd);
#endif
/* XXX Probably need better checking than just this the energy XXX */
hit = 'f';
s->fax_hits++;
} /* Don't reset fax hits counter */
} else {
if (s->fax_hits > 5) {
s->mhit = 'f';
s->detected_digits++;
if (s->current_digits < MAX_DTMF_DIGITS)
{
s->digits[s->current_digits++] = hit;
s->digits[s->current_digits] = '\0';
}
else
{
s->lost_digits++;
}
}
s->fax_hits = 0;
}
s->hit1 = s->hit2;
s->hit2 = s->hit3;
s->hit3 = hit;
/* Reinitialise the detector for the next block */
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]);
goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]);
goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]);
} }
goertzel_init (&s->fax_tone, &fax_detect); }
goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); /* ... and second harmonic test */
s->energy = 0.0; if (i >= 4
s->current_sample = 0; &&
(row_energy[best_row] + col_energy[best_col]) > 42.0 * s->energy
&&
zap_goertzel_result (&s->col_out2nd[best_col]) *
DTMF_2ND_HARMONIC_COL < col_energy[best_col]
&& zap_goertzel_result (&s->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 (hit == s->hit3 && s->hit3 != s->hit2) {
s->mhit = hit;
s->digit_hits[(best_row << 2) + best_col]++;
s->detected_digits++;
if (s->current_digits < MAX_DTMF_DIGITS) {
s->digits[s->current_digits++] = hit;
s->digits[s->current_digits] = '\0';
} else {
s->lost_digits++;
}
}
}
} }
if ((!s->mhit) || (s->mhit != hit)) if (!hit && (fax_energy >= FAX_THRESHOLD)
{ && (fax_energy > s->energy * 21.0)) {
s->mhit = 0; fax_energy_2nd = zap_goertzel_result (&s->fax_tone2nd);
return(0); if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy) {
#if 0
printf ("Fax energy/Second Harmonic: %f/%f\n", fax_energy,
fax_energy_2nd);
#endif
/* XXX Probably need better checking than just this the energy XXX */
hit = 'f';
s->fax_hits++;
} /* Don't reset fax hits counter */
} else {
if (s->fax_hits > 5) {
s->mhit = 'f';
s->detected_digits++;
if (s->current_digits < MAX_DTMF_DIGITS) {
s->digits[s->current_digits++] = hit;
s->digits[s->current_digits] = '\0';
} else {
s->lost_digits++;
}
}
s->fax_hits = 0;
} }
return (hit); s->hit1 = s->hit2;
s->hit2 = s->hit3;
s->hit3 = hit;
/* Reinitialise the detector for the next block */
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]);
goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]);
goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]);
}
goertzel_init (&s->fax_tone, &fax_detect);
goertzel_init (&s->fax_tone2nd, &fax_detect_2nd);
s->energy = 0.0;
s->current_sample = 0;
}
if ((!s->mhit) || (s->mhit != hit)) {
s->mhit = 0;
return (0);
}
return (hit);
} }
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
int zap_dtmf_get (dtmf_detect_state_t *s, int
char *buf, zap_dtmf_get (dtmf_detect_state_t * s, char *buf, int max)
int max)
{ {
if (max > s->current_digits) if (max > s->current_digits)
max = s->current_digits; max = s->current_digits;
if (max > 0) if (max > 0) {
{ memcpy (buf, s->digits, max);
memcpy (buf, s->digits, max); memmove (s->digits, s->digits + max, s->current_digits - max);
memmove (s->digits, s->digits + max, s->current_digits - max); s->current_digits -= max;
s->current_digits -= max; }
} buf[max] = '\0';
buf[max] = '\0'; return max;
return max;
} }
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/