// morseCISC181.cc  P. Conrad   CISC181 Fall 2005
// Write a WAV file that spells out CISC181 in Morse Code 
// -.-. .. ... -.-. .---- ---.. .----

// @@@ Add your own comment here indicating that you
// @@@ updated the file; include your name, date, section, and "CISC181 proj1b"

#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"




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

  // for an explanation of ditDuration, dahDuration,
  // spaceInsideChars, spaceBetweenChars and spaceBetweenWords,
  // see the comment at the end of this file.

  double ditDuration = atof(argv[1]);

  
  if (ditDuration <= 0 || ditDuration > 1.0)
    {
      cerr << "Error: numSeconds must be between 0 and 1.0" << endl;
      exit(2);
    }

  double dahDuration = ditDuration * 3.0;
  double spaceInsideChars = ditDuration;
  double spaceBetweenChars = ditDuration * 3.0;
  double spaceBetweenWords = ditDuration * 7.0;

  const int samplesPerSecond = 11025;
  const int morseCodeFrequency = 500; // 500Hz

  int fd = open(argv[2], O_RDWR | O_CREAT, 0755 );
  
  // make sure open was successful
  
  if (fd < 0)
    {
      perror("open:");
      cerr << "File " << argv[2] << " could not be opened" << endl;
      exit(3);
    }
  
  // Compute number of dits for CISC


  double lengthInSeconds =
    lengthOfC(ditDuration,dahDuration,spaceInsideChars) + spaceBetweenChars +
    lengthOfI(ditDuration,dahDuration,spaceInsideChars) + spaceBetweenChars +
    lengthOfS(ditDuration,dahDuration,spaceInsideChars) + spaceBetweenChars +
    lengthOfC(ditDuration,dahDuration,spaceInsideChars) + spaceBetweenWords;

  int numSamples = (int) floor(lengthInSeconds * samplesPerSecond);
  
  // Write the header to the file
  
  writeWAVheader(numSamples, samplesPerSecond, fd);
  
  // Write the samples to the file
  
  writeC(fd, ditDuration, dahDuration, spaceInsideChars, morseCodeFrequency);
  writeSilenceSamples(fd, spaceBetweenChars);

  writeI(fd, ditDuration, dahDuration, spaceInsideChars, morseCodeFrequency);
  writeSilenceSamples(fd, spaceBetweenChars);

  writeS(fd, ditDuration, dahDuration, spaceInsideChars, morseCodeFrequency);
  writeSilenceSamples(fd, spaceBetweenChars);

  writeC(fd, ditDuration, dahDuration, spaceInsideChars, morseCodeFrequency);
  writeSilenceSamples(fd, spaceBetweenChars); //@@@ CHANGE to spaceBetweenWords


  close(fd);

  int status;

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


// Explanation of Morse Code "ditDuration" etc.
// 
// It is said that Morse code is a binary code because there
// are two symbols: dot and dash.  This is not exactly correct.
// 
// In a more precise view, there are five symbols that a sender
// or receiver of Morse Code must 
// 
//    dot (called a "dit" by Morse Code users)
//    dash (called a "dah" by Morse Code users)
//    spaceInsideCharacter (e.g. in S, which is ..., the
//      period of silence between dit one and dit two, and
//      between dit two and dit three
//    spaceBetweenCharacters (e.g. in ... - - - ..., SOS, the period
//      of silence between the last dit in the S, and the first
//      dah in the O, and between the last dah in the O, and the
//      first dit in the S.
//    spaceBetweenWords (e.g. if you spelling out words, the
//      period of silence between the last char of one word,
//      and the first char of the next word.
// 
//     
// At a first approximation, according to
// http://www.netwalk.com/~fsv/CWguide.htm
// the relationships between these are as follows: 
// 
//    dahDuration = ditDuration * 3.0;
//    spaceInsideCharacter = ditDuration;
//    spaceBetweenCharacters = ditDuration * 3.0;
//    spaceBetweenWords = ditDuration * 7.0;
// 
// To convert from WordsPerMinute to the ditDuration,
// the word PARIS is used as a standard.  The word PARIS
// (followed by a spaceBetweenWords) adds up to 50 ditDurations.
// So the expression:
//
//   w  (words/minute) * (1 minute/60 seconds) * (50 ditDurations)/(1 word)
//
// yields a value in ditDurations / second.  The reciprocal of that value
// gives us seconds per ditDuration.  For example, 5 wpm gives us:
//
//  5 (words/minutes) * (1 minutes/60 seconds) * (50 ditDurations)/(1 word)
// 
//  = (5 * 50)/60 = 250/60 = 4.166666666667 ditDurations / second
//  = 0.24 seconds per ditDuration
//
//  The PARIS standard is described at:
//    http://www.ac6v.com/morseaids.htm#MS
//
// However, in an effort to improve the understandability of code,
// "Farnsworth timing" is often used instead.  In Farnsworth
// timing, you use a fast wpm value for the dit,dah, and space between
// characters, and then add extra space to the spaceBetweenChars and 
// spaceBetweenWords, to acheive a slower overall wpm value.
//
// The following document specifies formulas for Farnsworth timing.
//  http://www.arrl.org/files/infoserv/tech/code-std.txt
//
// The way I read the document, the final formulas for 
// Tc and Tw given are "extra" time to be added to the 
// spaceBetweenCharacters and spaceBetweenWords.
//
// So, for example, when sending in Farnsworth timing at 5wpm/18wpm
// you would use the following (read the web page above for details)
// 
//     c = 18
//     s = 5
//
//     Ta = (60c - 37.2s)/sc
//     Tc = (3Ta)/19
//     Tw = (7Ta)/19
//
//  ditDuration, dahDuration and spaceInsideChars are taken from 18wpm, so
//    
//  18 (words/minutes) * (1 minutes/60 seconds) * (50 ditDurations)/(1 word)
// 
//  = (18 * 50)/60 = 900/60 = 15 ditDurations / second
//  = 0.0666666667 seconds per ditDuration
//  
//  dahDuration = 3 * ditDuration = 0.2 seconds
//  spaceInsideChars = ditDuration = 0.0666666667 seconds
//
// Ta = 9.933333333
// Tc = 1.568421053
// Tw = 3.659649123
//
// spaceBetweenChars =  ditDuration * 3  + Tc = 1.768421053
// spaceBetweenWords = ditDuration * 7  + Tw = 4.126315789








