0

Hi,
i have to compile some coding to show how dtmf works.
Any idea how?
I see most of it uses unix c or linux programming?
I have only been programming with windows C.
Pls do guide me step by step on how to program in these languages.
here are 2 websites that i found that offer codes to encode and modulate.
How do i compile them? i had troubles doing it the way a windows C is done.
http://www.rid.mv.ru/dsp/dtmf/P50-13.txt
Aerospace Software Ltd.

thank you all,
Trinetra

2
Contributors
1
Reply
4
Views
5 Years
Discussion Span
Last Post by BobS0327
-1

The code listed below is from the website and has been modified to compile under Windows. Please note there are two files dtmf.c and detect.h

// Compile under Windows as Cl.exe dtmf.c
/*
 * 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 <fcntl.h>
#include <io.h>   // read
#include "detect.h"

/* -------- local defines (if we had more.. seperate file) ----- */
#define FSAMPLE   8000   /* sampling rate, 8KHz */

/*
 * FLOAT_TO_SAMPLE converts a float in the range -1.0 to 1.0
 * into a format valid to be written out in a sound file
 * or to a sound device
 */
#ifdef SIGNED
#  define FLOAT_TO_SAMPLE(x)    ((char)((x) * 127.0))
#else
#  define FLOAT_TO_SAMPLE(x)    ((char)((x + 1.0) * 127.0))
#endif

#define SOUND_DEV  "/dev/dsp"
typedef char sample;
/* --------------------------------------------------------------- */






/*
 * 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
 */
int calc_power(unsigned char *data,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
 */
int decode(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((unsigned char *)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);
}

int read_frame(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
 */
void dtmf_to_ascii(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);
}

#ifdef bob

int main(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);
}

#endif


/*
 * take the sine of x, where x is 0 to 65535 (for 0 to 360 degrees)
 */
float mysine(short in)

{
    static float coef[] = {
        3.140625, 0.02026367, -5.325196, 0.5446778, 1.800293
    };
    float x,y,res;
    int sign,i;

    if(in < 0) {       /* force positive */
        sign = -1;
        in = -in;
    } else
        sign = 1;
    if(in >= 0x4000)      /* 90 degrees */
        in = 0x8000 - in;   /* 180 degrees - in */
    x = in * (1/32768.0);
    y = x;               /* y holds x^i) */
    res = 0;
    for(i=0; i<5; i++) {
        res += y * coef[i];
        y *= x;
    }
    return(res * sign);
}

/*
 * play tone1 and tone2 (in Hz)
 * for 'length' milliseconds
 * outputs samples to sound_out
 */
void two_tones(int sound_out, unsigned int tone1,unsigned int tone2,unsigned int length)
{
#define BLEN 128
    sample cout[BLEN];
    float out;
    unsigned int ad1,ad2;
    short c1,c2;
    int i,l,x;

    ad1 = (tone1 << 16) / FSAMPLE;
    ad2 = (tone2 << 16) / FSAMPLE;
    l = (length * FSAMPLE) / 1000;
    x = 0;
    for( c1=0, c2=0, i=0 ;
            i < l;
            i++, c1+= ad1, c2+= ad2 ) {
        out = (mysine(c1) + mysine(c2)) * 0.5;
        cout[x++] = FLOAT_TO_SAMPLE(out);
        if (x==BLEN) {
            write(sound_out, cout, x * sizeof(sample));
            x=0;
        }
    }
    write(sound_out, cout, x);
}

/*
 * silence on 'sound_out'
 * for length milliseconds
 */
void silence(int sound_out, unsigned int length)
{
    int l,i,x;
    static sample c0 = FLOAT_TO_SAMPLE(0.0);
    sample cout[BLEN];

    x = 0;
    l = (length * FSAMPLE) / 1000;
    for(i=0; i < l; i++) {
        cout[x++] = c0;
        if (x==BLEN) {
            write(sound_out, cout, x * sizeof(sample));
            x=0;
        }
    }
    write(sound_out, cout, x);
}

/*
 * play a single dtmf tone
 * for a length of time,
 * input is 0-9 for digit, 10 for * 11 for #
 */
void dtmf(int sound_fd, int digit, int length)
{
    /* Freqs for 0-9, *, # */
    static int row[] = {
        941, 697, 697, 697, 770, 770, 770, 852, 852, 852, 941, 941
    };
    static int col[] = {
        1336, 1209, 1336, 1477, 1209, 1336, 1477, 1209, 1336, 1447,
        1209, 1477
    };

    two_tones(sound_fd, row[digit], col[digit], length);
}

/*
 * take a string and output as dtmf
 * valid characters, 0-9, *, #
 * all others play as 50ms silence
 */
void dial(int sound_fd, char * number)
{
    int i,x;
    char c;

    for(i=0; number[i]; i++) {
        c = number[i];
        x = -1;
        if(c >= '0' && c <= '9')
            x = c - '0';
        else if(c == '*')
            x = 10;
        else if(c == '#')
            x = 11;
        if(x >= 0)
            dtmf(sound_fd, x, 50);
        silence(sound_fd,50);
    }
}


int main(void)
{
    int sfd;
    char number[100];

    sfd = open(SOUND_DEV,O_RDWR);
    if(sfd<0) {
        perror(SOUND_DEV);
        return(-1);
    }
    printf("Enter fone number: ");
    gets(number);
    dial(sfd,number);
    return 0;
}

Detect.h follows:

/* 
 *
 * 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 "on" */
#define THRESH 100.0         /* minimum level for the loudest tone */
#define FLUSH_TIME 100       /* 100 frames = 3 seconds */
Votes + Comments
And how does this help him LEARN how to do it himself? We to not hand out code, we help them code it themselves.
This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.