Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Re: Parsing touch tone input?

by Anonymous Monk
on Jul 20, 2002 at 21:48 UTC ( #183683=note: print w/ replies, xml ) Need Help??


in reply to Parsing touch tone input?

Dunno if this will help, It's in C but you might be able to convert it into perl.

/* * detect.c * This program will detect MF tones and normal * dtmf tones as well as some other common tones such * as BUSY, DIALTONE and RING. * The program uses a goertzel algorithm to detect * the power of various frequency ranges. * * input is assumed to be 8 bit samples. The program * can use either signed or unsigned samples according * to a compile time option: * * cc -DUNSIGNED detect.c -o detect * * for unsigned input (soundblaster) and: * * cc detect.c -o detect * * for signed input (amiga samples) * if you dont want flushes, -DNOFLUSH * * Tim N. */ #include <stdio.h> #include <math.h> #include "detect.h" /* * calculate the power of each tone according * to a modified goertzel algorithm described in * _digital signal processing applications using the * ADSP-2100 family_ by Analog Devices * * input is 'data', N sample values * * ouput is 'power', NUMTONES values * corresponding to the power of each tone */ calc_power(data,power) #ifdef UNSIGNED unsigned char *data; #else char *data; #endif float *power; { float u0[NUMTONES],u1[NUMTONES],t,in; int i,j; for(j=0; j<NUMTONES; j++) { u0[j] = 0.0; u1[j] = 0.0; } for(i=0; i<N; i++) { /* feedback */ #ifdef UNSIGNED in = ((int)data[i] - 128) / 128.0; #else in = data[i] / 128.0; #endif for(j=0; j<NUMTONES; j++) { t = u0[j]; u0[j] = in + coef[j] * u0[j] - u1[j]; u1[j] = t; } } for(j=0; j<NUMTONES; j++) /* feedforward */ power[j] = u0[j] * u0[j] + u1[j] * u1[j] - coef[j] * u0[j] * u1[j] +; return(0); } /* * detect which signals are present. * * return values defined in the include file * note: DTMF 3 and MF 7 conflict. To resolve * this the program only reports MF 7 between * a KP and an ST, otherwise DTMF 3 is returned */ decode(data) char *data; { float power[NUMTONES],thresh,maxpower; int on[NUMTONES],on_count; int bcount, rcount, ccount; int row, col, b1, b2, i; int r[4],c[4],b[8]; static int MFmode=0; calc_power(data,power); for(i=0, maxpower=0.0; i<NUMTONES;i++) if(power[i] > maxpower) maxpower = power[i]; /* for(i=0;i<NUMTONES;i++) printf("%f, ",power[i]); printf("\n"); */ if(maxpower < THRESH) /* silence? */ return(DSIL); thresh = RANGE * maxpower; /* allowable range of powers */ for(i=0, on_count=0; i<NUMTONES; i++) { if(power[i] > thresh) { on[i] = 1; on_count ++; } else on[i] = 0; } /* printf("%4d: ",on_count); for(i=0;i<NUMTONES;i++) putchar('0' + on[i]); printf("\n"); */ if(on_count == 1) { if(on[B7]) return(D24); if(on[B8]) return(D26); return(-1); } if(on_count == 2) { if(on[X1] && on[X2]) return(DDT); if(on[X2] && on[X3]) return(DRING); if(on[X3] && on[X4]) return(DBUSY); b[0]= on[B1]; b[1]= on[B2]; b[2]= on[B3]; b[3]= on[B4]; b[4]= on[B5]; b[5]= on[B6]; b[6]= on[B7]; b[7]= on[B8]; c[0]= on[C1]; c[1]= on[C2]; c[2]= on[C3]; c[3]= on[C4]; r[0]= on[R1]; r[1]= on[R2]; r[2]= on[R3]; r[3]= on[R4]; for(i=0, bcount=0; i<8; i++) { if(b[i]) { bcount++; b2 = b1; b1 = i; } } for(i=0, rcount=0; i<4; i++) { if(r[i]) { rcount++; row = i; } } for(i=0, ccount=0; i<4; i++) { if(c[i]) { ccount++; col = i; } } if(rcount==1 && ccount==1) { /* DTMF */ if(col == 3) /* A,B,C,D */ return(DA + row); else { if(row == 3 && col == 0 ) return(DSTAR); if(row == 3 && col == 2 ) return(DPND); if(row == 3) return(D0); if(row == 0 && col == 2) { /* DTMF 3 conflicts with MF 7 */ if(!MFmode) return(D3); } else return(D1 + col + row*3); } } if(bcount == 2) { /* MF */ /* b1 has upper number, b2 has lower */ switch(b1) { case 7: return( (b2==6)? D2426: -1); case 6: return(-1); case 5: if(b2==2 || b2==3) /* KP */ MFmode=1; if(b2==4) /* ST */ MFmode=0; return(DC11 + b2); /* MF 7 conflicts with DTMF 3, but if we made it * here then DTMF 3 was already tested for */ case 4: return( (b2==3)? D0: D7 + b2); case 3: return(D4 + b2); case 2: return(D2 + b2); case 1: return(D1); } } return(-1); } if(on_count == 0) return(DSIL); return(-1); } read_frame(fd,buf) int fd; char *buf; { int i,x; for(i=0; i<N; ) { x = read(fd, &buf[i], N-i); if(x <= 0) return(0); i += x; } return(1); } /* * read in frames, output the decoded * results */ dtmf_to_ascii(fd1, fd2) int fd1; FILE *fd2; { int x,last= DSIL; char frame[N+5]; int silence_time; while(read_frame(fd1, frame)) { x = decode(frame); /* if(x== -1) putchar('-'); if(x==DSIL) putchar(' '); if(x!=DSIL && x!=-1) putchar('a' + x); fflush(stdout); continue; */ if(x >= 0) { if(x == DSIL) silence_time += (silence_time>=0)?1:0 ; else silence_time= 0; if(silence_time == FLUSH_TIME) { fputs("\n",fd2); silence_time= -1; /* stop counting */ } if(x != DSIL && x != last && (last == DSIL || last==D24 || last == D26 || last == D2426 || last == DDT || last == DBUSY || last == DRING) ) { fputs(dtran[x], fd2); #ifndef NOFLUSH fflush(fd2); #endif } last = x; } } fputs("\n",fd2); } main(argc,argv) int argc; char **argv; { FILE *output; int input; input = 0; output = stdout; switch(argc) { case 1: break; case 3: output = fopen(argv[2],"w"); if(!output) { perror(argv[2]); return(-1); } /* fall through */ case 2: input = open(argv[1],0); if(input < 0) { perror(argv[1]); return(-1); } break; default: fprintf(stderr,"usage: %s [input [output]]\n",argv[0]); return(-1); } dtmf_to_ascii(input,output); fputs("Done.\n",output); return(0); }


Comment on Re: Parsing touch tone input?
Download Code
Re: Re: Parsing touch tone input?
by Anonymous Monk on Jul 20, 2002 at 21:58 UTC
    and here is detect.h
    /* * * goertzel aglorithm, find the power of different * frequencies in an N point DFT. * * ftone/fsample = k/N * k and N are integers. fsample is 8000 (8khz) * this means the *maximum* frequency resolution * is fsample/N (each step in k corresponds to a * step of fsample/N hz in ftone) * * N was chosen to minimize the sum of the K errors for * all the tones detected... here are the results : * * Best N is 240, with the sum of all errors = 3.030002 * freq freq actual k kactual kerr * ---- ------------ ------ ------- ----- * 350 (366.66667) 10.500 (11) 0.500 * 440 (433.33333) 13.200 (13) 0.200 * 480 (466.66667) 14.400 (14) 0.400 * 620 (633.33333) 18.600 (19) 0.400 * 697 (700.00000) 20.910 (21) 0.090 * 700 (700.00000) 21.000 (21) 0.000 * 770 (766.66667) 23.100 (23) 0.100 * 852 (866.66667) 25.560 (26) 0.440 * 900 (900.00000) 27.000 (27) 0.000 * 941 (933.33333) 28.230 (28) 0.230 * 1100 (1100.00000) 33.000 (33) 0.000 * 1209 (1200.00000) 36.270 (36) 0.270 * 1300 (1300.00000) 39.000 (39) 0.000 * 1336 (1333.33333) 40.080 (40) 0.080 **** I took out 1477.. too close to 1500 * 1477 (1466.66667) 44.310 (44) 0.310 **** * 1500 (1500.00000) 45.000 (45) 0.000 * 1633 (1633.33333) 48.990 (49) 0.010 * 1700 (1700.00000) 51.000 (51) 0.000 * 2400 (2400.00000) 72.000 (72) 0.000 * 2600 (2600.00000) 78.000 (78) 0.000 * * notice, 697 and 700hz are indestinguishable (same K) * all other tones have a seperate k value. * these two tones must be treated as identical for our * analysis. * * The worst tones to detect are 350 (error = 0.5, * detet 367 hz) and 852 (error = 0.44, detect 867hz). * all others are very close. * */ #define FSAMPLE 8000 #define N 240 int k[] = { 11, 13, 14, 19, 21, 23, 26, 27, 28, 33, 36, 39, 40, /*44,*/ 45, 49, 51, 72, 78, }; /* coefficients for above k's as: * 2 * cos( 2*pi* k/N ) */ float coef[] = { 1.917639, 1.885283, 1.867161, 1.757634, 1.705280, 1.648252, 1.554292, 1.520812, 1.486290, 1.298896, 1.175571, 1.044997, 1.000000, /* 0.813473,*/ 0.765367, 0.568031, 0.466891, -0.618034, -0.907981, }; #define X1 0 /* 350 dialtone */ #define X2 1 /* 440 ring, dialtone */ #define X3 2 /* 480 ring, busy */ #define X4 3 /* 620 busy */ #define R1 4 /* 697, dtmf row 1 */ #define R2 5 /* 770, dtmf row 2 */ #define R3 6 /* 852, dtmf row 3 */ #define R4 8 /* 941, dtmf row 4 */ #define C1 10 /* 1209, dtmf col 1 */ #define C2 12 /* 1336, dtmf col 2 */ #define C3 13 /* 1477, dtmf col 3 */ #define C4 14 /* 1633, dtmf col 4 */ #define B1 4 /* 700, blue box 1 */ #define B2 7 /* 900, bb 2 */ #define B3 9 /* 1100, bb 3 */ #define B4 11 /* 1300, bb4 */ #define B5 13 /* 1500, bb5 */ #define B6 15 /* 1700, bb6 */ #define B7 16 /* 2400, bb7 */ #define B8 17 /* 2600, bb8 */ #define NUMTONES 18 /* values returned by detect * 0-9 DTMF 0 through 9 or MF 0-9 * 10-11 DTMF *, # * 12-15 DTMF A,B,C,D * 16-20 MF last column: C11, C12, KP1, KP2, ST * 21 2400 * 22 2600 * 23 2400 + 2600 * 24 DIALTONE * 25 RING * 26 BUSY * 27 silence * -1 invalid */ #define D0 0 #define D1 1 #define D2 2 #define D3 3 #define D4 4 #define D5 5 #define D6 6 #define D7 7 #define D8 8 #define D9 9 #define DSTAR 10 #define DPND 11 #define DA 12 #define DB 13 #define DC 14 #define DD 15 #define DC11 16 #define DC12 17 #define DKP1 18 #define DKP2 19 #define DST 20 #define D24 21 #define D26 22 #define D2426 23 #define DDT 24 #define DRING 25 #define DBUSY 26 #define DSIL 27 /* translation of above codes into text */ char *dtran[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "#", "A", "B", "C", "D", "+C11 ", "+C12 ", " KP1+", " KP2+", "+ST ", " 2400 ", " 2600 ", " 2400+2600 ", " DIALTONE ", " RING ", " BUSY ","" }; #define RANGE 0.1 /* any thing higher than RANGE*peak is "o +n" */ #define THRESH 100.0 /* minimum level for the loudest tone */ #define FLUSH_TIME 100 /* 100 frames = 3 seconds */

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://183683]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (5)
As of 2014-12-18 04:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (41 votes), past polls