// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Tue Dec 18 11:01:22 PST 2001 // Last Modified: Wed Aug 20 22:37:23 PDT 2003 (add field option) // Last Modified: Thu Aug 21 19:20:02 PDT 2003 (added **kotov conversion) // Last Modified: Tue Aug 26 22:54:00 PDT 2003 (added spine manipulators) // Filename: ...sig/examples/all/koto2kern.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/koto2kern.cpp // Syntax: C++; museinfo // // Description: Convert **koto representation to **kern representation // // Note: Not finished // #include "humdrum.h" #include <string.h> #include <stdio.h> #include <ctype.h> #include <math.h> // function declarations void checkOptions(Options& opts, int argc, char* argv[]); void example(void); void usage(const char* command); void convertKoto(HumdrumFile& infile); void processKotoData(HumdrumRecord& line); void processKotoDatum(const char* string, HumdrumRecord& line); void processInterpretation(HumdrumRecord& line); void storeTuning(const char* tunestring); void printRhythm(const char* string, double scaling = 1.0); void printPitch(const char* string, HumdrumRecord& line); void printKernNotes(const char* string, HumdrumRecord& line); // command line options: Options options; // database for command-line arguments int debugQ = 0; // for debugging options --debug int skeletonQ = 0; // convert only basic musical ornaments int appendQ = 0; // for use with the -a option int field = 0; // for use with the -f option Array<int> tuning; // for koto tuning /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile; // input Humdrum Format file tuning.setSize(13); tuning.allowGrowth(0); // process the command-line options checkOptions(options, argc, argv); // figure out the number of input files to process int numinputs = options.getArgCount(); for (int 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 { infile.read(options.getArg(i+1)); } convertKoto(infile); } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // convertKoto -- // void convertKoto(HumdrumFile& infile) { int i; int spine; int scount; for (i=0; i<infile.getNumLines(); i++) { switch (infile[i].getType()) { case E_humrec_none: case E_humrec_empty: case E_humrec_global_comment: case E_humrec_bibliography: cout << infile[i] << "\n"; break; case E_humrec_data_comment: if (appendQ) { cout << infile[i] << "\t!\n"; } else { cout << infile[i][0] << "\n"; } break; case E_humrec_data_kern_measure: if (appendQ) { cout << infile[i] << "\t"; } scount = 0; for (spine=0; spine<infile[i].getFieldCount(); spine++) { if (infile[i].getPrimaryTrack(spine)-1 != field) { continue; } scount++; if (scount > 1) { cout << "\t"; } cout << infile[i][spine]; } cout << "\n"; break; case E_humrec_interpretation: processInterpretation(infile[i]); break; case E_humrec_data: processKotoData(infile[i]); break; default: cout << "!!" << infile[i] << "\n"; break; } } } ////////////////////////////// // // processInterpretation -- // void processInterpretation(HumdrumRecord& line) { if (appendQ) { cout << line << "\t"; } if (strncmp(line[field], "**", 2) == 0) { cout << "**kern\n"; return; } int spine; int scount = 0; for (spine=0; spine<line.getFieldCount(); spine++) { if (line.getPrimaryTrack(spine)-1 != field) { continue; } scount++; if (scount > 1) { cout << "\t"; } if (strcmp(line[spine], "*-") == 0) { cout << "*-"; continue; } if (strncmp(line[spine], "*M", 2) == 0) { int top, bottom; int count = sscanf(line[0], "*M%d/%d", &top, &bottom); if (count == 2) { cout << line[spine] << ""; } else { cout << "*"; } continue; } if (strncmp(line[spine], "*tune[", 6) == 0) { storeTuning(line[spine]); if (appendQ) { cout << "*"; } continue; } if (strcmp(line[spine], "*free") == 0) { cout << "*free"; continue; } if (strcmp(line[spine], "*strict") == 0) { cout << "*strict"; continue; } cout << line[spine]; } cout << "\n"; } /////////////////////////////// // // storeTuning -- // void storeTuning(const char* tunestring) { int length = strlen(tunestring); int i; int stringnum = 0; Array<int> info(13); for (i=0; i<13; i++) { info[i] = -1; } for (i=6; i<length-1; i++) { if (tunestring[i] == ':') { stringnum++; } else { if (info[stringnum] < 0) { info[stringnum] = Convert::kernToBase40(&tunestring[i]); } } } for (i=0; i<13; i++) { if (info[i] > 0) { tuning[i] = info[i]; } } } ////////////////////////////// // // processKotoData -- // void processKotoData(HumdrumRecord& line) { static char buffer[1024] = {0}; if (appendQ) { cout << line << "\t"; } int spine; int i; int tokencount; int scount = 0; for (spine=0; spine<line.getFieldCount(); spine++) { if (line.getPrimaryTrack(spine) - 1 != field) { continue; } scount++; if (scount > 1) { cout << "\t"; } if (strncmp(line[spine], "-", 1) == 0) { cout << "."; continue; } tokencount = line.getTokenCount(spine); for (i=0; i<tokencount; i++) { line.getToken(buffer, spine, i); processKotoDatum(buffer, line); if (i < tokencount - 1) { cout << " "; } } } cout << "\n"; } ////////////////////////////// // // processKotoDatum -- // void processKotoDatum(const char* string, HumdrumRecord& line) { if (strchr(string, '{') != NULL) { cout << '{'; } if (strchr(string, '(') != NULL) { cout << '('; } if (strchr(string, '[') != NULL) { cout << '['; } printKernNotes(string, line); if (strchr(string, 'q') != NULL) { cout << 'q'; } if (strchr(string, ':') != NULL) { cout << ':'; } if (strchr(string, ';') != NULL) { cout << ';'; } if (strchr(string, ']') != NULL) { cout << ']'; } if (strchr(string, ')') != NULL) { cout << ')'; } if (strchr(string, '}') != NULL) { cout << '}'; } } ////////////////////////////// // // printKernNotes -- // void printKernNotes(const char* string, HumdrumRecord& line) { printPitch(string, line); } ////////////////////////////// // // printRhythm -- // void printRhythm(const char* string, double scaling) { int pluscount = 0; int dotcount = 0; int pipecount = 0; int i; int length = strlen(string); // print a rhythm only if there is a string number // also allowed: W, Z, and z int stringQ = 0; for (i=0; i<length; i++) { if (isdigit(string[i])) { stringQ = 1; break; } else if (string[i] == 'A' || string[i] == 'B' || string[i] == 'C' || string[i] == 'D' || string[i] == 'E' || string[i] == 'W' || string[i] == 'Z' || string[i] == 'z') { stringQ = 1; break; } } if (stringQ == 0) { return; } for (i=0; i<length; i++) { if (string[i] == '+') { pluscount++; } if (string[i] == '|') { pipecount++; } if (string[i] == '.') { dotcount++; } } if (pluscount == 0 && pipecount == 0) { cout << (int)(4 / scaling); } else if (pluscount > 0) { if (pluscount == 2) { cout << "2."; } else { cout << (int)(4 / scaling) / (pluscount+1); } } else if (pipecount > 0) { cout << (int)(4 / scaling) * pow(2.0, pipecount); } else { cout << "RHYTHM_ERROR"; } for (i=0; i<dotcount; i++) { cout << "."; } } ////////////////////////////// // // printPitch -- print the pitch related to this line. // Added sha arpeggio Wed Aug 7 15:03:33 PDT 2002 // Added wa glissando Tue Aug 26 18:54:23 PDT 2003 // void printPitch(const char* string, HumdrumRecord& line) { double scaling = 1; // rhythmic scaling for oshi tome hanashi, etc. int i, j; int pvalue = 0; int length = strlen(string); int index = 0; char buffer[32] = {0}; int sharpcount = 0; int sharpcount2 = 0; for (i=0; i<length; i++) { if (string[i] == '#') { sharpcount++; } } // check for higher octave in vocal part int octave = 0; if (strchr(string, '^') != NULL) { octave = 1; } if (!skeletonQ) { if (strchr(string, 'o')) { // oshi tome is present scaling = 0.5; } } printRhythm(string, scaling); for (i=0; i<length; i++) { if (isxdigit(string[i])) { if (string[i] == 'a' || string[i] == 'b' || string[i] == 'c' || string[i] == 'd' || string[i] == 'e' || string[i] == 'f' || string[i] == 'F') { continue; } else { if (isdigit(string[i])) { index = string[i] - '0' - 1; } else { index = string[i] - 'A' - 1 + 10; } if (index < 0) { cout << "r"; } else { pvalue = tuning[index]; Convert::base40ToKern(buffer, pvalue + octave * 40); length = strlen(buffer); for (j=0; j<length; j++) { if (buffer[j] == '#') { sharpcount2++; } } if (sharpcount == 1 && sharpcount2 == 1) { pvalue = pvalue - sharpcount2 + 6; } else if (sharpcount == 2 && sharpcount2 == 1) { pvalue = pvalue - sharpcount2 + 7; } else if (sharpcount == 3 && sharpcount2 == 0) { pvalue = pvalue + 11; } else if (sharpcount == 1 && sharpcount2 == 0) { pvalue = pvalue + 1; } else if (sharpcount == 2 && sharpcount2 == 0) { pvalue = pvalue + 6; } else if (sharpcount + sharpcount2 > 3) { cout << "PERROR"; } // cout << ">" << sharpcount << "," << sharpcount2 << "<"; cout << Convert::base40ToKern(buffer, pvalue + octave * 40); if (!skeletonQ) { if (strchr(string, 's') != NULL) { // print sha ornament cout << ": "; if (index + 1 < tuning.getSize()) { pvalue = tuning[index + 1]; } printRhythm(string, scaling); cout << Convert::base40ToKern(buffer, pvalue + octave * 40); cout << ":"; } else if (strchr(string, 'o') != NULL) { // oshi tome: increase the current tone by a whole step cout << "H\n"; // beginning of glissando if (appendQ) { for (i=0; i<line.getFieldCount(); i++) { cout << ".\t"; } } printRhythm(string, scaling); cout << Convert::base40ToKern(buffer, pvalue+6 + octave * 40); cout << "h"; // end of glissando } } // end !skeletonQ } return; } } } // check for ura-ren (wa) arpeggio on strings 1,2,3,4: if (strchr(string, 'W') != 0) { cout << Convert::base40ToKern(buffer, tuning[0]); cout << ": "; printRhythm(string, scaling); cout << Convert::base40ToKern(buffer, tuning[1]); cout << ": "; printRhythm(string, scaling); cout << Convert::base40ToKern(buffer, tuning[2]); cout << ": "; printRhythm(string, scaling); cout << Convert::base40ToKern(buffer, tuning[3]); cout << ":"; return; } // nothing, so the previous note must be continuing if (strcmp(string, ".") == 0) { cout << "."; } else { cout << "x"; // don't know or missing a string number } } ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("a|append=b", "append conversion to input data"); opts.define("s|skeleton|b|basic=b", "convert only basic ornaments"); opts.define("f|field=i:1", "field to convert"); 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, Dec 2001" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: Dec 2001" << 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); } appendQ = opts.getBoolean("append"); skeletonQ = opts.getBoolean("skeleton"); debugQ = opts.getBoolean("debug"); field = opts.getInteger("field") - 1; if (field < 0) { field = 0; } } ////////////////////////////// // // example -- example usage of the scrub program // void example(void) { cout << " \n" << endl; } ////////////////////////////// // // usage -- gives the usage statement for the scrub program // void usage(const char* command) { cout << " \n" << endl; } // md5sum: 129d8e3b3ef4ff13e5fd4c904b890d9a koto2kern.cpp [20050403]