// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Tue Jan 16 11:25:31 PST 2001 // Last Modified: Mon Jan 29 14:02:45 PST 2001 // Last Modified: Fri Feb 2 12:05:51 PST 2001 (added weights display) // Last Modified: Tue Feb 6 19:13:51 PST 2001 (fixed -r option for large dur) // Last Modified: Wed Mar 21 13:31:19 PST 2001 (duration normalization added) // Filename: ...sig/examples/all/croot.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/croot.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, double duration); void generateAnalysis(HumdrumFile& infile, Array<int>& rootanalysis, Array<double>& rootscores, double duration); // 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 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 int srhythm = 4; // used with the -r option double empirical1 = -4; // used with the --e1 option double empirical2 = -3; // used with the --e2 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 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, duration); printAnalysis(infile, rootanalysis, rootscores, duration); } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // printAnalysis -- display the analysis results. // void printAnalysis(HumdrumFile& infile, Array<int>& rootanalysis, Array<double>& rootscores, double duration) { char buffer[1024] = {0}; int i; double fraction; int oldlocation = -1; int location; int n, m; if (rawQ) { for (i=0; i<rootanalysis.getSize(); i++) { if (rootanalysis[i] > 0) { cout << "beat: " << i * duration << "\t= " << Convert::base40ToKern(buffer, rootanalysis[i]) << ",\tscore = " << rootscores[i] << endl; } else { cout << "beat: " << i * duration << "\t= " << "rest" << "\tscore = " << 0 << endl; } } } else { for (i=0; i<infile.getNumLines(); i++) { switch (infile[i].getType()) { case E_humrec_data: fraction = fabs(infile[i].getAbsBeat()/duration); location = (int)fraction; fraction = fraction - (int)fraction; if (fraction > 0.999) { fraction = 0.0; } if (location - oldlocation > 1 && oldlocation > 0) { for (n=1; n<location-oldlocation; n++) { for (m=0; m<infile[i].getFieldCount(); m++) { cout << ".\t"; } cout << Convert::durationToKernRhythm(buffer, duration); if (rootanalysis[oldlocation + 1] > 0) { cout << Convert::base40ToKern(buffer, rootanalysis[oldlocation + n]); } else { cout << "r"; } if (weightsQ) { cout << "\t" << rootscores[oldlocation + n]; } cout << "\n"; } } oldlocation = location; cout << infile[i].getLine(); cout << "\t"; if (fraction < 0.001) { cout << Convert::durationToKernRhythm(buffer, duration); if (rootanalysis[location] > 0) { cout << Convert::base40ToKern(buffer, rootanalysis[location]); } else { cout << "r"; } } else { cout << "."; } if (weightsQ && fraction < 0.001) { cout << "\t" << rootscores[location]; } else if (weightsQ) { cout << "\t."; } cout << "\n"; break; case E_humrec_data_measure: fraction = fabs(infile[i].getAbsBeat()/duration); location = (int)fraction; fraction = fraction - (int)fraction; if (fraction > 0.999) { fraction = 0.0; } if (location - oldlocation > 1 && oldlocation > 0) { for (n=1; n<location-oldlocation; n++) { for (m=0; m<infile[i].getFieldCount(); m++) { cout << ".\t"; } cout << Convert::durationToKernRhythm(buffer, duration); if (rootanalysis[oldlocation + 1] > 0) { cout << Convert::base40ToKern(buffer, rootanalysis[oldlocation + n]); } else { cout << "r"; } if (weightsQ) { cout << "\t" << rootscores[oldlocation + n]; } cout << "\n"; } } oldlocation = location - 1; 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) { cout << "\t**kern"; 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: fraction = fabs(infile[i].getAbsBeat()/duration); location = (int)fraction; fraction = fraction - (int)fraction; if (fraction > 0.999) { fraction = 0.0; } if (location - oldlocation > 1 && oldlocation > 0) { for (n=1; n<location-oldlocation; n++) { for (m=0; m<infile[i].getSpineWidth(); m++) { cout << ".\t"; } cout << Convert::durationToKernRhythm(buffer, duration); if (rootanalysis[oldlocation + 1] > 0) { cout << Convert::base40ToKern(buffer, rootanalysis[oldlocation + n]); } else { cout << "r"; } if (weightsQ) { cout << "\t" << rootscores[oldlocation + n]; } cout << "\n"; } } oldlocation = location - 1; cout << infile[i].getLine() << "\n"; } } } } ////////////////////////////// // // generateAnalysis -- analyze the roots of the chords // void generateAnalysis(HumdrumFile& infile, Array<int>& rootanalysis, Array<double>& rootscores, double duration) { infile.analyzeRhythm("4"); // force the beat to be quarter notes for now Array<int> rhylev; infile.analyzeMetricLevel(rhylev); Array<double> tonicscores; int most = 0; Array<double> values; values.setSize(0); double startbeat = 0.0; double endbeat = 0.0; double totaldur = infile.getTotalDuration(); int size = (int)(totaldur/duration); int nextroot = 0; int lastroot = 0; int i; rootscores.setSize(size); rootscores.setSize(0); rootanalysis.setSize(size); rootanalysis.setSize(0); char buffer[128] = {0}; for (i=0; i<size; i++) { startbeat = duration * i; endbeat = startbeat + duration - 0.01; // cout << "StartBeat = " << startbeat << "\tduration = " << duration << endl; most = infile.analyzeChordProbabilityDur(values, startbeat, endbeat, rhylev, empirical1, empirical2, sx, sy); 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(values[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=i:4", "rhythm to measure root at"); opts.define("e1|empirical1=d:-4.0", "empirical rhythm value 1"); opts.define("e2|empirical2=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("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; } rval = opts.getInteger("rhythm")/4.0; srhythm = (int)(rval * 4.0); // can't handle some cases yet duration = 4.0 / srhythm; rlevel = log10((double)srhythm)/log10(2.0) - 2.0; empirical1 = opts.getDouble("empirical1"); empirical2 = opts.getDouble("empirical2"); sx = opts.getDouble("sx"); sy = opts.getDouble("sy"); octave = opts.getInteger("octave"); weightsQ = opts.getBoolean("weights"); } ////////////////////////////// // // 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: e10b1da3b33076262ad45749fede939a croot.cpp [20050403]