//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Wed Apr  4 20:40:28 PDT 2012
// Last Modified: Wed Apr  4 20:40:34 PDT 2012
// Filename:      ...sig/examples/all/menpat.cpp
// Web Address:   http://sig.sapp.org/examples/museinfo/humdrum/menpat.cpp
// Syntax:        C++; museinfo
//
// Description:   Extract mensural rhythmic patterns from each measure in 
//                each voice.
//

#include "humdrum.h"
#include "PerlRegularExpression.h"

#ifndef OLDCPP
   #include <sstream>
   #define SSTREAM stringstream
   #define CSTRING str().c_str()
   using namespace std;
#else
   #ifdef VISUAL
      #include <strstrea.h>     /* for windows 95 */
   #else
      #include <strstream.h>
   #endif
   #define SSTREAM strstream
   #define CSTRING str()
#endif
   

// function declarations
void  checkOptions(Options& opts, int argc, char* argv[]);
void  example(void);
void  usage(const char* command);
void  processVoice(int track, int voice, HumdrumFile& infile);
char* getNoteDuration(char* buffer, RationalNumber& dur, 
                                     int dot);
void  adjustMensuration(char* mensuration);
int   getDot(const char* strang);
int   getLastDataLine(HumdrumFile& infile);
void  printExclusiveInterpretations(void);
void  printDataTerminator(void);
void  getRhythmString(char* buffer, HumdrumFile& infile, 
                                     int line, int track, int voice, 
                                     RationalNumber& rscale, char* mensuration);
void  processVoice2(int track, int voice, HumdrumFile& infile);
void  markRhythm(char* buffer, HumdrumFile& infile, 
                                     int line, int track, int voice);
RationalNumber getNextMeasureAbsTime(HumdrumFile& infile, int line, 
                                     int track);
char* cleanRhythmString(char* buffer);

// global variables
Options   options;                 // database for command-line arguments
int       voiceQ       = 0;        // used with -v option
int       barQ         = 0;        // used with -b option
int       mensurationQ = 1;        // used with -M option
int       fileQ        = 0;        // used with -f option
int       pathQ        = 0;        // used with --path option
int       humdrumQ     = 0;        // used with -H option
const char* Filename   = "STDIN";  // used with -f option
int       nameQ        = 0;        // used with -n option
Array<Array<char> > Names;         // used with -n option
int       LastDataLine = 0;
int       markQ        = 0;        // used with -m option
const char* markSearch = "";       // used with -m option

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

int main(int argc, char* argv[]) {
   HumdrumFile infile;

   // process the command-line options
   checkOptions(options, argc, argv);

   // figure out the number of input files to process
   int numinputs = options.getArgCount();

   int i, j;

   if ((!markQ) && humdrumQ) {
      printExclusiveInterpretations();
   }

   Array<char> filebuffer;
   PerlRegularExpression pre;

   for (i=0; i<numinputs || i==0; i++) {
      infile.clear();

      // if no command-line arguments read data file from standard input
      if (numinputs < 1) {
         infile.read(cin);
      } else {
         Filename = options.getArg(i+1);
         infile.read(Filename);
         if (!pathQ) {
            filebuffer.setSize(strlen(Filename)+1);
            strcpy(filebuffer.getBase(), Filename);
            pre.sar(filebuffer, ".*\\/", "");
            Filename = filebuffer.getBase();
         }
      }
      // analyze the input file according to command-line options
      infile.analyzeRhythm("4");
      Array<int> kerntracks;
      infile.getTracksByExInterp(kerntracks, "**kern");
      Names.setSize(kerntracks.getSize());
      for (j=0; j<Names.getSize(); j++) {
         Names[j].setSize(1);
         Names[j][0] = '\0';
      }
      LastDataLine = getLastDataLine(infile);
      for (j=0; j<kerntracks.getSize(); j++) {
         if (markQ) {
            processVoice2(kerntracks[kerntracks.getSize()-j-1], j+1, infile);
         } else {
            processVoice(kerntracks[kerntracks.getSize()-j-1], j+1, infile);
            cout << endl;
         }
      }
   }

   if (markQ) {
      cout << infile;
      cout << "!!!RDF**kern: @ = matched pattern " 
           << markSearch 
           << " (color=\"#ff0000\")"
           << endl;
   } else {
      if (humdrumQ) {
         printDataTerminator();
      }
   }

   return 0;
}


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


//////////////////////////////
//
// printExclusiveInterpretations --
//

void printExclusiveInterpretations(void) {
   if (fileQ) {
      cout << "**file" << "\t";
   }
   if (barQ) {
      cout << "**bar" << "\t";
   }
   if (voiceQ) {
      cout << "**voice" << "\t";
   }
   if (mensurationQ) {
      cout << "**meter" << "\t";
   }
   if (fileQ || voiceQ || barQ || mensurationQ) {
      cout << "**dummy" << "\t";
   }
   cout << "**pattern" << "\n";
}



//////////////////////////////
//
// printDataTerminator --
//

void printDataTerminator(void) {
   if (fileQ) {
      cout << "*-" << "\t";
   }
   if (barQ) {
      cout << "*-" << "\t";
   }
   if (voiceQ) {
      cout << "*-" << "\t";
   }
   if (mensurationQ) {
      cout << "*-" << "\t";
   }
   if (fileQ || voiceQ || barQ || mensurationQ) {
      cout << "*-" << "\t";
   }
   cout << "*-" << "\n";
}



//////////////////////////////
//
// getLastDataLine --  return the last line index of the file which contains
//     data.
//

int getLastDataLine(HumdrumFile& infile) {
   int i;
   for (i=infile.getNumLines()-1; i>=0; i--) {
      if (infile[i].isData()) {
         return i;
      }
   }
   return -1;
}



///////////////////////////////
//
// processVoice2 -- 
//

void processVoice2(int track, int voice, HumdrumFile& infile) {
   RationalNumber rscale(1,1);

   int i, j;
   PerlRegularExpression pre;
   RationalNumber noteduration;
   RationalNumber tieduration;

   char mensuration[1024] = {0};
   // double metpos;
   //int mstart = 1;
   // double measuresum = 0.0;
   //int measure = 1;
   int xtrack;
   // int content = 0;
   int count = 0;
   int trackcol;
   int ignore = 0;

   char buffer[123123] = {0};


   for (i=0; i<=LastDataLine; i++) {

      if (infile[i].isGlobalComment()) {
         //if (pre.search(infile[i][0], 
         //         "primary-mensuration.*met\\(([^)]+)\\)")) {
         //   strcpy(mensuration, "m(");
         //   strcat(mensuration, pre.getSubmatch(1));
         //   strcat(mensuration, ")");
         //   adjustMensuration(mensuration);
         //}
         continue;
      }

      if (infile[i].isInterpretation()) {
         for (j=0; j<infile[i].getFieldCount(); j++) {
            xtrack = infile[i].getPrimaryTrack(j);
            if (xtrack != track) {
               continue;
            }
            if (pre.search(infile[i][j], "^\\*met\\(([^)]+)\\)")) {
               strcpy(mensuration, "m(");
               strcat(mensuration, pre.getSubmatch(1));
               strcat(mensuration, ")");
               adjustMensuration(mensuration);
            } else if (pre.search(infile[i][j], "^\\*I'(.*)")) {
               int slen = strlen(pre.getSubmatch(1));
               Names[voice-1].setSize(slen+1);
               strcpy(Names[voice-1].getBase(), pre.getSubmatch());
            } else if (pre.search(infile[i][j], "^\\*rscale:(\\d+)/(\\d+)")) {
               rscale = atoi(pre.getSubmatch(1));
               rscale /= atoi(pre.getSubmatch(2));
            } else if (pre.search(infile[i][j], "^\\*rscale:(\\d+)")) {
               rscale = atoi(pre.getSubmatch(1));
            } else if (pre.search(infile[i][j], "^\\*tacet$")) {
               ignore = 1;
            } else if (pre.search(infile[i][j], "^\\*xtacet$")) {
               ignore = 0;
            }
          
            break;
         }
         continue;
      }

      if (infile[i].isMeasure()) {
         trackcol = infile[i].getTrackColumn(track);
         if (trackcol < 0) { 
            continue;
         }
         if (strcmp(infile[i][trackcol], "=-") == 0) {
            // invisible barline not at measure boundary, ignore and continue;
            continue;
         }

         count = 0;
         //if (content) {
         //   cout << endl;
         //}
         if (strncmp(infile[i][0], "==", 2) == 0) {
            break;
         }

         // if (!ignore) {
            // found the start of a measure.  Go get the rhythm string
            // and check against the matchSearch string.
            buffer[0] = '\0';
            getRhythmString(buffer, infile, i+1, track, voice, rscale, 
                  mensuration);

   
            if (strcmp(buffer, markSearch) == 0) {
               markRhythm(buffer, infile, i+1, track, voice);
            }
         // }

      }

   }
}



//////////////////////////////
//
// cleanRhythmString --
//

char* cleanRhythmString(char* buffer) {
   if (strcmp(buffer, "qr_qr_qr_qr_qr_qr_qr_qr_qr_qr_qr_qr") == 0) {
      strcpy(buffer, "bdr");
      return buffer;
   }
   if (strcmp(buffer, "wr_wr_m_m") == 0) {
      strcpy(buffer, "br_m_m");
      return buffer;
   }
   if (strcmp(buffer, "wdr_wrd") == 0) {
      strcpy(buffer, "bdr");
      return buffer;
   }
   return buffer;
}



//////////////////////////////
//
// markRhythm -- 
//

void markRhythm(char* buffer, HumdrumFile& infile, int line, int track, 
      int voice) {
   strcpy(buffer, "");

   int i, j;
   RationalNumber noteduration;
   RationalNumber tieduration;
   PerlRegularExpression pre;

   char tbuffer[1024] = {0};
   // double metpos;
   // int mstart = 1;
   // double measuresum = 0.0;
   //int measure = 1;
   int xtrack;
   //int content = 0;
   int count = 0;
   int trackcol;

   for (i=line; i<=LastDataLine; i++) {

      if (infile[i].isMeasure()) {
         trackcol = infile[i].getTrackColumn(track);
         if (trackcol < 0) { 
            continue;
         }
         if (strcmp(infile[i][trackcol], "=-") == 0) {
            // invisible barline not at measure boundary, ignore and continue;
            continue;
         }

         count = 0;
         //if (content) {
         //   cout << endl;
         //}
         if (strncmp(infile[i][0], "==", 2) == 0) {
            break;
         }

         if (pre.search(infile[i][0], "[-.]")) {
            // ignore invisible and dashed barlines.
            continue;
         }

         // finished creating rhythm string.
         return;
      }

      if (!infile[i].isData()) {
         continue;
      }

      //int dot;
      for (j=0; j<infile[i].getFieldCount(); j++) {
         xtrack = infile[i].getPrimaryTrack(j);
         if (xtrack != track) {
            continue;
         }
         if (strcmp(infile[i][j], ".") == 0) {
            break;
         }

         strcpy(tbuffer, infile[i][j]);
         strcat(tbuffer, "@");
         infile[i].changeField(j, tbuffer);
      }
   }
}



///////////////////////////////
//
// getRhythmString -- 
//

void getRhythmString(char* buffer, HumdrumFile& infile, int line, int track, 
      int voice, RationalNumber& rscale, char* mensuration) {
   strcpy(buffer, "");

   int i, j;
   PerlRegularExpression pre;
   RationalNumber noteduration;
   RationalNumber tieduration;
   RationalNumber absbeat;

   RationalNumber nextmeasure;
   nextmeasure = getNextMeasureAbsTime(infile, line, track);

   char tbuffer[1024] = {0};
   int mstart = 1;
   // double measuresum = 0.0;
   //int measure = 1;
   int xtrack;
   int content = 0;
   int count = 0;
   int trackcol;

   for (i=line; i<=LastDataLine; i++) {

      if (infile[i].isGlobalComment()) {
         //if (pre.search(infile[i][0], 
         //         "primary-mensuration.*met\\(([^)]+)\\)")) {
         //   strcpy(mensuration, "m(");
         //   strcat(mensuration, pre.getSubmatch(1));
         //   strcat(mensuration, ")");
         //   adjustMensuration(mensuration);
         //}
         continue;
      }

      if (infile[i].isInterpretation()) {
         for (j=0; j<infile[i].getFieldCount(); j++) {
            xtrack = infile[i].getPrimaryTrack(j);
            if (xtrack != track) {
               continue;
            }
            if (pre.search(infile[i][j], "^\\*met\\(([^)]+)\\)")) {
               strcpy(mensuration, "m(");
               strcat(mensuration, pre.getSubmatch(1));
               strcat(mensuration, ")");
               adjustMensuration(mensuration);
            } else if (pre.search(infile[i][j], "^\\*rscale:(\\d+)/(\\d+)")) {
               rscale = atoi(pre.getSubmatch(1));
               rscale /= atoi(pre.getSubmatch(2));
            } else if (pre.search(infile[i][j], "^\\*rscale:(\\d+)")) {
               rscale = atoi(pre.getSubmatch(1));
            }
            break;
         }
         continue;
      }

      if (infile[i].isMeasure()) {
         trackcol = infile[i].getTrackColumn(track);
         if (trackcol < 0) { 
            continue;
         }
         if (strcmp(infile[i][trackcol], "=-") == 0) {
            // invisible barline not at measure boundary, ignore and continue;
            continue;
         }

         count = 0;
         //if (content) {
         //   cout << endl;
         //}
         if (strncmp(infile[i][0], "==", 2) == 0) {
            break;
         }

         if (pre.search(infile[i][0], "[-.]")) {
            // ignore invisible and dashed barlines.
            continue;
         }

         // finished creating rhythm string.
         return;
      }

      if (!infile[i].isData()) {
         continue;
      }

      int dot;
      for (j=0; j<infile[i].getFieldCount(); j++) {
         xtrack = infile[i].getPrimaryTrack(j);
         if (xtrack != track) {
            continue;
         }
         if (strcmp(infile[i][j], ".") == 0) {
            break;
         }
         if ((!mstart) && ((strchr(infile[i][j], '_') != NULL) ||
                        (strchr(infile[i][j], ']') != NULL))) {
            continue;
         }
         if (mstart && ((strchr(infile[i][j], '_') != NULL) ||
                        (strchr(infile[i][j], ']') != NULL))) {
            content = 1;
            strcat(buffer, "t");
         }
         count++;
         if (count > 1) {
            content = 1;
            strcat(buffer, "_");
         }
         mstart = 0;
         // metpos = infile[i].getBeat();
         // noteduration = Convert::kernToDurationR(infile[i][j]);
         noteduration = infile.getTiedDurationR(i,j);
         absbeat = infile[i].getAbsBeatR();
         if (absbeat + noteduration > nextmeasure) {
            noteduration = nextmeasure - absbeat;
         }
         noteduration *= rscale;
         dot = getDot(infile[i][j]);
         if (dot) {
            noteduration *= 2;
            noteduration /= 3;
         }
         strcat(buffer, getNoteDuration(tbuffer, noteduration, dot));
         content = 1;
         
         // cout << metpos;
         if (strchr(infile[i][j], 'r') != NULL) {
            content = 1;
            strcat(buffer, "r");
         } 
         break;
      }
   }
   cleanRhythmString(buffer);
}



///////////////////////////////
//
// processVoice -- 
//

void processVoice(int track, int voice, HumdrumFile& infile) {
   int i, j;
   PerlRegularExpression pre;
   RationalNumber noteduration;
   RationalNumber tieduration;
   RationalNumber absbeat;
   RationalNumber nextmeasure(0,1);
   RationalNumber rscale(1,1);

   char durbuffer[128] = {0};
   char mensuration[1024] = {0};
   // double metpos;
   int mstart = 1;
   // double measuresum = 0.0;
   int measure = 1;
   int xtrack;
   int content = 0;
   int count = 0;
   int trackcol;
   char buffer[10123] = {0};

   int ignore = 0; // turned on with *tacet and off with *xtacet


   for (i=0; i<=LastDataLine; i++) {

      if (infile[i].isGlobalComment()) {
         //if (pre.search(infile[i][0], 
         //         "primary-mensuration.*met\\(([^)]+)\\)")) {
         //   strcpy(mensuration, "m(");
         //   strcat(mensuration, pre.getSubmatch(1));
         //   strcat(mensuration, ")");
         //   adjustMensuration(mensuration);
         //}
         continue;
      }

      if (infile[i].isInterpretation()) {
         for (j=0; j<infile[i].getFieldCount(); j++) {
            xtrack = infile[i].getPrimaryTrack(j);
            if (xtrack != track) {
               continue;
            }
            if (pre.search(infile[i][j], "^\\*met\\(([^)]+)\\)")) {
               strcpy(mensuration, "m(");
               strcat(mensuration, pre.getSubmatch(1));
               strcat(mensuration, ")");
               adjustMensuration(mensuration);
            } else if (pre.search(infile[i][j], "^\\*I'(.*)")) {
               int slen = strlen(pre.getSubmatch(1));
               Names[voice-1].setSize(slen+1);
               strcpy(Names[voice-1].getBase(), pre.getSubmatch());
            } else if (pre.search(infile[i][j], "^\\*rscale:(\\d+)/(\\d+)")) {
               rscale = atoi(pre.getSubmatch(1));
               rscale /= atoi(pre.getSubmatch(2));
            } else if (pre.search(infile[i][j], "^\\*rscale:(\\d+)")) {
               rscale = atoi(pre.getSubmatch(1));
            } else if (pre.search(infile[i][j], "^\\*tacet$")) {
               ignore = 1;
            } else if (pre.search(infile[i][j], "^\\*xtacet$")) {
               ignore = 0;
            }
            break;
         }
         continue;
      }

      if (infile[i].isMeasure()) {
         trackcol = infile[i].getTrackColumn(track);
         if (trackcol < 0) { 
            continue;
         }
         if (strcmp(infile[i][trackcol], "=-") == 0) {
            // invisible barline not at measure boundary, ignore and continue;
            continue;
         }

         if (pre.search(infile[i][trackcol], "[-.]") &&
            (strcmp(infile[i][trackcol], "=1-"))) { 
            // ignore invisible barlines and dotted barlines.
            continue;
         }

         // if (!ignore) {
            nextmeasure = getNextMeasureAbsTime(infile, i+1, track);
            count = 0;
            if (content) {
               cleanRhythmString(buffer);
               cout << buffer;
               cout << endl;
               strcpy(buffer, "");
            }
            if (strncmp(infile[i][0], "==", 2) == 0) {
               break;
            }
            if (fileQ) {
               cout << Filename << "\t";
            }
   
            if (pre.search(infile[i][trackcol], "=(\\d+)")) {
// cout << " TOKEN=" << infile[i][trackcol] << " ";
               if (barQ) {
                  content = 1;
                  cout << "b";
                  if (measure < 100) {
                     cout << "0";
                  }
                  if (measure < 10) {
                     cout << "0";
                  }
                  cout << measure << "\t";
                  measure = atoi(pre.getSubmatch(1));
// cout << " MEASURE = " << measure << " ";
               }
            } else if (!pre.search(infile[i][trackcol], "[-.]")) {
               // handling case where a polymensural barline is not coincident
               // with a barline of the parts in primary mensuration.
               if (barQ) {
                  content = 1;
                  cout << "b";
                  if (measure < 100) {
                     cout << "0";
                  }
                  if (measure < 10) {
                     cout << "0";
                  }
                  cout << measure << "x\t";
               }
            }
   
            if (voiceQ) {
               content = 1;
               cout << "v";
               if (voice < 10) {
                  cout << "0";
               }
               cout << voice;
               if (nameQ) {
                  cout << "{";
                  cout << Names[voice-1];
                  cout << "}";
               }
               cout << "\t";
            }
            mstart = 1;
   
            if (mensurationQ && !pre.search(mensuration, "^\\s$")) {
               content = 1;
               cout << mensuration << "\t";
            }
         // }

         continue;
      }

      if (!infile[i].isData()) {
         continue;
      }

      //if (ignore) {
      //   continue;
      //}
 
      // getRhythmString(buffer, infile, i, track, voice, rscale, mensuration);
      // cout << buffer;

      int dot;
      for (j=0; j<infile[i].getFieldCount(); j++) {
         xtrack = infile[i].getPrimaryTrack(j);
         if (xtrack != track) {
            continue;
         }
         if (strcmp(infile[i][j], ".") == 0) {
            break;
         }
         if ((!mstart) && ((strchr(infile[i][j], '_') != NULL) ||
                        (strchr(infile[i][j], ']') != NULL))) {
            continue;
         }
         if (mstart && (fileQ || voiceQ || barQ || mensurationQ)) {
            content = 1;
            cout << "::\t";
         }
         if (mstart && ((strchr(infile[i][j], '_') != NULL) ||
                        (strchr(infile[i][j], ']') != NULL))) {
            content = 1;
            cout << "t";
         }
         count++;
         if (count > 1) {
            content = 1;
            // cout << "_";
            strcat(buffer, "_");
         }
         mstart = 0;

         // metpos = infile[i].getBeat();
         // noteduration = Convert::kernToDurationR(infile[i][j]);
         noteduration = infile.getTiedDurationR(i,j);
         absbeat = infile[i].getAbsBeatR();
         if (absbeat + noteduration > nextmeasure) {
            noteduration = nextmeasure - absbeat;
         }
         
         noteduration *= rscale;
         dot = getDot(infile[i][j]);
         if (dot) {
            noteduration *= 2;
            noteduration /= 3;
         }
         strcat(buffer, getNoteDuration(durbuffer, noteduration, dot));
         //cout << getNoteDuration(durbuffer, noteduration, dot);
         content = 1;
         
         // cout << metpos;
         if (strchr(infile[i][j], 'r') != NULL) {
            content = 1;
            strcat(buffer, "r");
            // cout << "r";
         } 

         
         break;
      }
   }

   if (strcmp(buffer, "") != 0) {
      cleanRhythmString(buffer);
      cout << buffer;
   }
}



//////////////////////////////
//
// getNextMeasureAbsTime --
//

RationalNumber getNextMeasureAbsTime(HumdrumFile& infile, int line, 
      int track) {
   int i;
   PerlRegularExpression pre;
   RationalNumber noteduration;
   RationalNumber tieduration;
   RationalNumber nextmeasure;
   RationalNumber rscale(1,1);

   int trackcol;
   int targeti = LastDataLine+1;

   for (i=line; i<=LastDataLine; i++) {

      if (infile[i].isMeasure()) {
         trackcol = infile[i].getTrackColumn(track);
         if (trackcol < 0) { 
            continue;
         }
         if (strcmp(infile[i][trackcol], "=-") == 0) {
            // invisible barline not at measure boundary, ignore and continue;
            continue;
         }

         if (pre.search(infile[i][trackcol], "[-.]") &&
            (strcmp(infile[i][trackcol], "=1-"))) { 
            // ignore invisible barlines and dotted barlines.
            continue;
         }

         targeti = i;
         break;
      }
   }


   return infile[targeti].getAbsBeatR();
}



//////////////////////////////
//
// getDot --
//

int getDot(const char* strang) {
   int len = strlen(strang);
   int output = 0;
   int i;
   for (i=0; i<len; i++) {
      if (strang[i] == ' ') {
         // don't check secondary chord notes
         break;
      }      
      if (strang[i] == '.') {
         output = 1;
         break;
      }
   }

   return output;
}



//////////////////////////////
//
// adjustMensuration --
//

void adjustMensuration(char* mensuration) {
   PerlRegularExpression pre;

   if (strcmp(mensuration, "m(C|)") == 0) {
      strcpy(mensuration, "menCutC");
      return;
   }

   if (strcmp(mensuration, "m(O)") == 0) {
      strcpy(mensuration, "menCircle");
      return;
   }

   if (strcmp(mensuration, "m(3)") == 0) {
      strcpy(mensuration, "men3");
      return;
   }

   if (strcmp(mensuration, "m(O|)") == 0) {
      strcpy(mensuration, "menCutCircle");
      return;
   }

   if (strcmp(mensuration, "m(2)") == 0) {
      strcpy(mensuration, "men2");
      return;
   }

   if (strcmp(mensuration, "m(3/2)") == 0) {
      strcpy(mensuration, "men3Over2");
      return;
   }

   if (strcmp(mensuration, "m(C)") == 0) {
      strcpy(mensuration, "menC");
      return;
   }

   if (strcmp(mensuration, "m(C.)") == 0) {
      strcpy(mensuration, "menCDot");
      return;
   }

   if (strcmp(mensuration, "m(C2)") == 0) {
      strcpy(mensuration, "menC2");
      return;
   }

   if (strcmp(mensuration, "m(C3)") == 0) {
      strcpy(mensuration, "menC3");
      return;
   }

   if (strcmp(mensuration, "m(Cr)") == 0) {
      strcpy(mensuration, "menReverseC");
      return;
   }

   if (strcmp(mensuration, "m(C|2)") == 0) {
      strcpy(mensuration, "menCutC2");
      return;
   }

   if (strcmp(mensuration, "m(C|3)") == 0) {
      strcpy(mensuration, "menCutC3");
      return;
   }

   if (strcmp(mensuration, "m(O.)") == 0) {
      strcpy(mensuration, "menCircleDot");
      return;
   }

   if (strcmp(mensuration, "m(O/3)") == 0) {
      strcpy(mensuration, "menCircleOver3");
      return;
   }

   if (strcmp(mensuration, "m(O2)") == 0) {
      strcpy(mensuration, "menCircle2");
      return;
   }

   if (strcmp(mensuration, "m(O|3/2)") == 0) {
      strcpy(mensuration, "menCutCircle3Over2");
      return;
   }

}



//////////////////////////////
//
// getNoteduration --
//
// b = breve
// 3 = triplet
// f = fusa (eighth note)
// m = minim (hale note)
// d = augmentation dot
// q = quarter note (semi-minim)
//

char* getNoteDuration(char* buffer, RationalNumber& dur, int dot) {
   strcpy(buffer, "");

   static RationalNumber eighthnote(1,2);
   static RationalNumber tripletbreve(16,3);
   static RationalNumber tripletwhole(8,3);
   static RationalNumber tripletminim(4,3);
   static RationalNumber tripletquarter(2,3);
   static RationalNumber dottedquarter(3,2);

   char tbuf[128] = {0};
   int triplet = 0;

   if (dur == eighthnote)     { 
      strcat(buffer, "f");   
   } else if (dur == tripletbreve)   { 
      strcat(buffer, "b");  
      triplet = 1;
   } else if (dur == eighthnote)     { 
      strcat(buffer, "f");   
   } else if (dur == tripletwhole)   { 
      strcat(buffer, "w");  
      triplet = 1;
   } else if (dur == tripletminim)   { 
      strcat(buffer, "m");  
      triplet = 1;
   } else if (dur == tripletquarter) { 
      strcat(buffer, "q");  
      triplet = 1;
   } else if (dur == dottedquarter)  { 
      strcat(buffer, "q");  
      dot = 1;
   } else if (dur ==  1)             { 
      strcat(buffer, "q");   
   } else if (dur ==  2)             { 
      strcat(buffer, "m");   
   } else if (dur ==  3)             { 
      strcat(buffer, "m");  
      dot = 1;
   } else if (dur ==  4)             { 
      strcat(buffer, "w");   
   } else if (dur ==  6)             { 
      strcat(buffer, "w");  
      dot = 1;
   } else if (dur ==  8)             { 
      strcat(buffer, "b");   
   } else if (dur == 12)             { 
      strcat(buffer, "b");  
      dot = 1;
   } else if (dur >= 16)             { 
      strcat(buffer, "l");  
   } else  {
      strcat(buffer, "X");
      sprintf(tbuf, "%dx%d", dur.getNumerator(), dur.getDenominator());
      strcat(buffer, tbuf);
   }

   // not bothering to check for double dotting...
   if (dot) {
      strcat(buffer, "d");
   }
   if (triplet) {
      strcat(buffer, "3");
   }

   return buffer;
}



//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//

void checkOptions(Options& opts, int argc, char* argv[]) {
   opts.define("v|voice=b",          "Display voice number");
   opts.define("b|bar=b",            "Display bar number");
   opts.define("H|humdrum=b",        "Output in Humdrum format");
   opts.define("n|name=b",           "Display the name of the parts");
   opts.define("p|path=b",           "Keep full pathname of file");
   opts.define("f|filename=b",       "Display filename");
   opts.define("M|no-mensuration=b", "Display mensuration");
   opts.define("m|mark=s",           "Mark given rhythmic pattern");

   opts.define("debug=b");           // determine bad input line num
   opts.define("author=b");          // author of program
   opts.define("version=b");         // compilation info
   opts.define("example=b");         // example usages
   opts.define("h|help=b");          // short description
   opts.process(argc, argv);
   
   // handle basic options:
   if (opts.getBoolean("author")) {
      cout << "Written by Craig Stuart Sapp, "
           << "craig@ccrma.stanford.edu, Apr 2012" << endl;
      exit(0);
   } else if (opts.getBoolean("version")) {
      cout << argv[0] << ", version: 4 Apr 2012" << endl;
      cout << "compiled: " << __DATE__ << endl;
      cout << MUSEINFO_VERSION << endl;
      exit(0);
   } else if (opts.getBoolean("help")) {
      usage(opts.getCommand());
      exit(0);
   } else if (opts.getBoolean("example")) {
      example();
      exit(0);
   }

   voiceQ       =  opts.getBoolean("voice");
   barQ         =  opts.getBoolean("bar");
   fileQ        =  opts.getBoolean("filename");
   pathQ        =  opts.getBoolean("path");
   nameQ        =  opts.getBoolean("name");
   markQ        =  opts.getBoolean("mark");
   markSearch   =  opts.getString("mark");
   humdrumQ     =  opts.getBoolean("humdrum");
   mensurationQ = !opts.getBoolean("no-mensuration");
}



//////////////////////////////
//
// example -- example usage of the quality program
//

void example(void) {
   cout <<
   "                                                                         \n"
   << endl;
}



//////////////////////////////
//
// usage -- gives the usage statement for the meter program
//

void usage(const char* command) {
   cout <<
   "                                                                         \n"
   << endl;
}



// md5sum: 5caea6420ea5a3409eae6949e9b8a743 menpat.cpp [20120523]