// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Wed May 16 14:14:47 PDT 2001 // Last Modified: Wed May 16 14:14:50 PDT 2001 // Filename: ...sig/examples/all/scrub.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/scrub.cpp // Syntax: C++; museinfo // // Description: Remove chordal/non-chordal tones from input music. // // Things to do: Allow for pickup beats. // #include "humdrum.h" #include "ctype.h" #include "string.h" // function declarations void checkOptions(Options& opts, int argc, char* argv[]); void example(void); void usage(const char* command); void processFile(HumdrumFile& infile); int getDegree(int note, int root); void erasenote(HumdrumFile& infile, NoteList& note); // command line options: Options options; // database for command-line arguments int debugQ = 0; // for debugging Array<int> filter(10); // notes to keep/remove. double timebase = 1.0; // duration of each chord /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile; // input Humdrum Format file // 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)); } infile.analyzeRhythm("4"); // force the beat to be quarter notes for now processFile(infile); cout << infile; } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // processFile -- // void processFile(HumdrumFile& infile) { double beatstart = 0.0; Array<double> scores(40); Array<int> roots(infile.getNumLines()*10); Array<double> starttimes(infile.getNumLines()*10); roots.setGrowth(infile.getNumLines()*10); starttimes.setGrowth(infile.getNumLines()*10); roots.setSize(0); starttimes.setSize(0); roots.allowGrowth(1); starttimes.allowGrowth(1); int root; Array<double> p(3); p[0] = 0.573; p[1] = -4.0; p[2] = -3.0; while (beatstart+timebase-0.01 < infile.getTotalDuration()) { root = infile.measureChordRoot(scores, p, beatstart, beatstart+timebase-0.01, 0); starttimes.append(beatstart); roots.append(root); beatstart += timebase; } NoteListArray notelist; infile.generateNoteList(notelist, 0, infile.getNumLines() - 1); char buffer[128] = {0}; int i; int degree; int k = 0; for (i=0; i<notelist.getSize(); i++) { while (k < starttimes.getSize() && notelist[i].getAbsBeat() >= starttimes[k]) { if (debugQ) { cout << "beat " << starttimes[k] << "\troot = " << Convert::base40ToKern(buffer, 2+roots[k]+3*40) << endl; } k++; } if(debugQ) { cout << "\t" << Convert::base40ToKern(buffer, notelist[i].getPitch()); } degree = getDegree(notelist[i].getPitch(), roots[k-1]+2); if (debugQ) { cout << "\t=\tdegree " << degree; } if (degree >= 0 && filter[degree] == 0) { if (debugQ) { cout << " (remove)"; } notelist[i].setPitch(-1); } if (debugQ) { cout << endl; } } // list removed notes for (i=0; i<notelist.getSize(); i++) { if (notelist[i].getPitch() == -1) { if (debugQ) { cout << "Remove note at line=" << notelist[i].getLine() << "\tspine=" << notelist[i].getSpine() << "\ttoken=" << notelist[i].getToken() << endl; } erasenote(infile, notelist[i]); } } } ////////////////////////////// // // erasenote -- // void erasenote(HumdrumFile& infile, NoteList& note) { char buffer[64] = {0}; Convert::durationToKernRhythm(buffer, note.getFirstDur()); strcat(buffer, "r"); infile[note.getLine()].changeToken(note.getSpine(), note.getToken(), buffer); } ////////////////////////////// // // getDegree -- convert a note to a chord degree // -1 = invalid // 0 = root // 1 = third // 2 = fifth, etc. // int getDegree(int note, int root) { int interval = (note - root + 40) % 40; switch (interval) { case 0: return 0; case 1: return 7; case 2: return 7; case 3: return -1; case 4: return 4; case 5: return 4; case 6: return 4; case 7: return 4; case 8: return 4; case 9: return -1; case 10: return 8; case 11: return 8; case 12: return 1; case 13: return 1; case 14: return 8; case 15: return 5; case 16: return 5; case 17: return 5; case 18: return 5; case 19: return 5; case 20: return -1; case 21: return 9; case 22: return 2; case 23: return 2; case 24: return 2; case 25: return 9; case 26: return -1; case 27: return 6; case 28: return 6; case 29: return 6; case 30: return 6; case 31: return 6; case 32: return -1; case 33: return 10; case 34: return 3; case 35: return 3; case 36: return 3; case 37: return 3; case 38: return 7; case 39: return 7; default: return -1; } } ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("r|remove=s:", "scale degrees to remove"); opts.define("k|keep=s:13579AB", "scale degrees to keep"); opts.define("t|timebase=s:4", "chord analysis timebase"); 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, May 2001" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: May 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); } int i; const char* string; int length; for (i=0; i<filter.getSize(); i++) { filter[i] = 1; } if (opts.getBoolean("remove")) { for (i=0; i<filter.getSize(); i++) { filter[i] = 1; } string = opts.getString("remove"); length = strlen(string); for (i=0; i<=length; i++) { switch (toupper(string[i])) { case '1': filter[0] = 0; break; case '3': filter[1] = 0; break; case '5': filter[2] = 0; break; case '7': filter[3] = 0; break; case '9': filter[4] = 0; break; case 'A': filter[5] = 0; break; case 'B': filter[6] = 0; break; case 'C': filter[7] = 0; break; case 'D': filter[8] = 0; break; case 'E': filter[9] = 0; break; case '2': filter[4] = 0; break; case '4': filter[5] = 0; break; case '6': filter[6] = 0; break; case '8': filter[0] = 0; break; } } } else if (opts.getBoolean("keep")) { for (i=0; i<filter.getSize(); i++) { filter[i] = 0; } string = opts.getString("keep"); length = strlen(string); for (i=0; i<=length; i++) { switch (toupper(string[i])) { case '1': filter[0] = 1; break; case '3': filter[1] = 1; break; case '5': filter[2] = 1; break; case '7': filter[3] = 1; break; case '9': filter[4] = 1; break; case 'A': filter[5] = 1; break; case 'B': filter[6] = 1; break; case 'C': filter[7] = 1; break; case 'D': filter[8] = 1; break; case 'E': filter[9] = 1; break; case '2': filter[4] = 1; break; case '4': filter[5] = 1; break; case '6': filter[6] = 1; break; case '8': filter[0] = 1; break; } } } timebase = Convert::kernToDuration(opts.getString("timebase")); debugQ = opts.getBoolean("debug"); } ////////////////////////////// // // 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: 6750cc5dc8228a3499322988390e0a8f scrub.cpp [20050403]