// mary.cc  P. Conrad   CISC181 Fall 2005
// Write a WAV file that plays a bit of Mary Had a Little Lamb.
// Specify output name on 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

#include "endian.h"
#include "wavLibrary.h"

void writeNote(int fd, double beatDuration, double freq)
{
  writeNoiseSamples(fd, 0.1 * beatDuration, 0.5 ); // 0.5 is the volume
  writeSineWaveSamples(fd, 0.4 * beatDuration, freq );
  writeSilenceSamples(fd, 0.5 * beatDuration);
}

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


  // An excerpt from Mary Had a Little Lamb
  // Four seconds, four notes per second
  // Each note is 1/8 of second, with 1/8 of a second between
  // notes. (1/8 = 0.125 seconds)
  //
  // E D C D | E E E (rest) | D D D (rest) |  E G G (rest) |

  double duration = 4.0;

  const int samplesPerSecond = 11025;

  const double halfStep = 1.05946309436; // this is the "twelth root of two"



  int fd = open(argv[1], O_RDWR | O_CREAT , 0755); // @@@ specifies mode
  
  // make sure open was successful
  
  if (fd < 0)
    {
      cerr << "File " << argv[1] << " could not be opened" << endl;
      perror("open:");
      exit(1);
    }
  
  int numSamples = (int) floor(duration * samplesPerSecond);
    
  // Write the header to the file
  
  writeWAVheader(numSamples, samplesPerSecond, fd);

  // An excerpt from Mary Had a Little Lamb
  // Four seconds, four notes per second
  // Each note is 1/8 of second, with 1/8 of a second between
  // notes. (1/8 = 0.125 seconds)
  //
  // E D C D | E E E (rest) | D D D (rest) |  E G G (rest) |

  const double freqA = 440.00; // A is 440 Hz
  const double freqC = freqA / (pow(halfStep, 9));  // C is 9 "half-steps" below A
  const double freqD = freqA / (pow(halfStep, 7));  // D is 7 "half-steps" below A
  const double freqE = freqA / (pow(halfStep, 5));  // E is 5 "half-steps" below A
  const double freqG = freqA / (pow(halfStep, 2));  // G is 2 "half-steps" below A

  
  const double beatDuration = 0.250; // four beats per second


  writeNote(fd, beatDuration, freqE);
  writeNote(fd, beatDuration, freqD);
  writeNote(fd, beatDuration, freqC);
  writeNote(fd, beatDuration, freqD);

  writeNote(fd, beatDuration, freqE);
  writeNote(fd, beatDuration, freqE);
  writeNote(fd, beatDuration, freqE);
  writeSilenceSamples(fd, beatDuration);

  writeNote(fd, beatDuration, freqD);
  writeNote(fd, beatDuration, freqD);
  writeNote(fd, beatDuration, freqD);
  writeSilenceSamples(fd, beatDuration);

  writeNote(fd, beatDuration, freqE);
  writeNote(fd, beatDuration, freqG);
  writeNote(fd, beatDuration, freqG);
  writeSilenceSamples(fd, beatDuration);

  close(fd);

  
  int status;
  
  // leading zero on 0755 is NECESSARY; makes it an octal number
  status = chmod(argv[1],0755); // like a chmod at command line
  
  if (status != 0)
    {
      perror("Trouble with chmod command");
      exit(4);
    }
  
  return 0;
  
}



