// makeDTMF.cc  P. Conrad   CISC181 Fall 2005
// Write a WAV file that dials 1 2 3 as a DTMF tone;
// Specify duration of each tone, filename on the command line

#include <iostream>
using namespace std;


// the following header files are needed for writing binary files
// they provide the functions open() and write(), as well as O_CREAT, O_RDWR

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <stdio.h> // for perror

#include <cmath>   // for sin, floor
#include <cstdlib> // for atoi, atof

bool systemIsLittleEndian();
int convertToLittleEndian(int x);
signed short convertShortToLittleEndian(signed short x);



void writeWAVheader(int numSamples, int samplesPerSecond, int fd)
{
  
  char riffHeader[] = "RIFF";
  write(fd, riffHeader, 4);
  
  int lengthField = convertToLittleEndian((numSamples * 2) + 36);
  write(fd, &lengthField, 4);
  
  char WAVEfmt_Headers[] = "WAVEfmt ";
  write(fd, WAVEfmt_Headers, 8);
  
  int formatChunkSize = convertToLittleEndian(16);
  write(fd, &formatChunkSize, 4);
  
  signed short numChannels = 1;
  signed short numChannelsLittleEndian = 
    convertShortToLittleEndian(numChannels);
  write(fd, &numChannelsLittleEndian, 2);
  
  signed short compression = 1;
  signed short compressionLittleEndian = 
    convertShortToLittleEndian(compression);
  write(fd, &compressionLittleEndian, 2);
  
  int samplesPerSecondField = convertToLittleEndian(samplesPerSecond);
  write(fd, &samplesPerSecondField, 4);
  
  int bytesPerSecondField = convertToLittleEndian(samplesPerSecond * 2);
  write(fd, &bytesPerSecondField, 4);
  
  signed short bytesPerSample = 2;
  signed short bytesPerSampleLittleEndian = 
    convertShortToLittleEndian(bytesPerSample);
  write(fd, &bytesPerSampleLittleEndian, 2);
  
  signed short bitsPerSample = 16;
  signed short bitsPerSampleLittleEndian = 
    convertShortToLittleEndian(bitsPerSample);
  write(fd, &bitsPerSampleLittleEndian, 2);
  
  
  char dataHeader[] = "data";
  write(fd, dataHeader, 4);
  
  int dataLength = convertToLittleEndian(numSamples * 2);
  write(fd, &dataLength, 4);
}


void  writeSilenceSamples(int fd, double duration)
{
  double t = 0;
  signed short sixteenBitSample;
  int numSamples = (int) floor (duration * 11025);
  for (int i=0; i<numSamples; i++)
    {
      sixteenBitSample = 0;
      write(fd,&sixteenBitSample,2);
      t += 1.0/11025.0;
    }
}

void  writeDTMFSamples(int fd, double duration, int freq1, int freq2)
{
  
  double t = 0;
  double sample, sample1, sample2;
  signed short sixteenBitSample;
  int numSamples = (int) floor (duration * 11025);
  for (int i=0; i<numSamples; i++)
    {
      sample1 = sin(freq1 * 2 * M_PI * t);
      sample2 = sin(freq2 * 2 * M_PI * t);
      sample = (sample1 + sample2) / 2.0;
      sixteenBitSample = (signed short) floor(sample * 32767);
      sixteenBitSample = convertShortToLittleEndian(sixteenBitSample);
      write(fd,&sixteenBitSample,2);
      t += 1.0/11025.0;
    }
}


int main(int argc, char *argv[])
{
  
  if (argc!=3)
    {
      cerr << "Usage: " << argv[0] << " numSeconds filename" << endl;
      exit(1);
    }

  // toneDuration is the length of each tone, and the space between.
  // we'll leave a space at the end too, so 1 (space) 2 (space) 3 (space)
  // is 6 times the tone duration

  double toneDuration = atof(argv[1]);
  
  if (toneDuration <= 0 || toneDuration > 3.0)
    {
      cerr << "Error: numSeconds must be between 0 and 3.0" << endl;
      exit(2);
    }

  const int samplesPerSecond = 11025;


  int fd = open(argv[2], O_RDWR | O_CREAT );
  
  // make sure open was successful
  
  if (fd < 0)
    {
      cerr << "File " << argv[2] << " could not be opened" << endl;
      perror("open:");
      exit(1);
    }
  
  int numSamples = (int) floor(toneDuration * 6 * samplesPerSecond);
  
  // Write the header to the file
  
  writeWAVheader(numSamples, samplesPerSecond, fd);
  
  // Write the samples to the file
  
  
  writeDTMFSamples(fd, toneDuration, 697, 1209);
  writeSilenceSamples(fd, toneDuration);

  writeDTMFSamples(fd, toneDuration, 697, 1336);
  writeSilenceSamples(fd, toneDuration);

  writeDTMFSamples(fd, toneDuration, 697, 1477);
  writeSilenceSamples(fd, toneDuration);
  
  
  close(fd);
  
}




