//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Thu Nov 30 16:41:05 PST 2000
// Last Modified: Wed Dec  6 20:06:55 PST 2000
// Last Modified: Tue Dec 19 11:15:53 PST 2000 (arbitrary part #s (L values))
// Filename:      ...sig/examples/all/mustran2kern.cpp
// Web Address:   http://sig.sapp.org/examples/museinfo/humdrum/mustran2kern.cpp
// Syntax:        C++; museinfo
//
// Description:   Converts MUSTRAN musical data into Humdrum **kern data.
//

#include "humdrum.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>

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


void parseLine(void);
void parseHeader(void);
void parseData(void);
void parseItem(char* data);
void parseNoteData(char* data, char* notebuffer);
void clearaccidentals(void);
int  checkforpart(void);
void parseChord(char* data, char* chordbuffer);
void printKern(int pitch, int octave, int clef, char* buffer);
void printHfiles(Array<HumdrumFile*>& hfiles);
void combineLines(Array<HumdrumFile*>& hfiles);
void fixties(HumdrumFile& file);
void getTiedPitches(Array<int>& pitchcount, Array<int>& tiedPitches, 
      HumdrumRecord& record);
void setTies(Array<int>& pitchcount, Array<int>& tiedPitches, 
      HumdrumRecord& record);

#define ACCIDENTAL_SIZE 7
int accidental[ACCIDENTAL_SIZE] = {0};
int tupletQ = 0;
int tuplettype = 0;
int tupletmatch = 0;
int part = 0;
int clef = 0;
int chordQ = 0;
int suppressQ = 0;

char tbuffer[10000] = {0};
char notebuffer[10000] = {0};
char linebuffer[100000] = {0};
int length = 0;
Array<int> partindex;

// interface variables:
Options options;
int combineQ = 1;                // used with the -s option

// function declarations:
void      checkOptions(Options& opts, int argc, char* argv[]);


Array<HumdrumFile*> hfiles;
HumdrumFile header;

int main(int argc, char** argv) {
   // process the command-line options
   checkOptions(options, argc, argv);
   
   if (options.getArgCount() != 1) {
      cout << "Usage: " << options.getCommand() << " inputfile " << endl;
      exit(1);
   }
   hfiles.setSize(1000);
   hfiles.setSize(0);

   partindex.setSize(1000);
   partindex.setSize(0);
   partindex.allowGrowth(1);
  
   #ifndef OLDCPP
      fstream infile(options.getArg(1), ios::in);
   #else
      fstream infile(options.getArg(1), ios::in | ios::nocreate);
   #endif

   if (!infile.is_open()) {
      cout << "Error: cannot open file for reading: " 
           << options.getArg(1) << endl;
      exit(1);
   }

   char *buffer = linebuffer;
   while (infile.getline(buffer, 100000, '\n')) {
      if (buffer[0] != '\0') {
         parseLine();
      }
      if (infile.eof()) {
         break;
      }
      // cout << "Line " << line++ << ":\t" << buffer << endl;
   }

   int i;
   for (i=0; i<hfiles.getSize(); i++) {
      fixties(*(hfiles[i]));
   }

   if (hfiles.getSize() == 1 && 
         strcmp((*hfiles[0])[hfiles[0]->getNumLines() - 1][0], "*-") != 0) {
      hfiles[0]->appendLine("*-");
   }
   
   if (hfiles.getSize() > 1 && combineQ) {
      combineLines(hfiles);
   } else {
      printHfiles(hfiles);
   }

   return 0;
}


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


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

void checkOptions(Options& opts, int argc, char* argv[]) {
   opts.define("A|no-assemble=b");   // don't assemble analyses
   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, December 2000" << endl;
      exit(0);
   } else if (opts.getBoolean("version")) {
      cout << argv[0] << ", version: 2 December 2000" << 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);
   }

   if (opts.getBoolean("no-assemble")) {
      combineQ = 0;
   } else {
      combineQ = 1;
   }
}
  


//////////////////////////////
//
// fixties --
//

void fixties(HumdrumFile& file) {
   Array<int> pitchcount(1000);
   pitchcount.zero();
   
   int i;
   int j = 0;
   Array<int> tielines;
   tielines.setSize(file.getNumLines());
   tielines.zero();
   tielines.allowGrowth(0);

   // find the lines with ties, and how many there are on each line
   for (i=file.getNumLines()-1; i>=0; i--) {
      if (file[i].getType() != E_humrec_data) {
         continue;
      }

      if (strstr(file[i][0], "]") != NULL) {
         length = strlen(file[i][0]);
         for (j=0; j<length; j++) {
            if (file[i][0][j] == ']') {
               tielines[i]++;
               continue;
            }
         }
      }
   }

   // now add opening ties to previous pitches
   Array<int> tiedPitches;
   int tieSearch = 0;
   // int tieLine = -1;
   for (i=file.getNumLines()-1; i>=0; i--) {
      if (file[i].getType() != E_humrec_data) {
         continue;
      }

      if (tieSearch) {
         // looking for ties, and this line does not have any new ties
         // there will be no continued ties.
         // all previous ties should be accounted for on this line.
         setTies(pitchcount, tiedPitches, file[i]);
         tieSearch = 0;
      }

      if (tieSearch == 0 && tielines[i] != 0) {
         // not previously looking for ties, but here is a line with them
         tieSearch = 1;
         // tieLine = i;
         getTiedPitches(pitchcount, tiedPitches, file[i]);
         continue;
      }

      if (tieSearch == 0 && tielines[i] == 0) {
         // prevent bugs in the data from propagating
         pitchcount.zero();
         tiedPitches.zero();
      }

   }
}



//////////////////////////////
//
// setTies --
//

void setTies(Array<int>& pitchcount, Array<int>& tiedPitches, 
      HumdrumRecord& record) {
   static char buffer[10000] = {0};
   char tbuffer[128] = {0};
   buffer[0] = '\0';
   int tokenCount = record.getTokenCount(0);
   int pitch;
   int match = 0;
   int m;
   int j;
   for (m=0; m<tokenCount; m++) {
      record.getToken(tbuffer, 0, m);
      pitch = Convert::kernToMidiNoteNumber(tbuffer);
      match = 0;
      for (j=0; j<tiedPitches.getSize(); j++) {
         if (pitch == tiedPitches[j]) {
            match = 1;
            pitchcount[pitch]--;
            if (pitchcount[pitch] == 0) {
               tiedPitches[j] = 0;
            }
         }
      }
      if (match == 1) {
         char* tptr;
         tptr = strchr(tbuffer, ']');
         if (tptr != NULL) {
            tptr[0] = '_';
            strcat(buffer, tbuffer);
         } else {
            strcat(buffer, "[");
            strcat(buffer, tbuffer);
         }
         if (m < tokenCount - 1) {
            strcat(buffer, " ");
         }
      } else {
         strcat(buffer, tbuffer);
         if (m < tokenCount - 1) {
            strcat(buffer, " ");
         }
      }
   }
   record.changeField(0, buffer);
}



//////////////////////////////
//
// getTiedPitches -- 
//

void getTiedPitches(Array<int>& pitchcount, Array<int>& tiedPitches, 
      HumdrumRecord& record) {
   tiedPitches.setSize(0);
   tiedPitches.allowGrowth(1);
   char buffer[128] = {0};
   int j;
   int pitch;
   int tokenCount = record.getTokenCount(0);
   for (j=0; j<tokenCount; j++) {
      record.getToken(buffer, 0, j);
      if ((strchr(buffer, ']') != 0) || (strchr(buffer, '_') != 0)) {
         pitch = Convert::kernToMidiNoteNumber(buffer);
         if (pitch < 0) {
            cout << "Error: cannot have tied rests" << endl;
            exit(1);
         }
         tiedPitches.append(pitch);
         pitchcount[pitch]++;
      }
   }
}



//////////////////////////////
//
// combineLines --
//

void combineLines(Array& hfiles) {
   HumdrumFile output;
   int i;
   for (i=0; i<hfiles.getSize(); i++) {
      hfiles[i]->analyzeSpines();
   }
   HumdrumFile::assemble(output, hfiles.getSize(), hfiles.getBase());
   cout << header;
   cout << output;
}



//////////////////////////////
//
// printHfiles --
//

void printHfiles(Array& hfiles) {
   cout << header;
   for (int i=0; i<hfiles.getSize(); i++) {
      cout << (*(hfiles[i]));
      if (i < hfiles.getSize() - 1) {
         cout << "\n";
      }
   }
}



//////////////////////////////
//
// parseline -- make commentary on the input data
//


void parseLine(void) {
   int oldpart;
   char* buffer = linebuffer;
   length = strlen(buffer);
   if (length < 13) {
      // cout << "   Not a valid data line" << endl;
      return;
   }
   int measure;
   int flag = sscanf(&buffer[11], "%d", &measure);
   if (flag != 1) {
      cout << "Error no measure number found" << endl;
   }
   if (measure == 0) {
//      cout << "   This is a header line giving title and composer" << endl;
      parseHeader();
   } else {

      int partQ = checkforpart();

      if (partQ) {
         HumdrumFile* hfile = new HumdrumFile;
         hfiles.append(hfile);
         partindex.append(part);
         oldpart = part;
         part = partindex.getSize();

         if (part > 1) {
//            cout << "==\n*-\n\n";
            hfiles[part-2]->appendLine("==");
            hfiles[part-2]->appendLine("*-");
         }
//         cout << "**kern\n!part" << oldpart << endl;
         hfiles[part-1]->appendLine("**kern");
         sprintf(tbuffer, "!part%d", oldpart);
         hfiles[part-1]->appendLine(tbuffer);
      }
      // cout << "   measure = " << measure << "\tfor part " << part << endl;
      if (measure > 1) {
//         cout << "=" << measure << endl;
         sprintf(tbuffer, "=%d", measure);
         hfiles[part-1]->appendLine(tbuffer);
      }
      parseData();
   }
}


//////////////////////////////
//
// checkforpart --
//

int checkforpart(void) {
   int i;
   for (i=0; i<length; i++) {
      if (linebuffer[i] == 'L') {
         i++;
         int flag = sscanf(&linebuffer[i], "%d", &part);
         if (flag != 1) {
            cout << "Error no part number indicated" << endl;
            exit(1);
         }
         return 1;
      }
   }

   return 0;
}



//////////////////////////////
//
// parseHeader -- make commentary on the header information
//

void parseHeader(void) {
   char hbuffer[1000] = {0};
   char letter[2] = {0};
   char* line = linebuffer;
   char* title = strstr(line, "\'*T");
   int i;
   if (title != NULL) {
      title += 3;
      // cout << "   Title\t=\t";
      strcpy(hbuffer, "!!!OTL: ");
      i = 0;
      while ((title[i] != '\0') && (title[i] != '\'')) {
         // cout << title[i++];
         letter[0] = title[i++];
         strcat(hbuffer, letter);
      }
      // cout << endl;
      header.appendLine(hbuffer);
      if (title[i] != '\'') {
         cout << "   There is an error in the title, no ending: \'" << endl;
      }
   } else {
      cout << "   No title information given" << endl;
   }

   char* name = strstr(line, "\'*C");
   if (name != NULL) {
      name += 3;
//    cout << "   Composer\t=\t";
      strcpy(hbuffer, "!!!COM: ");
      i = 0;
      while ((name[i] != '\0') && (name[i] != '\'')) {
//       cout << name[i++];
         letter[0] = name[i++];
         strcat(hbuffer, letter);
      }
//      cout << endl;
      header.appendLine(hbuffer);
      if (name[i] != '\'') {
         cout << "   There is an error in the name, no ending: \'" << endl;
      }
   } else {
      cout << "   No composer information given" << endl;
   }
}



//////////////////////////////
//
// parseData -- make commentary on the input data line
//

void parseData(void) {
   char* line = linebuffer;
   char* data = strchr(line, ',');
   data++;
   char* buffer = linebuffer;
   data = strtok(buffer, ",");
   data = strtok(NULL, ",");
   int count = 1;
   // int tlen;
   while (data != NULL) {
      // tlen = strlen(data);
//      cout << "   item ";
//      if (count < 10) {
//         cout << ' ';
//      }
//      if (count < 100) {
//         cout << ' ';
//      }
//      cout << count << ": _" << data << "_";
      count++;
//      if (tlen < 4) {
//         cout << "\t";
//      }
//      cout << "\t==> ";
      parseItem(data);
      if (!suppressQ) {
//         cout << endl;
      }
      suppressQ = 0;
      
      data = strtok(NULL, ",");
   }
}


//////////////////////////////
//
// parseItem --
//

void parseItem(char* data) {
   static char chordbuffer[10000] = {0};
   if (toupper(data[0]) == 'L') {
//      sscanf(data, "L%d", &part);
//   cout << "part number = " << partindex[part-1] << endl;
      suppressQ = 1;
      return;
   }

   if (strchr(data, '(') != 0) {
//      cout << "start of tuplet";  
      tupletQ = 1;
      int flag = sscanf(data, "%d", &tuplettype);
      if (flag != 1) {
         cout << "Error no starting tuplet indicator" << endl;
         exit(1);
      }

      int i = data - linebuffer;;
      while (linebuffer[i] != ')' && i < length) {
         i++;
      }
      if (linebuffer[i] != ')') {
         cout << "\nError: no ending to tuplet " << endl;
         exit(1);
      }
      i--;
      if (!isdigit(linebuffer[i])) {
         cout << "\nError: no ending tuplet value" << endl;
         exit(1);
      }
      while (isdigit(linebuffer[i])) {
         i--;
      }
      i++;
      sscanf(&linebuffer[i], "%d", &tupletmatch);
//      cout << ": " <<  tuplettype << " in the time of " << tupletmatch;

      suppressQ = 1;
      return;
   }
   if (strchr(data, ')') != 0) {
//      cout << "end of tuplet";  
      tupletQ = 0;
      suppressQ = 1;
      return;
   }

   if (strcmp(data, "GS") == 0) {
//      cout << "treble clef";
//      cout << "*clefG2";
      hfiles[part-1]->appendLine("*clefG2");
      clef = 0;
      return;
   }

   if (strcmp(data, "FS") == 0) {
//      cout << "bass clef";
//      cout << "*clefF4";
      hfiles[part-1]->appendLine("*clefF4");
      clef = 1;
      return;
   }

   if (strchr(data, '=') != NULL) {
      int top;
      int bottom;
      sscanf(data, "%d=%d", &top, &bottom);
//      cout << "Time signature: " << top << '/' << bottom;
//      cout << "*M" << top << "/" << bottom;
      sprintf(tbuffer, "*M%d/%d", top, bottom);
      hfiles[part-1]->appendLine(tbuffer);
      return;
   }

   if (strcmp(data, "/") == 0 || strncmp(data, "/ ", 2) == 0) {
//      cout << "End of measure marker";
      clearaccidentals();
      suppressQ = 1;
      return;
   }

   if (strncmp(data, "//", 2) == 0) {
//      cout << "End of piece marker";
//      cout << "==\n*-";
      hfiles[part-1]->appendLine("==");
      hfiles[part-1]->appendLine("*-");
      clearaccidentals();
      suppressQ = 1;
      return;
   }

   if (strncmp(data, "END", 3) == 0) {
//      cout << "End of piece assertion";
      clearaccidentals();
      suppressQ = 1;
      return;
   }

   if (strchr(data, 'Y') != 0) {
      chordQ = 1;
      parseChord(data, chordbuffer);
      hfiles[part-1]->appendLine(chordbuffer);
      chordQ = 0;
      return;
   }

   parseNoteData(data, notebuffer);
   hfiles[part-1]->appendLine(notebuffer);
}



//////////////////////////////
//
// parseChord --
//

void parseChord(char* data, char* chordbuffer) {
   char* note;
   chordbuffer[0] = '\0';

   int tlen = strlen(data);
   int i = 0;
   int count = 1;
   int rcount = 0;
   for(i=0; iif (data[i] == 'R') {
         rcount++;
      }
      if (data[i] == 'Y') {
         data[i] = '\0';
         count++;
      }
   }

   if(count-rcount == 1) {
//      cout << "CHORD with " << count-rcount << " note";
   } else {
//      cout << "CHORD with " << count-rcount << " notes";
   }
   if(rcount > 0) {
      if (rcount == 1) {
//         cout << " (and " << rcount << " rest)";
      } else {
//         cout << " (and " << rcount << " rests)";
      }
   }
//   cout << endl;
   note = data;
   int xcount = 0;
   while(xcount < count) {
      i = 0;
      xcount++;
//      cout << "\t     _";
//      cout << note;
//      cout << "_\t    chord ";
      parseNoteData(note, notebuffer);
      strcat(chordbuffer, notebuffer);
      if (count != xcount) {
//         cout << endl;
//        cout << " ";
        strcat(chordbuffer, " ");
      }
      while(note[i] != '\0') {
         i++;
      }
      i++;
      note += i;
   }
}



//////////////////////////////
//
// clearaccidentals -- 
//

void clearaccidentals(void) {
   for(int i=0; i//////////////////////////////
//
// parseNoteData -- 
//

void parseNoteData(char* data, char* notebuffer) {
   int rhythm;
   if (!isdigit(data[0])) {
      cout << "ERROR: no rhythm";
      return;
   } else {
      sscanf(data, "%d", &rhythm);
   }

   int forcedQ = 0;
   int acc = 0;
   if (strchr(data, '*') != NULL) {
      acc = +1;
   }
   if (strchr(data, '$') != NULL) {
      acc = -1;
   }
   if (strchr(data, 'N') != NULL) {
      forcedQ = 1;
      acc = +10;
   }
   if (strstr(data, "$$") != NULL) {
      acc = -1;
   }
   if (strstr(data, "**") != NULL) {
      acc = -1;
   }


   const char* pitch = "X";
   if (strchr(data, 'A') != NULL) {
      pitch = strchr(data, 'A');
   } else if (strchr(data, 'B') != NULL) {
      pitch = strchr(data, 'B');
   } else if (strchr(data, 'C') != NULL) {
      pitch = strchr(data, 'C');
   } else if (strchr(data, 'D') != NULL) {
      pitch = strchr(data, 'D');
   } else if (strchr(data, 'E') != NULL) {
      pitch = strchr(data, 'E');
   } else if (strchr(data, 'F') != NULL) {
      pitch = strchr(data, 'F');
   } else if (strchr(data, 'G') != NULL) {
      pitch = strchr(data, 'G');
   } else if (strchr(data, 'R') != NULL) {
      pitch = strchr(data, 'R');
   } else {
      cout << "Error: no pitch given";
   }

   if(pitch[0] != 'R') {
      if (acc == 0) {
         acc = accidental[pitch[0] - 'A'];
      }
      if (acc == 10) {
         accidental[pitch[0] - 'A'] = 0;
         acc = 0;
      }
      accidental[pitch[0] - 'A'] = acc;
   }
  
   int dotQ = 0;
   if (strchr(data, '.')) {
      dotQ = 1;
   }

   int octave = 0;
   if (strchr(data, '+') != 0) {
      octave = +1;
   }
   if (strchr(data, '-') != 0) {
      octave = -1;
   }
   if (strstr(data, "++") != 0) {
      octave = +2;
   }
   if (strstr(data, "--") != 0) {
      octave = -2;
   }
   if (strstr(data, "+++") != 0) {
      octave = +3;
   }
   if (strstr(data, "---") != 0) {
      octave = -3;
   }
   if (strstr(data, "++++") != 0) {
      octave = +4;
   }
   if (strstr(data, "----") != 0) {
      octave = -4;
   }

   int tieQ = 0;
   if (strchr(data, 'J') != 0) {
      tieQ = 1;
   }


   //
   // read to print analysis
   //

   //////////////////////////////
  
   notebuffer[0] = '\0';

//   cout << " rhythm=" << rhythm;
   if(tupletQ) {
//      cout << rhythm * tuplettype / tupletmatch;
      sprintf(tbuffer, "%d", rhythm * tuplettype / tupletmatch);
      strcat(notebuffer, tbuffer);
   } else {
//      cout << rhythm;
      sprintf(tbuffer, "%d", rhythm);
      strcat(notebuffer, tbuffer);
   }
   if(dotQ) {
//      cout << ".";
      strcat(notebuffer, ".");
   }
//   if (tupletQ) {
//      cout << "T" << tuplettype << ":" << tupletmatch;
//   }


   if(pitch[0] == 'R') {
//      cout << "rest";
//      cout << "r";
      strcat(notebuffer, "r");
   } else {
      printKern(pitch[0], octave, clef, notebuffer);
//      cout << "note=" << pitch[0];
      if (acc == -1) {
//         cout << "-flat";
//         cout << "-";
         strcat(notebuffer, "-");
      }
      if (acc == -2) {
//         cout << " double-flat";
//         cout << "--";
         strcat(notebuffer, "--");
      }
      if (acc == +1) {
//         cout << "-sharp";
//         cout << "#";
         strcat(notebuffer, "#");
      }
      if (acc == +2) {
//         cout << " double-sharp";
//         cout << "##";
         strcat(notebuffer, "##");
      }
      if (acc == 0 && forcedQ) {
//         cout << "-natural";
//         cout << "n";
         strcat(notebuffer, "n");
      }
//      if (octave != 0) {
//         cout << " octave=" << octave;
//      }
   }

   if(clef) {
//      cout << " clef=bass";
   }


   if(tieQ == 1) {
//      cout << " tied-previous";
//      cout << "]";
      strcat(notebuffer, "]");
   }

}


//////////////////////////////
//
// printKern -- 
//

void printKern(int pitch, int octave, int clef, char* buff) {
   SSTREAM buffstream;
   pitch = toupper(pitch);
   if(clef == 0) {

      // treble clef
      if (octave == 0) {
            buffstream << (char)tolower(pitch); 
      } else if (octave == -1) {
            buffstream  << (char)toupper(pitch);
      } else if (octave == +1) {
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
      } else if (octave == -2) {
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
      } else if (octave == +2) {
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
      } else if (octave == -3) {
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
      } else if (octave == +3) {
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
      } else if (octave == -4) {
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
      } else if (octave == +4) {
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
      } else if (octave == -5) {
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
      } else {
            buffstream  << (char)tolower(pitch);
      }



   } else {
      // bass clef
      int newp = pitch - 'A';
      newp += 2;
      newp = newp % 7;
      octave--;
      if (newp == 2 || newp == 3) {
         octave++;
      }
      pitch = newp + 'A';
      // bass clef
      if (octave == 0) {
            buffstream << (char)toupper(pitch); 
      } else if (octave == -1) {
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
      } else if (octave == +1) {
            buffstream << (char)tolower(pitch); 
      } else if (octave == -2) {
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
      } else if (octave == +2) {
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
      } else if (octave == -3) {
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
      } else if (octave == +3) {
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
      } else if (octave == -4) {
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
            buffstream  << (char)toupper(pitch);
      } else if (octave == +4) {
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
            buffstream << (char)tolower(pitch); 
      } else if (octave == +5) {
            buffstream  << (char)tolower(pitch);
            buffstream  << (char)tolower(pitch);
            buffstream  << (char)tolower(pitch);
            buffstream  << (char)tolower(pitch);
      } else {
            buffstream  << (char)toupper(pitch);
      }

   }

   buffstream << ends;
   strcat(buff, buffstream.CSTRING);

}


// md5sum: 817b14d888e18753d3e30a24e2246370 mustran2kern.cpp [20050403]