// // Programmer: Craig Stuart Sapp // Creation Date: Wed Oct 27 11:03:38 PDT 2004 // Last Modified: Wed Oct 27 12:33:26 PDT 2004 // Filename: ...sig/examples/all/modid.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/modid.cpp // Syntax: C++; museinfo // // Description: Automatic modulation identification using the // Krumhansl-Schmuckler key-finding algorithm. // // A modulation is defined with following algorithm: // (1) defined a window size (e.g. 16 beats). // (2) choose a test modulation position in the score. // (3) if the window of music starting at that window generate the same // key analysis as a 1/2 window at the same location, then there // is a stable key after the test modulation position. // (4) if the window of music before the starting position is stable // according to the same method, then continue. // (5) if a window centered at the modulation point gives a lower // score for the two keys from the window before and after the // test modulation point, then mark the position in the score // as a modulation. // #include "humdrum.h" // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void example (void); void usage (const char* command); int getDurationLineStart (HumdrumFile& infile, double target); int getDurationLineEnd (HumdrumFile& infile, double target); void getModulation (int& mod, int& before, HumdrumFile& infile, int line, double window); void getModulationAnalysis (HumdrumFile& infile, Array& modulations, Array& beforemod); void printModulations (HumdrumFile& infile, Array& modulations, Array& beforemod); void printPitch (int value); // user interface variables Options options; // database for command-line arguments int appendQ = 0; // used with -a option int prependQ = 0; // used with -p option double window = 16.0; // used with -w option int debugQ = 0; // used with --debug option /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { // process the command-line options checkOptions(options, argc, argv); // if no command-line arguments read data file from standard input HumdrumFile infile; if (options.getArgCount() < 1) { infile.read(cin); } else { infile.read(options.getArg(1)); } infile.analyzeRhythm(); Array modulations; Array beforemod; getModulationAnalysis(infile, modulations, beforemod); printModulations(infile, modulations, beforemod); return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // printModulations -- // void printModulations(HumdrumFile& infile, Array& modulations, Array& beforemod) { int i; for (i=0; i= 12) { value -= 12; mode = 1; // minor key } int base40 = Convert::base12ToBase40(value); base40 = (base40 + 40) % 40; base40 = base40 + 3 * 40; if (mode == 1) { base40 += 40; } char buffer[64] = {0}; cout << Convert::base40ToKern(buffer, base40); } ////////////////////////////// // // getModulationAnalysis -- // void getModulationAnalysis(HumdrumFile& infile, Array& modulations, Array& beforemod) { modulations.setSize(infile.getNumLines()); modulations.setAll(-1); beforemod.setSize(infile.getNumLines()); beforemod.setAll(-1); int i; int mod; int before; for (i=0; i scores(24); int wafter = -1; // ending window index after mod point int w2after = -1; // ending half-window index after mod point int wbefore = -1; // starting window index before mod point int w2before = -1; // starting half-window index before mod point int midval = -1; // double rafter = -1.0; // rvalue for window after mod point // double r2after = -1.0; // rvalue for half-window after mod point // double rbefore = -1.0; // rvalue for window before mod point // double r2before = -1.0; // rvalue for half-window before mod point // double rmidbefore = -1.0; // rvalue 1 for mid-window // double rmidafter = -1.0; // rvalue 1 for mid-window int wafterstop = getDurationLineEnd(infile, infile[line].getAbsBeat()+window); int w2afterstop = getDurationLineEnd(infile, infile[line].getAbsBeat()+window/2.0); int wbeforestart = getDurationLineStart(infile, infile[line].getAbsBeat()-window); int w2beforestart = getDurationLineStart(infile, infile[line].getAbsBeat()-window/2.0); wafter = infile.analyzeKeyKS(scores, line, wafterstop); // rafter = scores[wafter]; w2after = infile.analyzeKeyKS(scores, line, w2afterstop); // r2after = scores[wafter]; wbefore = infile.analyzeKeyKS(scores, wbeforestart, line); // rbefore = scores[wafter]; w2before = infile.analyzeKeyKS(scores, w2beforestart, line); // r2before = scores[wafter]; midval = infile.analyzeKeyKS(scores, w2beforestart, w2afterstop); // rmidbefore = scores[wbefore]; // rmidafter = scores[wafter]; if (debugQ) { cout << "wa=" << wafter; cout << "\tw2a=" << w2after; cout << "\twb=" << wbefore; cout << "\tw2b=" << w2before; cout << endl; } mod = -1; before = -1; if ((midval == w2before) && (midval == w2after)) { if ((w2before != wbefore) || (w2after != wafter)) { before = midval; mod = -3; return; } } if (wbefore != w2before) { return; } if (wafter != w2after) { return; } if (wbefore == wafter) { if (midval == wbefore) { // indicate a stable local region before = midval; mod = -2; } return; } mod = wafter; before = wbefore; } ////////////////////////////// // // getDurationLineEnd -- return the index of the last line // with the specified duration (or less). // int getDurationLineEnd(HumdrumFile& infile, double target) { int i; for (i=infile.getNumLines()-1; i>=0; i--) { if (infile[i].getAbsBeat() <= target) { return i; } } return 0; } ////////////////////////////// // // getDurationLineStart -- return the index of the first line // with the specified duration (or greater). // int getDurationLineStart(HumdrumFile& infile, double target) { int i; for (i=0; i= target) { return i; } } return infile.getNumLines()-1; } ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("a|append=b", "append analysis to original score"); opts.define("p|prepend=b", "prepend analysis to original score"); opts.define("w|window=d:16.0", "analysis window size"); 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, Oct 2004" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 27 Oct 2004" << endl; cout << "compiled: " << __DATE__ << endl; cout << MUSEINFO_VERSION << endl; exit(0); } else if (opts.getBoolean("help")) { usage(opts.getCommand().c_str()); exit(0); } else if (opts.getBoolean("example")) { example(); exit(0); } appendQ = opts.getBoolean("append"); prependQ = opts.getBoolean("prepend"); window = opts.getDouble("window"); if (window <= 0) { window = 16.0; } debugQ = opts.getBoolean("debug"); } ////////////////////////////// // // 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: 21ad7c9a643a1215ab1b67e693066420 modid.cpp [20160320]