// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Fri Apr 6 13:35:26 PDT 2001 // Last Modified: Mon May 21 20:20:14 PDT 2001 // Filename: ...sig/examples/all/croot2.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/croot2.cpp // Syntax: C++; museinfo // // Description: determine the root of a chord in a given timespan. // #include "humdrum.h" #include <string.h> #include <math.h> // function declarations void checkOptions(Options& opts, int argc, char* argv[]); void example(void); void usage(const char* command); void printAnalysis(HumdrumFile& infile, Array<int>& rootanalysis, Array<double>& rootscores); void generateAnalysis(HumdrumFile& infile, Array<int>& rootanalysis, Array<double>& rootscores); // global variables Options options; // database for command-line arguments int debugQ = 0; // used with the --debug option int rawQ = 0; // used with the --raw option int appendQ = 0; // used with the -a option int compoundQ = 1; // used with the -c option int kernQ = 0; // used with the -k option double rval = 1.0; // used with the -r option double rlevel = 1.0; // used with the -r option double duration = 1.0; // used with the -r option double srhythm = 4.0; // used with the -r option double delta = -4; // used with the --delta option double lambda = -3; // used with the --lambda option double sx = 0.578; // used with the --sx option double sy = 1.0; // used with the --sx option int octave = -1; // used with the -o option int weightsQ = 0; // used with the -w option int algorithm = 0; // used with the --algorithm option double pickupfraction = 0.0; /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile; // process the command-line options checkOptions(options, argc, argv); // figure out the number of input files to process int numinputs = options.getArgCount(); Array<int> rootanalysis; // roots analysed at various times Array<double> rootbeat; // absolute start beat of root Array<double> rootscores; // score of best root 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)); } generateAnalysis(infile, rootanalysis, rootscores); printAnalysis(infile, rootanalysis, rootscores); } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // printAnalysis -- display the analysis results. // void printAnalysis(HumdrumFile& infile, Array<int>& rootanalysis, Array<double>& rootscores) { char buffer[1024] = {0}; int i; int m; if (rawQ) { for (i=0; i<rootanalysis.getSize(); i++) { if (rootanalysis[i] > 0) { cout << "absbeat: " << pickupfraction + i * duration << "\t= " << Convert::base40ToKern(buffer, rootanalysis[i]) << ",\tscore = " << rootscores[i] << endl; } else { cout << "absbeat: " << pickupfraction + i * duration << "\t= " << "rest" << "\tscore = " << 0 << endl; } } return; } int j = 0; double pos; for (i=0; i<infile.getNumLines(); i++) { pos = j * duration + pickupfraction; // next beat in analysis switch (infile[i].getType()) { case E_humrec_data: if (infile[i].getAbsBeat() < pickupfraction) { cout << infile[i].getLine(); cout << "\t"; cout << Convert::durationToKernRhythm(buffer, pickupfraction); cout << "r"; if (weightsQ) { cout << "\t0"; } } else if (fabs(infile[i].getAbsBeat() - pos) < 0.01) { cout << infile[i].getLine(); cout << "\t"; cout << Convert::durationToKernRhythm(buffer, duration); if (rootanalysis[j] > 0) { cout << Convert::base40ToKern(buffer, rootanalysis[j]); } else { cout << "r"; } if (weightsQ) { cout << "\t" << rootscores[j]; } j++; pos = j * duration + pickupfraction; } else if (infile[i].getAbsBeat() < pos) { cout << infile[i].getLine() << "\t."; if (weightsQ) { cout << "\t."; } } else { while (pos < infile[i].getAbsBeat()) { cout << "XXXNEWLINE: "; cout << "\t"; cout << Convert::durationToKernRhythm(buffer, duration); if (rootanalysis[j] > 0) { cout << Convert::base40ToKern(buffer, rootanalysis[j]); } else { cout << "r"; } if (weightsQ) { cout << "\t" << rootscores[j]; } j++; pos = j * duration + pickupfraction; // next beat in analysis } } cout << "\n"; break; case E_humrec_data_measure: if (infile[i].getAbsBeat() > pos) { while (pos < infile[i].getAbsBeat()) { for (m=0; m<infile[i].getFieldCount(); m++) { cout << ".\t"; } cout << "YYYNEWLINE: "; cout << "\t"; cout << Convert::durationToKernRhythm(buffer, duration); if (rootanalysis[j] > 0) { cout << Convert::base40ToKern(buffer, rootanalysis[j]); } else { cout << "r"; } if (weightsQ) { cout << "\t" << rootscores[j]; } cout << "\n"; j++; pos = j * duration + pickupfraction; } } cout << infile[i].getLine(); cout << "\t" << infile[i][0]; if (weightsQ) { cout << "\t" << infile[i][0]; } cout << "\n"; break; case E_humrec_data_comment: cout << infile[i].getLine(); if (infile[i].equalFieldsQ()) { cout << "\t" << infile[i][0]; } else { cout << "\t!"; } if (weightsQ && infile[i].equalFieldsQ()) { cout << "\t" << infile[i][0]; } else if (weightsQ) { cout << "\t!"; } cout << "\n"; break; case E_humrec_data_interpretation: cout << infile[i].getLine(); if (strncmp(infile[i][0], "**", 2) == 0) { if (kernQ) { cout << "\t**kern"; } else { cout << "\t**root"; } if (weightsQ) { cout << "\t**weight"; } cout << "\n"; } else { if (infile[i].equalFieldsQ()) { cout << "\t" << infile[i][0]; } else { cout << "\t*"; } if (weightsQ && infile[i].equalFieldsQ()) { cout << "\t" << infile[i][0]; } else if (weightsQ) { cout << "\t*"; } cout << "\n"; } break; case E_humrec_global_comment: case E_humrec_bibliography: case E_humrec_none: case E_humrec_empty: default: cout << infile[i].getLine() << "\n"; } } } ////////////////////////////// // // generateAnalysis -- analyze the roots of the chords // void generateAnalysis(HumdrumFile& infile, Array<int>& rootanalysis, Array<double>& rootscores) { Array<double> tonicscores(40); infile.analyzeRhythm("4"); // force the beat to be quarter notes for now double pickupoffset = infile.getPickupDuration(); double totalduration = infile.getTotalDuration(); double fraction = pickupoffset/duration - int(pickupoffset/duration); pickupfraction = fraction * duration; double startbeat; if (fraction > 0.005) { startbeat = pickupfraction; } else { startbeat = 0.0; } int size = int((totalduration - startbeat)/duration); double currentbeat = 0.0; double endbeat = 0.0; int most = 0; int nextroot = 0; int lastroot = 0; int i; Array<double> parameters(3); parameters[0] = sx; parameters[1] = delta; parameters[2] = lambda; rootscores.setSize(size); rootscores.setSize(0); rootscores.allowGrowth(1); rootanalysis.setSize(size); rootanalysis.setSize(0); rootanalysis.allowGrowth(1); char buffer[128] = {0}; for (i=0; i<size; i++) { currentbeat = startbeat + duration * i; endbeat = currentbeat + duration - 0.01; most = infile.measureChordRoot(tonicscores, parameters, currentbeat, endbeat, algorithm, debugQ); if (most >= 0) { if (octave < 0) { nextroot = (most + 2) % 40 + 80; if (abs(nextroot + 40 - lastroot) < 13) { nextroot += 40; } else if (abs(nextroot - 40 - lastroot) < 13) { nextroot -= 40; } } else { nextroot = (most + 2) % 40 + 40 * octave; } Convert::base40ToKern(buffer, nextroot); lastroot = nextroot; } else { nextroot = 0; } rootanalysis.append(nextroot); if (most < 0) { double zero = 0.0; rootscores.append(zero); } else { rootscores.append(tonicscores[most]); } } } ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("a|append=b", "append analysis to data in output"); opts.define("raw=b", "raw display of output"); opts.define("C|compound=b", "don't try to use compound meters"); opts.define("r|rhythm=s:4", "rhythm to measure root at"); opts.define("delta=d:-4.0", "empirical rhythm value 1"); opts.define("lambda=d:-3.0", "empirical rhythm value 2"); opts.define("sx=d:0.578", "scale factor for the x-pitch space axis"); opts.define("sy=d:1.0", "scale factor for the y-pitch space axis"); opts.define("o|octave=i:-1", "octave number of bass line"); opts.define("w|weights=b", "display parallel spine of scores next to roots"); opts.define("g|algorithm=i:0", "controls which root algorithm to use"); opts.define("k|kern=b", "output root spine as **kern rather than **root"); 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 2000" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 21 Mar 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); } debugQ = opts.getBoolean("debug"); appendQ = opts.getBoolean("append"); rawQ = opts.getBoolean("raw"); if (opts.getBoolean("compound")) { compoundQ = 0; } else { compoundQ = 0; } duration = Convert::kernToDuration(opts.getString("rhythm")); srhythm = 4.0 / duration; rlevel = log10(srhythm)/log10(2.0) - 2.0; delta = opts.getDouble("delta"); lambda = opts.getDouble("lambda"); sx = opts.getDouble("sx"); sy = opts.getDouble("sy"); octave = opts.getInteger("octave"); weightsQ = opts.getBoolean("weights"); kernQ = opts.getBoolean("kern"); } ////////////////////////////// // // 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: bcbdaca8d63f596f978634d8f67bd7ed croot2.cpp [20050403]