www.pudn.com > dtmf-ansi-c-version.rar > dtmf.c, change:2005-07-20,size:3857b


#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <errno.h>
#include <linux/soundcard.h>
#include <assert.h>

/*  Tobin Fricke <tobin@splorg.org> 16 November 1999
 *  Copyright (c) 1999
 *  Distributed under the terms of the GNU Public License */

/** Generate a specified number of samples containing the two specified
 *  frequencies (in hertz) and dump to the file descriptor audio_fd. */

void dual_tone(int audio_fd, int samples, double freq1, double freq2) {
  static double Pi = 3.14159;
  unsigned char *buffer;
  double sampleperiod = 1.0/8000.0;
  int sample;

  /* Convert each frequency from Hertz to radians/second so that we
   * don't have to do this calculation in the loop.. not that this is
   * necessary on any fast processor, but why not? */

  freq1 *= 2*Pi;
  freq2 *= 2*Pi;

  /* Allocate some memory for the waveform data. */

  buffer = (unsigned char *)malloc(samples * sizeof(unsigned char));

  /* Generate the waveform data. */

  for (sample=0; sample<samples; sample++) 
      buffer[sample] = (unsigned char)(128.0 + 
	                  40*cos(freq1*sample*sampleperiod) +
	                  40*cos(freq2*sample*sampleperiod));
 
  /* Send the waveform data to the audio device. */

  write(audio_fd, buffer, samples*sizeof(unsigned char));

  /* Free our buffer */

  free(buffer);
}

/** Play the DTMF for a single key.  The argument audio_fd is the file
 *  descriptor for the audio output device (/dev/audio, /dev/dsp, properly
 *  configured via calls to ioctl). key is the number of the button
 *  (0,1,..,9).  The set of keys {*,#,A,B,C,D} is left unimplemented.  
 *  duration specifies the duration the sound should last, measured in
 *  samples (eg 8000 samples == 1 second). */

void play_dtmf(int audio_fd, int key, int duration) {
  char buffer[500];
  int s;
  double col_freq[3] = { 1209.0, 1336.0, 1477.0 };
  double row_freq[4] = { 697.0, 770.0, 852.0, 941.0 };
  int row, col;

  /* Figure out the column and row of the requested key.  Column and row
   * numbers are zero-based. Zero is a special case because it's located
   * in a funny place. Once again note that key must be in {0,...,9}. */

  if (key) {
    row = (key - 1) / 3;
    col = (key - 1) % 3;
  }
  else {     /* Key is 0 */
    row = 3;
    col = 1;
  }
 
  /* for fun, and debugging */
  printf(" key %u row %u col %u freqs %f %f \n",key,row,col,row_freq[row],col_freq[col]);

  dual_tone(audio_fd,duration,row_freq[row],col_freq[col]);

  /* Play a short bit of silence */

  for (s = 0; s<500; s++) buffer[s] = 128;
  write(audio_fd,buffer,100);
}

int main(int argc, char **argv) {
  int audio_fd;                /* Will hold the file handle of the audiodev */
  char *device = "/dev/dsp";   /* The filename of the audio device */
  int format;	               /* General purpose variable */
  char *number = "19495864906";    /* Phone number to dial. */

  /* Open the audio device */

  if ((audio_fd = open(device,O_WRONLY,0)) == -1) {
      fprintf(stderr,"Couldn't open audio device. (%s)\n",strerror(errno));
      exit(1);
  }

  /* Set the sample format to unsigned, 8 bits/sample */

  format = AFMT_U8;
  if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) == -1) {
      printf("Couldn't change audio format.\n");
      exit(1);
  }

  /* Single channel mode -- disable stereo */
  format = 0;
  assert( ioctl(audio_fd, SNDCTL_DSP_STEREO, &format) != -1);

  /* Set the audio device to 8000 samples per second */
  format = 8000;
  assert( ioctl(audio_fd, SNDCTL_DSP_SPEED, &format) != -1);

  /* Play each digit of the number in turn. */
  dual_tone(audio_fd,16000,350.0,440.0);
  while (*number) {
   play_dtmf(audio_fd,(*number)-'0',1000);
   number++;
  }
  dual_tone(audio_fd,4000,440.0,480.0);
  /* Close the audio device. */

  close(audio_fd);

  return (0);
}