//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Tue May 22 12:20:05 PDT 2001
// Last Modified: Tue May 22 12:20:08 PDT 2001
// Filename:      ...sig/doc/examples/sig/sigfile/henonsnd/henonsnd.cpp
// Syntax:        C++; sig
//
// Description:   Generates Henon sequence for hearing by applying
//                a filter to held values of the sequence.
//

#include "sigAudio.h"

void   checkOptions(Options& opts, int argc, char* argv[]);
void   example(void);
void   usage(const char* command);
double henonseq(double a, double b);

// Option values
Options options;
double amp;          // used with the -amp option
double k;            // used with the -k option
double a;            // used with the -a option
double b;            // used with the -b option
double xstart;       // used with the -x option
double ystart;       // used with the -y option
int    hrate;        // used with the -r option

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

int main(int argc, char* argv[]) {
   checkOptions(options, argc, argv);

   // determine how many samples in the output based on the duration
   int numSamples;
   if (options.getInt("samples") > 0) {
      numSamples = options.getInt("samples");
   } else {
      numSamples = (int)(options.getDouble("duration") * 44100 + 0.5);
   }
  
   // prepare for a monophonic output file
   SoundHeader header;
   header.setHighMono();

   // Elements:
   Constant     henoninput;
   Smoother     smoother(k);
   DCBlock      nodc;
   Scale        scale(amp);
   SoundFileOut outsound(options.getArg(1), header);

   // Connections:
   smoother.connect(henoninput, 0);
   nodc.connect(smoother);
   scale.connect(nodc);
   outsound.connect(scale);

   for (int i=0; i<numSamples; i++) {
      if (i % hrate == 0) {
         henoninput.setValue(henonseq(a, b));
      }
      Tick(outsound);      
   }

   return 0;
}


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

//////////////////////////////
//
// henonseq -- generate a Henon sequence.
//

double henonseq(double a, double b) {
   static double x = 0.0;
   static double y = 0.0;
   double newx, newy;

   newx = 1 + a * x * x + b * y;
   newy = x;
   x = newx;
   y = newy;

   return x;
}



//////////////////////////////
//
// checkOptions -- handle command-line options.
//

void checkOptions(Options& opts, int argc, char** argv) {
   opts.define("amp=d:1.0", "amplitude scalar");
   opts.define("a|alpha|=d:-1.81496", "Henon sequence alpha parameter");
   opts.define("b|beta|=d:-0.208661", "Henon sequence beta parameter");
   opts.define("r|rate=i:100", "The number of samples to hold sequence");
   opts.define("x=d:0.0", "Initial value of x in henon sequence");
   opts.define("y=d:0.0", "Initial value of y in henon sequence");
   opts.define("k|smooth=d:0.0005", "Filter factor for smoothing filter");
   opts.define("d|dur|duration=d:1.0 second");
   opts.define("s|samples=i");
   opts.define("author=b");
   opts.define("version=b");
   opts.define("example=b");
   opts.define("help=b");
   opts.process(argc, argv);

   if (opts.getBoolean("author")) {
      cout << "Written by Craig Stuart Sapp, "
           << "craig@ccrma.stanford.edu, May 2001" << endl;
      exit(0);
   }
   if (opts.getBoolean("version")) {
      cout << "compiled: " << __DATE__ << endl;
      cout << SIG_VERSION << endl;
      exit(0);
   }
   if (opts.getBoolean("help")) {
      usage(opts.getCommand());
      exit(0);
   }
   if (opts.getBoolean("example")) {
      example();
      exit(0);
   }

   // can only have one output filename
   if (opts.getArgCount() == 0) {
      cout << "Error: need one output file name." << endl;
      usage(opts.getCommand());
      exit(1);
   } else if (opts.getArgCount() > 1) {
      cout << "Error: too many arguments.  Given " 
           << opts.getArgCount() << " but need only 1." << endl;
      usage(opts.getCommand());
      exit(1);
   }   

   hrate = opts.getInteger("rate");
   k = opts.getDouble("k");
   amp = opts.getDouble("amp");
   a = opts.getDouble("alpha");
   b = opts.getDouble("beta");
   xstart = opts.getDouble("x");
   ystart = opts.getDouble("y");

}
   


//////////////////////////////
//
// example -- gives example calls to the osc program.
//

void example(void) {
   cout << 
   "# henonsnd examples:                                                     \n"
   << endl;
}



//////////////////////////////
//
// usage -- how to run the osc program on the command line.
//

void usage(const char* command) {
   cout << 
   "                                                                         \n"
   "Creates an audio rate version of the henon sequence.                     \n"
   "                                                                         \n"
   "Usage: " << command << " [-d duration] outsound                          \n"
   "                                                                         \n"
   "Options:                                                                 \n"
   "   -d = duration of the oscillator in seconds (default 1.0).             \n"
   "   -s = duration in samples.  Overrides the -d option (default null)     \n"
   "   --options = list of all options, aliases and default values.          \n"
   "                                                                         \n"
   "                                                                         \n"
   << endl;
}



// md5sum: 8631f350f793e91aafa180b3be41ff76 henonsnd.cpp [20050403]