//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Wed Jul 18 12:42:51 PDT 2001
// Last Modified: Wed Jul 18 12:42:54 PDT 2001
// Filename:      ...sig/doc/examples/sig/sigfile/pitch2midi/pitch2midi.cpp
// Syntax:        C++; sig
//
// Description:   extract the pitch from a microphone and convert to
//                MIDI.
//

#include "sig.h"

#include <iostream.h>
#include <stdlib.h>
#include <iomanip.h>

void checkOptions(Options& opts);
void example(void);
void usage(const char* command);


#define PITCH_HPS 0
#define PITCH_ML  1

// User interfaction variables:
int palgorithm = PITCH_HPS;      // pitch detection algorithm
int displayQ = 0;                // for displaying pitch information
KeyboardInput interfaceKeyboard; // for computer keyboard interface
Voice midiout;
int recordQ = 0;                 // for recording pitch info

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

int main(int argc, char* argv[]) {
   Options options(argc, argv);
   checkOptions(options);
   cout << "Press space for detailed information" << endl;
 
   fstream debugfile("/tmp/soundinfo.dat", ios::out);
  
   // Elements:
   AudioIn audioin;
   audioin.open();

   Pitch        pitch;

   // Connections:
   pitch.connect(audioin);

   switch (palgorithm) {
      case PITCH_HPS: pitch.doHPS(); break;
      case PITCH_ML:  pitch.doML(); break;
      default:        pitch.doHPS();
   }

   int oldfund = -1;   // the old MIDI pitch note
   int fund = -1;      // the new MIDI pitch note
   int keepfund = -1;  // the currently playing note

   char buffer[1024] = {0};

   Action action;
   cout << "**sample\t**sec\t**pitch\t**amp\n";
   int i = 0;
   int command = 0;
   while (command != 'Q') {
      action.tick(pitch, 512);
      if (displayQ) {
         cout << i*512 << "\t";
         cout.precision(3);
         cout << i*512/pitch.getSrate();
         cout.precision(7);
         // cout << "\t" << pitch.output(0)/4096.0 * 44100.0;
         cout << "\t" << pitch.output(0);
         cout << "\t" << pitch.output(1) << endl;
      }
      if (recordQ) {
         debugfile << pitch.output(0)  << "\n";
      }

      // keep track of MIDI note information
      if (pitch.output(1) > 0.001) {
         oldfund = fund;
         fund = Convert::freq2midi(pitch.output(0));
         if (fund == oldfund) {
            if (fund != keepfund && fund > 0 && fund < 128) {
               midiout.play(0, fund, 64);
               keepfund = fund;
               cout << " note:" << Convert::base12ToKern(buffer, keepfund) 
                    << flush;
            }
         }
      }

      i++;
      if (i % 10 == 0) {
         if (interfaceKeyboard.hit()) {
            command = interfaceKeyboard.getch();
            switch (command) {
               case ' ':  displayQ = !displayQ;  break;
               case 'r':  
                  recordQ = !recordQ;    
                  cout << "Record = " << recordQ << endl;
                  debugfile << "Record state = " << recordQ << "\n";
                  break;
            }
         }
      }
   }
   cout << "*-\t*-\t*-\t*-\n";

   return 0;
}


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


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

void checkOptions(Options& opts) {
   opts.define("a|amp|amp-env=s:0 1 1 1");
   opts.define("d|dur|duration=d:1.0 second");
   opts.define("s|samples=i");
   opts.define("f|freq|freq-env=s:0 440 1 440");
   opts.define("H|HPS|hps=b", "use the HPS pitch detection algorithm");
   opts.define("M|ML|ml=b", "use the ML pitch detection algorithm");
   opts.define("p|midiout|port=i:0", "MIDI output port");
   opts.define("l|list|listmidiports=b", "List number of MIDI output ports");

   opts.define("author=b");
   opts.define("version=b");
   opts.define("example=b");
   opts.define("help=b");
   opts.process();

   if (opts.getBoolean("author")) {
      cout << "Written by Craig Stuart Sapp, "
           << "craig@ccrma.stanford.edu, July 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: no command line arguments needed." << endl;
      usage(opts.getCommand());
      exit(1);
   } 

   if (opts.getBoolean("HPS")) {
      palgorithm = PITCH_HPS;
   }

   if (opts.getBoolean("ML")) {
      palgorithm = PITCH_ML;
   }

   if (opts.getBoolean("listmidiports")) {
      cout << "There are : " << midiout.getNumPorts() << " MIDI output ports"
           << endl;
      exit(1);
   }

   midiout.setPort(opts.getInteger("midiout"));
}
   


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

void example(void) {
}



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

void usage(const char* command) {
}



// md5sum: 41ee9ebf4df79ff4df9c2f5899b98236 pitch2midi.cpp [20050403]