Goto: [ Program Documentation ]

//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Wed Apr  3 20:44:21 PST 2002
// Last Modified: Wed Apr  3 20:44:25 PST 2002
// Filename:      ...sig/examples/all/triped.cpp
// Web Address:   http://sig.sapp.org/examples/museinfo/humdrum/triped.cpp
// Syntax:        C++; museinfo
//
// Description:   2-D correlation plot generate for pitch, duration,
//                and metric level.
//

#include "humdrum.h"

#include <math.h>
#include <string.h>

typedef Array<float> ArrayFloat;

// function declarations
void   checkOptions(Options& opts, int argc, char* argv[]);
void   example(void);
void   usage(const char* command);
void   printAnalysis(HumdrumFile& infileA, HumdrumFile& infileB,
                                 Array<ArrayFloat>& pitchAnalysis,
                                 Array<ArrayFloat>& durationAnalysis, 
                                 Array<ArrayFloat>& levelAnalysis);
void   printAnalysisRegular(Array<ArrayFloat>& pitchAnalysis,
                                 Array<ArrayFloat>& durationAnalysis, 
                                 Array<ArrayFloat>& levelAnalysis);
void   printAnalysisFlip(Array<ArrayFloat>& pitchAnalysis,
                                 Array<ArrayFloat>& durationAnalysis, 
                                 Array<ArrayFloat>& levelAnalysis);
void   printAnalysisFull(Array<ArrayFloat>& pitchAnalysis,
                                 Array<ArrayFloat>& durationAnalysis, 
                                 Array<ArrayFloat>& levelAnalysis);
void   printAnalysisFullDur(HumdrumFile& infileA, HumdrumFile& infileB,
                                 Array<ArrayFloat>& pitchAnalysis,
                                 Array<ArrayFloat>& durationAnalysis, 
                                 Array<ArrayFloat>& levelAnalysis);
void   generateLevelAnalysis(HumdrumFile& infileA, HumdrumFile& infileB, 
                                 Array<ArrayFloat>& levelAnalysis);
void   generateDurationAnalysis(HumdrumFile& infileA, HumdrumFile& infileB, 
                                 Array<ArrayFloat>& durationAnalysis);
void   generatePitchAnalysis(HumdrumFile& infileA, HumdrumFile& infileB, 
                                 Array<ArrayFloat>& pitchAnalysis);
void   printAnalysisData(HumdrumFile& infileA, HumdrumFile& infileB,
                                 const char* filenameA, const char* filenameB);
void   printAnalysisFile(HumdrumFile& infile);
void   createDurationMapping(Array<int>& lookupA, Array<int>& lookupB, 
                                 HumdrumFile& infileA, HumdrumFile& infileB);
void   printAnalysisDur(HumdrumFile& infileA, HumdrumFile& infileB,
                                 Array<ArrayFloat>& pitchAnalysis,
                                 Array<ArrayFloat>& durationAnalysis, 
                                 Array<ArrayFloat>& levelAnalysis);
void   printAnalysisWhiteDur(HumdrumFile& infileA, HumdrumFile& infileB,
                                 Array<ArrayFloat>& pitchAnalysis,
                                 Array<ArrayFloat>& durationAnalysis, 
                                 Array<ArrayFloat>& levelAnalysis);
void   getPitchData(Array<int>& pitchA, HumdrumFile& infileA, 
                                 int intervalQ, int pitchclassQ);

// global variables
Options   options;            // database for command-line arguments
int       repeat    = 5;      // pixel magnification size
int       allQ      = 0;      // draw 4 pictures
int       flipQ     = 0;      // flip the vertical axis
int       dataQ     = 0;      // print analysis data along with input data
int       eventQ    = 0;      // display by event rather than duration
int       redQ      = 1;      // display pitch information
int       greenQ    = 1;      // display duration information
int       blueQ     = 1;      // display metric information
int       whiteQ    = 0;      // display only highly equivalent sections
int       intervalQ = 0;      // use intervals instead of absolute pitch
int       pclassQ   = 0;      // use pitch class instead of absolute pitch

int minA = 1;
int minB = 1;
float totaldurA = 1.0;
float totaldurB = 1.0;


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

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

   HumdrumFile infileA;
   HumdrumFile infileB;
   const char* filenameA = "";
   const char* filenameB = "";

   filenameA = options.getArg(1);
   if (options.getArgCount() < 2) {
      filenameB = options.getArg(1);
   } else {
      filenameB = options.getArg(2);
   }
   infileA.read(filenameA);
   infileB.read(filenameB);
   infileA.analyzeRhythm();
   infileB.analyzeRhythm();
   minA = infileA.getMinTimeBase();
   minB = infileB.getMinTimeBase();
   totaldurA = infileA.getTotalDuration();
   totaldurB = infileB.getTotalDuration();

   Array<ArrayFloat> levelAnalysis;
   Array<ArrayFloat> durationAnalysis;
   Array<ArrayFloat> pitchAnalysis;

   if (dataQ) {
      printAnalysisData(infileA, infileB, filenameA, filenameB);
      exit(0);
   }

   generateLevelAnalysis(infileA,    infileB, levelAnalysis);
   generateDurationAnalysis(infileA, infileB, durationAnalysis);
   generatePitchAnalysis(infileA,    infileB, pitchAnalysis);

   printAnalysis(infileA, infileB, pitchAnalysis, durationAnalysis, 
         levelAnalysis);

   return 0;
}


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


//////////////////////////////
//
// printAnalysisData --
//

void printAnalysisData(HumdrumFile& infileA, HumdrumFile& infileB,
      const char* filenameA, const char* filenameB) {
   printAnalysisFile(infileA);
   if (strcmp(filenameA, filenameB) != 0) {
      cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
           << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
      printAnalysisFile(infileB);
   }
}



//////////////////////////////
//
// printAnalysisFile --
//

void printAnalysisFile(HumdrumFile& infile) {
   int i;
   Array<int> rhylev;
   infile.analyzeMetricLevel(rhylev);

   for (i=0; i<infile.getNumLines(); i++) {
      switch (infile[i].getType()) {
         case E_humrec_data_comment:
            cout << infile[i] << "\t!\t!\t!\n";
            break;
         case E_humrec_data_kern_measure:
            cout << infile[i] << "\t"
                 << infile[i][0] << "\t"
                 << infile[i][0] << "\t"
                 << infile[i][0] << "\n";
            break;
         case E_humrec_interpretation:
            if (strncmp(infile[i][0], "**", 2) == 0) {
               cout << infile[i] << "\t**mlev\t**dur\t**pitch\n";
            } else if (strcmp(infile[i][0], "*-") == 0) {
               cout << infile[i] << "\t*-\t*-\t*-\n";
            } else if (strncmp(infile[i][0], "*>", 2) == 0) {
               cout << infile[i] << "\t"
                    << infile[i][0] << "\t"
                    << infile[i][0] << "\t"
                    << infile[i][0] << "\n";
            } else {
               cout << infile[i] << "\t*\t*\t*\n";
            }
            break;
         case E_humrec_data:
            if (strcmp(infile[i][0], ".") == 0 ||
                strchr(infile[i][0], '_') != NULL ||
                strchr(infile[i][0], ']') != NULL ) {
               cout << infile[i] << "\t.\t.\t.\n";
            } else {
               int pitch;
               char buffer[16] = {0};
               pitch = Convert::kernToBase40(infile[i][0]);
               cout << infile[i] << "\t"
                    << -rhylev[i] << "\t"
                    << infile.getTiedDuration(i, 0) << "\t"
                    << Convert::base40ToKern(buffer, pitch)
                    << "\n";
            }
            break;
         case E_humrec_none:
         case E_humrec_empty:
         case E_humrec_global_comment:
         case E_humrec_bibliography:
         default:
            cout << infile[i] << "\n";
            break;
      }
   }

}



//////////////////////////////
//
// printAnalysis -- 
//

void printAnalysis(HumdrumFile& infileA, HumdrumFile& infileB, 
      Array<ArrayFloat>& pitchAnalysis, Array<ArrayFloat>& durationAnalysis, 
      Array<ArrayFloat>& levelAnalysis) {

   // binary display options:
   // 
   // eventQ == display by event rather than duration
   // allQ   == print four pictures rather than one
   //   linearQ == allQ with four pictures in one row.
   // flipQ  == print with vertical axis flipped
   // 
   // redQ   = printRed picture
   // greenQ = printRed picture
   // blueQ  = printRed picture
   // whiteQ = print only parts of pictures which agree with all
   //          three measurements of musical information

   if (whiteQ) {
      printAnalysisWhiteDur(infileA, infileB, pitchAnalysis, durationAnalysis, 
            levelAnalysis);
      return;
   }


   if (eventQ == 0) {
      if (allQ) {
         printAnalysisFullDur(infileA, infileB, pitchAnalysis, durationAnalysis, 
               levelAnalysis);
      } else {
         printAnalysisDur(infileA, infileB, pitchAnalysis, durationAnalysis, 
               levelAnalysis);
      }

   } else {
      if (allQ) {
         printAnalysisFull(pitchAnalysis, durationAnalysis, levelAnalysis);
      } else if (flipQ && !allQ) {
         printAnalysisFlip(pitchAnalysis, durationAnalysis, levelAnalysis);
      } else {
         printAnalysisRegular(pitchAnalysis, durationAnalysis, levelAnalysis);
      }
   }

}



//////////////////////////////
//
// printAnalysisDur -- starts in lower left-hand corner.  Scaled to
//     duration of the two pieces of music.
//

void printAnalysisDur(HumdrumFile& infileA, HumdrumFile& infileB, 
      Array<ArrayFloat>& pitchAnalysis, Array<ArrayFloat>& durationAnalysis, 
      Array<ArrayFloat>& levelAnalysis) {

   unsigned char red;
   unsigned char green;
   unsigned char blue;
   int i, j;
   int r, s;
   Array<int> lookupA;
   Array<int> lookupB;
   createDurationMapping(lookupA, lookupB, infileA, infileB);
   int width = lookupB.getSize();
   int height = lookupA.getSize();
   int v1, v2;

   cout << "P6\n" << width * repeat << " " << height * repeat << "\n255\n";

   for (i=0; i<height; i++) {
      v1 = lookupA[height - i - 1];
      for (r=0; r<repeat; r++) {
         for (j=0; j<width; j++) {
            v2 = lookupB[j];
            for (s=0; s<repeat; s++) {
               if (redQ) red   = 0xff & (int)(pitchAnalysis[v1][v2] * 255 + 0.5);
               else      red   = 0x00;
               if (greenQ) green = 0xff & (int)(durationAnalysis[v1][v2] * 255 + 0.5);
               else        green = 0x00;
               if (blueQ) blue  = 0xff & (int)(levelAnalysis[v1][v2] * 255 + 0.5);
               else       blue  = 0x00;
               cout << red << green << blue;
            }
         }
      }
   }
   cout << flush;

}



//////////////////////////////
//
// printAnalysisWhiteDur -- starts in lower left-hand corner.  Scaled to
//     duration of the two pieces of music.
//

void printAnalysisWhiteDur(HumdrumFile& infileA, HumdrumFile& infileB, 
      Array<ArrayFloat>& pitchAnalysis, Array<ArrayFloat>& durationAnalysis, 
      Array<ArrayFloat>& levelAnalysis) {

   unsigned char red;
   unsigned char green;
   unsigned char blue;
   int i, j;
   int r, s;
   Array<int> lookupA;
   Array<int> lookupB;
   createDurationMapping(lookupA, lookupB, infileA, infileB);
   int width = lookupB.getSize();
   int height = lookupA.getSize();
   int v1, v2;

   cout << "P6\n" << width * repeat << " " << height * repeat << "\n255\n";

   for (i=0; i<height; i++) {
      v1 = lookupA[height - i - 1];
      for (r=0; r<repeat; r++) {
         for (j=0; j<width; j++) {
            v2 = lookupB[j];
            for (s=0; s<repeat; s++) {
               if (redQ) red   = 0xff & (int)(pitchAnalysis[v1][v2] * 255 + 0.5);
               else      red   = 0x00;
               if (greenQ) green = 0xff & (int)(durationAnalysis[v1][v2] * 255 + 0.5);
               else        green = 0x00;
               if (blueQ) blue  = 0xff & (int)(levelAnalysis[v1][v2] * 255 + 0.5);
               else       blue  = 0x00;
               if (red == green && green == blue) {
                  cout << red << green << blue;
               } else {
                  red = green = blue = 0x00;
                  cout << red << green << blue;
               }
            }
         }
      }
   }
   cout << flush;

}



//////////////////////////////
//
// createDurationMapping --
//

void createDurationMapping(Array<int>& lookupA, Array<int>& lookupB, 
      HumdrumFile& infileA, HumdrumFile& infileB) {

   double mindurA = 4.0 / minA;
   double mindurB = 4.0 / minB;

   lookupA.setSize((int)(totaldurA / mindurA) + 1000);
   lookupA.setSize(0);
   lookupB.setSize((int)(totaldurB / mindurB) + 1000);
   lookupB.setSize(0);

   lookupA.setAll(-1);
   lookupB.setAll(-1);

   int realindex;
   double duration = 0.0;

   realindex = 0;
   int i, j;
   for (i=0; i<infileA.getNumLines(); i++) {
      if (!infileA[i].isData()) {
         continue;
      }
      if (strcmp(infileA[i][0], ".") == 0     ||
          strchr(infileA[i][0], '_') != NULL  ||
          strchr(infileA[i][0], ']') != NULL) {
         continue;
      }
      duration = infileA.getTiedDuration(i, 0);
      for (j=0; j<(int)(duration / mindurA + 0.001); j++) {
         lookupA.append(realindex);
      }
      realindex++;
   }

   realindex = 0;
   for (i=0; i<infileB.getNumLines(); i++) {
      if (!infileB[i].isData()) {
         continue;
      }
      if (strcmp(infileB[i][0], ".") == 0     ||
          strchr(infileB[i][0], '_') != NULL  ||
          strchr(infileB[i][0], ']') != NULL) {
         continue;
      }
      duration = infileB.getTiedDuration(i, 0);
      for (j=0; j<(int)(duration / mindurB + 0.001); j++) {
         lookupB.append(realindex);
      }
      realindex++;
   }
}



//////////////////////////////
//
// printAnalysisRegular -- starts in lower left-hand corner.
//

void printAnalysisRegular(Array<ArrayFloat>& pitchAnalysis, 
      Array<ArrayFloat>& durationAnalysis, Array<ArrayFloat>& levelAnalysis) {

   unsigned char red;
   unsigned char green;
   unsigned char blue;
   int i, j;
   int r, s;
   int width = levelAnalysis[0].getSize();
   int height = levelAnalysis.getSize();
   int v1;

   cout << "P6\n" << width * repeat << " " << height * repeat << "\n255\n";

   for (i=0; i<height; i++) {
      v1 = height - i - 1;
      for (r=0; r<repeat; r++) {
         for (j=0; j<width; j++) {
            for (s=0; s<repeat; s++) {
               if (redQ) red   = 0xff & (int)(pitchAnalysis[v1][j] * 255 + 0.5);
               else      red   = 0x00;
               if (greenQ) green = 0xff & (int)(durationAnalysis[v1][j] * 255 + 0.5);
               else        green = 0x00;
               if (blueQ) blue  = 0xff & (int)(levelAnalysis[v1][j] * 255 + 0.5);
               else       blue  = 0x00;
               cout << red << green << blue;
            }
         }
      }
   }
   cout << flush;

}



//////////////////////////////
//
// printAnalysisFullDur -- print four pictures with duration weighting
//

void printAnalysisFullDur(HumdrumFile& infileA, HumdrumFile& infileB, 
      Array<ArrayFloat>& pitchAnalysis, Array<ArrayFloat>& durationAnalysis, 
      Array<ArrayFloat>& levelAnalysis) {

   unsigned char red;
   unsigned char green;
   unsigned char blue;
   int i, j;
   int r, s;
   Array<int> lookupA;
   Array<int> lookupB;
   createDurationMapping(lookupA, lookupB, infileA, infileB);
   int width = lookupB.getSize();
   int height = lookupA.getSize();
   int v1 = 0;
   int v2 = 0;

   int imageWidth  = width * repeat * 2 + 1;
   int imageHeight = height * repeat * 2 + 1;

   cout << "P6\n" << imageWidth << " " << imageHeight << "\n255\n";

   for (i=0; i<height; i++) {
      v1 = lookupA[height -i - 1];
      for (r=0; r<repeat; r++) {
         // print row: Full picture
         for (j=0; j<width; j++) {
            v2 = lookupB[j];
            for (s=0; s<repeat; s++) {
               red   = 0xff & (int)(pitchAnalysis[v1][v2] * 255 + 0.5);
               green = 0xff & (int)(durationAnalysis[v1][v2] * 255 + 0.5);
               blue  = 0xff & (int)(levelAnalysis[v1][v2] * 255 + 0.5);
               cout << red << green << blue;
            }
         }

         // print a white pixel to separate pictures
         red = green = blue = 0xff;
         cout << red << green << blue;

         // print next picture: pitch (red)
         for (j=0; j<width; j++) {
            v2 = lookupB[j];
            for (s=0; s<repeat; s++) {
               red   = 0xff & (int)(pitchAnalysis[v1][v2] * 255 + 0.5);
               green = 0;
               blue  = 0;
               cout << red << green << blue;
            }
         }
      }
   }

   // print a small white line to separate pictures
   for (i=0; i<imageWidth; i++) {
      red = green = blue = 0xff;
      cout << red << green << blue;
   }

   for (i=0; i<height; i++) {
      v1 = lookupA[height - i - 1];
      for (r=0; r<repeat; r++) {
         // print row: duration (green)
         for (j=0; j<width; j++) {
            v2 = lookupB[j];
            for (s=0; s<repeat; s++) {
               red   = 0;
               green = 0xff & (int)(durationAnalysis[v1][v2] * 255 + 0.5);
               blue  = 0;
               cout << red << green << blue;
            }
         }

         // print a white pixel to separate pictures
         red = green = blue = 0xff;
         cout << red << green << blue;

         // print next picture: meter (blue)
         for (j=0; j<width; j++) {
            v2 = lookupB[j];
            for (s=0; s<repeat; s++) {
               red   = 0;
               green = 0;
               blue  = 0xff & (int)(levelAnalysis[v1][v2] * 255 + 0.5);
               cout << red << green << blue;
            }
         }
      }
   }
   cout << flush;

}



//////////////////////////////
//
// printAnalysisFull -- print four pictures
//

void printAnalysisFull(Array<ArrayFloat>& pitchAnalysis, 
      Array<ArrayFloat>& durationAnalysis, Array<ArrayFloat>& levelAnalysis) {

   unsigned char red;
   unsigned char green;
   unsigned char blue;
   int i, j;
   int r, s;
   int width = levelAnalysis[0].getSize();
   int height = levelAnalysis.getSize();
   int v1;
  
   int imageWidth  = width  * repeat * 2 + 1;
   int imageHeight = height * repeat * 2 + 1;

   cout << "P6\n" << imageWidth << " " << imageHeight << "\n255\n";

   for (i=0; i<height; i++) {
      v1 = height - i - 1;
      for (r=0; r<repeat; r++) {
         // print row: Full picture
         for (j=0; j<width; j++) {
            for (s=0; s<repeat; s++) {
               red   = 0xff & (int)(pitchAnalysis[v1][j] * 255 + 0.5);
               green = 0xff & (int)(durationAnalysis[v1][j] * 255 + 0.5);
               blue  = 0xff & (int)(levelAnalysis[v1][j] * 255 + 0.5);
               cout << red << green << blue;
            }
         }

         // print a white pixel to separate pictures
         red = green = blue = 0xff;
         cout << red << green << blue;

         // print next picture: pitch (red)
         for (j=0; j<width; j++) {
            for (s=0; s<repeat; s++) {
               red   = 0xff & (int)(pitchAnalysis[v1][j] * 255 + 0.5);
               green = 0;
               blue  = 0;
               cout << red << green << blue;
            }
         }
      }
   }

   // print a small white line to separate pictures
   for (i=0; i<imageWidth; i++) {
      red = green = blue = 0xff;
      cout << red << green << blue;
   }

   for (i=0; i<height; i++) {
      v1 = height - i - 1;
      for (r=0; r<repeat; r++) {
         // print row: duration (green)
         for (j=0; j<width; j++) {
            for (s=0; s<repeat; s++) {
               red   = 0;
               green = 0xff & (int)(durationAnalysis[v1][j] * 255 + 0.5);
               blue  = 0;
               cout << red << green << blue;
            }
         }

         // print a white pixel to separate pictures
         red = green = blue = 0xff;
         cout << red << green << blue;

         // print next picture: meter (blue)
         for (j=0; j<width; j++) {
            for (s=0; s<repeat; s++) {
               red   = 0;
               green = 0;
               blue  = 0xff & (int)(levelAnalysis[v1][j] * 255 + 0.5);
               cout << red << green << blue;
            }
         }
      }
   }
   cout << flush;

}



//////////////////////////////
//
// printAnalysisFlip -- 
//

void printAnalysisFlip(Array<ArrayFloat>& pitchAnalysis, 
      Array<ArrayFloat>& durationAnalysis, Array<ArrayFloat>& levelAnalysis) {

   unsigned char red;
   unsigned char green;
   unsigned char blue;
   int i, j;
   int r, s;
   int width = levelAnalysis[0].getSize();
   int height = levelAnalysis.getSize();


   cout << "P6\n" << width * repeat << " " << height * repeat << "\n255\n";

   for (i=0; i<height; i++) {
      for (r=0; r<repeat; r++) {
         for (j=0; j<width; j++) {
            for (s=0; s<repeat; s++) {
               if (redQ) red   = 0xff & (int)(pitchAnalysis[i][j] * 255 + 0.5);
               else      red   = 0x00;
               if (greenQ) green = 0xff & (int)(durationAnalysis[i][j] * 255 + 0.5);
               else        green = 0x00;
               if (blueQ) blue  = 0xff & (int)(levelAnalysis[i][j] * 255 + 0.5);
               else       blue  = 0x00;
               cout << red << green << blue;
            }
         }
      }
   }
   cout << flush;

}



//////////////////////////////
//
// generateLevelAnalysis --
//

void generateLevelAnalysis(HumdrumFile& infileA, HumdrumFile& infileB, 
      Array<ArrayFloat>& levelAnalysis) {
   Array<int> rhylev;
   Array<int> levelsA;
   Array<int> levelsB;
   int i, j;

   infileA.analyzeMetricLevel(rhylev);
   levelsA.setSize(rhylev.getSize());
   levelsA.setSize(0);
   for (i=0; i<infileA.getNumLines(); i++) {
      if (infileA[i].isData()) {
         if (strcmp(infileA[i][0], ".") != 0    &&  // ignore null tokens
             strchr(infileA[i][0], '_') == NULL &&  // ignore continued ties
             strchr(infileA[i][0], ']') == NULL) {  // ignore tie endings
            levelsA.append(rhylev[i]);
         }
      } 
   }

   infileB.analyzeMetricLevel(rhylev);
   levelsB.setSize(rhylev.getSize());
   levelsB.setSize(0);
   for (i=0; i<infileB.getNumLines(); i++) {
      if (infileB[i].isData()) {
         if (strcmp(infileB[i][0], ".") != 0    &&  // ignore null tokens
             strchr(infileB[i][0], '_') == NULL &&  // ignore continued ties
             strchr(infileB[i][0], ']') == NULL) {  // ignore tie endings
            levelsB.append(rhylev[i]);
         }
      } 
   }

   levelAnalysis.setSize(levelsA.getSize());
   for (i=0; i<levelsA.getSize(); i++) {
      levelAnalysis[i].setSize(levelsB.getSize());
   }

   for (i=0; i<levelsA.getSize(); i++) {
      for (j=0; j<levelsB.getSize(); j++) {
         if (levelsA[i] == levelsB[j]) {
            levelAnalysis[i][j] = 1.0;
         } else {
            levelAnalysis[i][j] = 0.0;
         }
      }
   }

}



//////////////////////////////
//
// generateDurationAnalysis --
//

void generateDurationAnalysis(HumdrumFile& infileA, HumdrumFile& infileB, 
      Array<ArrayFloat>& durationAnalysis) {
   Array<float> dursA;
   Array<float> dursB;
   float duration = 0.0;
   int i, j;

   dursA.setSize(infileA.getNumLines());
   dursA.setSize(0);
   for (i=0; i<infileA.getNumLines(); i++) {
      if (infileA[i].isData()) {
         if (strcmp(infileA[i][0], ".") != 0    &&   // ignore null tokens
             strchr(infileA[i][0], '_') == NULL &&   // ignore continued ties
             strchr(infileA[i][0], ']') == NULL) {   // ignore tie endings
            duration = (float)infileA.getTiedDuration(i, 0);
            dursA.append(duration);
         }
      } 
   }

   dursB.setSize(infileB.getNumLines());
   dursB.setSize(0);
   for (i=0; i<infileB.getNumLines(); i++) {
      if (infileB[i].isData()) {
         if (strcmp(infileB[i][0], ".") != 0    &&   // ignore null tokens
             strchr(infileB[i][0], '_') == NULL &&   // ignore continued ties
             strchr(infileB[i][0], ']') == NULL) {   // ignore tie endings
            duration = (float)infileB.getTiedDuration(i, 0);
            dursB.append(duration);
         }
      } 
   }

   durationAnalysis.setSize(dursA.getSize());
   for (i=0; i<dursA.getSize(); i++) {
      durationAnalysis[i].setSize(dursB.getSize());
   }

   for (i=0; i<dursA.getSize(); i++) {
      for (j=0; j<dursB.getSize(); j++) {
         if (fabs(dursA[i] - dursB[j]) < 0.01) {
            durationAnalysis[i][j] = 1.0;
         } else {
            durationAnalysis[i][j] = 0.0;
         }
      }
   }

}



//////////////////////////////
//
// generatePitchAnalysis --
//

void generatePitchAnalysis(HumdrumFile& infileA, HumdrumFile& infileB, 
      Array<ArrayFloat>& pitchAnalysis) {
   int i, j;
   Array<int> pitchA;
   Array<int> pitchB;
   getPitchData(pitchA, infileA, intervalQ, pclassQ);
   getPitchData(pitchB, infileB, intervalQ, pclassQ);

   pitchAnalysis.setSize(pitchA.getSize());
   for (i=0; i<pitchA.getSize(); i++) {
      pitchAnalysis[i].setSize(pitchB.getSize());
   }

   for (i=0; i<pitchA.getSize(); i++) {
      for (j=0; j<pitchB.getSize(); j++) {
         if (pitchA[i] == pitchB[j]) {
            pitchAnalysis[i][j] = 1.0;
         } else {
            pitchAnalysis[i][j] = 0.0;
         }
      }
   }

}



//////////////////////////////
//
// getPitchData -- return pitches or intervals as requested
//

void getPitchData(Array<int>& pitchA, HumdrumFile& infileA, int intervalQ,
      int pitchclassQ) {
   int pitch;
   int savepitch = 0;
   int oldsavepitch = 0;
   int init = 0;
   int i;
   
   pitchA.setSize(infileA.getNumLines());
   pitchA.setSize(0);
   for (i=0; i<infileA.getNumLines(); i++) {
      if (infileA[i].isData()) {
         if (strcmp(infileA[i][0], ".") != 0 ||   // ignore null tokens
             strcmp(infileA[i][0], "_") != 0 ||   // ignore continued ties
             strcmp(infileA[i][0], "]") != 0) {   // ignore tie endings
            pitch = Convert::kernToBase40(infileA[i][0]);

            if (intervalQ) {
               if (pitch < 0) {
                  pitch = -1000;
               } else if (init == 0 && pitch > 0) {
                  init = 1;
                  savepitch = pitch;
                  pitch = 1000;
               } else if (pitch > 0) {
                  oldsavepitch = savepitch;
                  savepitch = pitch;
                  pitch = savepitch - oldsavepitch;
               }
            } else if (pclassQ) {
               if (pitch > 0) {
                  pitch = pitch % 40;
               }
            }
            pitchA.append(pitch);
         }
      } 
   }
}



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

void checkOptions(Options& opts, int argc, char* argv[]) {
   opts.define("r|repeat=i:5",   "pixel magnification size");   
   opts.define("a|all=b",        "display image for each analysis");
   opts.define("w|white=b",      "display only highly similar locations");
   opts.define("f|flip=b",       "flip the vertical axis");
   opts.define("d|data=b",       "print analysis data of original file");
   opts.define("e|event=b",      "scale by events rather than duration");
   opts.define("i|interval=b",   "use intervals instead of absolute pitches");
   opts.define("p|pitch-class=b","use pitch class instead of absolute pitches");
   opts.define("R|no-pitch=b",   "scale by events rather than duration");
   opts.define("G|no-duration=b","scale by events rather than duration");
   opts.define("B|no-level=b",   "scale by events rather than duration");

   opts.define("debug=b",        "trace input parsing");   
   opts.define("author=b",       "author of the program");   
   opts.define("version=b",      "compilation information"); 
   opts.define("example=b",      "example usage"); 
   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, April 2002" << endl;
      exit(0);
   } else if (opts.getBoolean("version")) {
      cout << argv[0] << ", version: 6 April 2002" << 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);
   }

   repeat    =  opts.getInteger("repeat");
   allQ      =  opts.getBoolean("all");
   whiteQ    =  opts.getBoolean("white");
   flipQ     =  opts.getBoolean("flip");
   dataQ     =  opts.getBoolean("data");
   eventQ    =  opts.getBoolean("event");
   intervalQ =  opts.getBoolean("interval");
   pclassQ   =  opts.getBoolean("pitch-class");

   redQ   = !opts.getBoolean("R");
   greenQ = !opts.getBoolean("G");
   blueQ  = !opts.getBoolean("B");
}



//////////////////////////////
//
// example -- example usage of the maxent program
//

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



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

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


// md5sum: 90e44b7e300a2720fdbd93b42de8d735 triped.cpp [20110418]