//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Wed Jan 23 21:10:32 PST 2002
// Last Modified: Sun Feb  3 11:08:04 PST 2002 (updated for soundfile 2.0)
// Filename:      ...soundfile/examples/multi2mono.cpp
// Syntax:        C++ 
//
// Description:   Adds all channels in the input sound file and writes
//                a sound file with the summation of all channels.
//                Amplitude scaling factor can be given to prevent
//                clipping if necessary.
//

#include "soundfile.h"
#include <stdlib.h>

#ifndef OLDCPP
   #include <iostream>
   #include <fstream>
   using namespace std;
#else
   #include <iostream.h>
   #include <fstream.h>
#endif

void getClickTimes(Array<long>& clicktimes, const char* filename);


//////////////////////////////////////////////////////////////////////////

int main(int argc, char** argv) {
   Options options;
   options.define("a|amp=d:1.0",       "amplitude scaling factor");
   options.define("c|click-amp=d:0.15","click track amplitude scaling factor");
   options.process(argc, argv);
   
   double amp      = options.getDouble("amp");
   double clickamp = options.getDouble("click-amp");
   const char* inputname  = options.getArg(1);
   const char* clicktrack = options.getArg(2);
   const char* outputname = options.getArg(3);

   Array<long> clicktimes;
   getClickTimes(clicktimes, clicktrack);

   SoundFileRead  insound(inputname);
   SoundHeader    header = insound;
   header.setChannels(2);
   SoundFileWrite outsound(outputname, header);

   int i, channel;
   double newsample;
   double clicksample;

   for (i=0; i<clicktimes.getSize(); i++) {
      clicktimes[i] = (long)(clicktimes[i] / 1000.0 * insound.getSrate() + 0.5);
      cout << clicktimes[i] << endl;
   }

   int clicki = 0;
   int clickstatus = 0;
   int clickcount = clicktimes.getSize();

   for (i=0; i<insound.getSamples(); i++) {
      newsample = 0.0;
      for (channel = 0; channel < insound.getChannels(); channel++) {
         newsample += insound.getCurrentSampleDouble(channel);
      }
      if ((clicki < clickcount) && (clicktimes[clicki] == i)) {
         clickstatus = 1;
         clicki++;
      }
      if (clickstatus) {
         clicksample = ((rand() * 2.0)/INT_MAX - 1.0) * clickamp;
         clickstatus++;
         if (clickstatus > 44) {
            clickstatus = 0;
         }
      } else {
         clicksample = 0.0;
      }
      outsound.writeSampleDouble(clicksample);
      outsound.writeSampleDouble(amp * newsample/insound.getChannels());
      insound.incrementSample();
   }

   return 0;
}



//////////////////////////////
//
// getClickTimes --
//

void getClickTimes(Array& clicktimes, const char* filename) {

   ifstream clickfile(filename);
   if (!clickfile.is_open()) {
      cerr << "Error: cannot open file " << filename << endl;
   }

   long input;
   clicktimes.setSize(100000);
   clicktimes.setGrowth(100000);
   clicktimes.setSize(0);

   clickfile >> input;
   while (!clickfile.eof()) {
      clicktimes.append(input);
      clickfile >> input;
   }
}


// md5sum: 5090326fba542fed193ee26abbe6281a clicktrack.cpp [20051017]