// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Wed Dec 13 13:35:37 PST 2000 // Last Modified: Wed Dec 13 13:35:41 PST 2000 // Filename: ...sig/examples/all/kern2melisma.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/kern2melisma.cpp // Syntax: C++; museinfo // Reference: http://bobo.link.cs.cmu.edu/music-analysis // // Description: Generates a list of pitches in a Humdrum file // according to the Melisma Music Analyzer file format // for notes. // #include "humdrum.h" #include <string.h> #include <ctype.h> #include <stdio.h> #ifndef OLDCPP #include <iostream> #else #include <iostream.h> #endif // function declarations: void checkOptions(Options& opts, int argc, char** argv); void example(void); void preparePitch(char* buffer2, const char* buffer1); void printOutput(HumdrumFile& hfile); void usage(const char* command); // User interface variables: Options options; int barlinesQ = 1; // used with the -B option int midinoteQ = 0; // used with the -m option int classQ = 0; // used with the -c option double tdefault = 60.0; // used with the -t option ////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { // process the command-line options checkOptions(options, argc, argv); HumdrumFile hfile(options.getArg(1)); hfile.analyzeRhythm("4"); printOutput(hfile); return 0; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // checkOptions -- // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("B|nobarlines=b", "don't display barlines"); opts.define("m|midi|MIDI=b", "display pitches as MIDI note numbers"); opts.define("c|class=b", "display pitches in pitch class notation"); opts.define("t|tempo|default-tempo=d:60.0", "tempo if none specified"); 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, May 1998" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 3 July 1998" << 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("nobarlines")) { barlinesQ = 0; } else { barlinesQ = 1; } if (opts.getBoolean("class")) { classQ = 1; } else { classQ = 0; } tdefault = opts.getDouble("default-tempo"); if (tdefault == 0.0) { cout << "Error default tempo cannot be zero." << endl; exit(1); } if (tdefault < 0.0) { cerr << "Warning: converting tempo to be positive" << endl; tdefault = -tdefault; } } ////////////////////////////// // // example -- // void example(void) { } ////////////////////////////// // // printOutput -- one small bug: the duration of the notes // are calculated under constant tempo. A tempo change during // a tied note will not give the correct ending point of the // tied note. This bug is minor and the work to fix it is major. // void printOutput(HumdrumFile& hfile) { Array<double> tempo; hfile.analyzeTempoMarkings(tempo, tdefault); double currentmillisecond = 0.0; double lastduration = 0.0; double endmillisecond; int i, j, k; char buffer1[1024] = {0}; char buffer2[1024] = {0}; double duration; for (i=0; i<hfile.getNumLines(); i++) { currentmillisecond = currentmillisecond + lastduration * 60000.0 / tempo[i]; lastduration = hfile[i].getDuration(); if (hfile[i].getType() == E_humrec_global_comment) { cout << "Comment\t" << &(hfile[i].getLine()[3]) << endl; } if (hfile[i].getType() == E_humrec_bibliography) { cout << "Reference " << &(hfile[i].getLine()[3]) << endl; } if (hfile[i].getType() == E_humrec_interpretation) { for (j=0; j<hfile[i].getFieldCount(); j++) { if (hfile[i].getExInterpNum(j) != E_KERN_EXINT) { continue; } int direction = 0; int acount = 0; if (strncmp(hfile[i][j], "*k[", 3) == 0) { if (strchr(hfile[i][j], '-') != NULL) { direction = -1; } else if (strchr(hfile[i][j], '#') != NULL) { direction = 1; } acount = (strlen(hfile[i][j]) - 4)/2; if (direction == 0) { cout << "Info keysig no accidentals" << endl; break; } else { cout << "Info keysig " << acount; if (acount < 0) { cout << " flat"; } else { cout << " sharp"; } if (acount > 1) { cout << "s"; } cout << endl; break; } } } } // look for key interpretations if (hfile[i].getType() == E_humrec_interpretation) { for (j=0; j<hfile[i].getFieldCount(); j++) { if (hfile[i].getExInterpNum(j) != E_KERN_EXINT) { continue; } int length = strlen(hfile[i][j]); if (length < 3 || length > 4) { continue; } if (hfile[i][j][length-1] == ':') { cout << "Info key "; cout << (char)toupper(hfile[i][j][1]); if (hfile[i][j][2] == '-') { cout << "-flat"; } if (hfile[i][j][2] == '#') { cout << "-sharp"; } if (islower(hfile[i][j][1])) { cout << " Minor"; } else { cout << " Major"; } cout << endl; break; } } } // look for tempo markings if (hfile[i].getType() == E_humrec_interpretation) { for (j=0; j<hfile[i].getFieldCount(); j++) { if (hfile[i].getExInterpNum(j) != E_KERN_EXINT) { continue; } double tempomark = 0.0; if (strncmp(hfile[i][j], "*MM", 3) == 0 && isdigit(hfile[i][j][3])) { sscanf(hfile[i][j], "*MM%lf", &tempomark); cout << "Info Tempo " << tempomark << " MM per quarter note" << endl; break; } } } if (hfile[i].getType() != E_humrec_data) { continue; } for (j=0; j<hfile[i].getFieldCount(); j++) { if (hfile[i].getExInterpNum(j) != E_KERN_EXINT) { continue; } for (k=0; k<hfile[i].getTokenCount(j); k++) { if (strcmp(hfile[i][j], ".") == 0) { continue; } hfile[i].getToken(buffer1, j, k); if (strchr(buffer1, '_') != NULL) { // ignore notes which are tied continue; } if (strchr(buffer1, ']') != NULL) { // ignore notes which are tied continue; } preparePitch(buffer2, buffer1); duration = hfile.getTiedDuration(i, j, k); int note = Convert::kernToMidiNoteNumber(buffer2); if (classQ) { note = note % 12; } if (note < 0) { // don't display rests. continue; } cout << "Note\t"; // cout << hfile.getAbsBeat(i) << "\t"; cout << (int)(currentmillisecond+0.5) << "\t"; // cout << duration << "\t"; endmillisecond = currentmillisecond + duration * 60000 / tempo[i]; if (int(endmillisecond+0.5) == int(currentmillisecond+0.5)) { // give grace notes 1 millisecond duration... cout << (int)(endmillisecond+0.5)+1 << "\t"; } else { cout << (int)(endmillisecond+0.5) << "\t"; } cout << note; cout << "\n"; } } } } ////////////////////////////// // // preparePitch -- // void preparePitch(char* buffer2, const char* buffer1) { strcpy(buffer2, buffer1); } ////////////////////////////// // // usage -- // void usage(const char* command) { } // md5sum: 07eaaa60a484c3c4f66eb68cabcc9c8f kern2melisma.cpp [20080205]