// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Tue Dec 2 21:56:54 PST 2003 // Last Modified: Tue Dec 2 21:56:58 PST 2003 // Filename: ...sig/examples/all/beat.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/beat.cpp // Syntax: C++; museinfo // // Description: Measure the duration since the last note // of the pitch class. Idea of Max Mathews for // application in Director Musices for performance // rules of pitch novelty. // #include "humdrum.h" #include <string.h> #include <ctype.h> // function declarations void checkOptions(Options& opts, int argc, char* argv[]); void example(void); void usage(const char* command); void printAnalysis(HumdrumFile& file, Array<Array<double> >& pastdur); void analyzeFile(HumdrumFile& infile, Array<Array<double> >& pastdur); double getAverage(HumdrumFile& infile, Array<Array<double> >& pastdist, double abeat, int index); // global variables Options options; // database for command-line arguments int appendQ = 0; // used with -a option int averageQ = 0; // used with -g option double averagebeat = 4.0; // used with -g option /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile; Array<Array<double> > pastdur; Array<int> lines; // 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)); } // analyze the input file according to command-line options analyzeFile(infile, pastdur); printAnalysis(infile, pastdur); } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // analyzeFile -- // void analyzeFile(HumdrumFile& infile, Array>& pastdur) { infile.analyzeRhythm(); Array<Array<int> > notes; pastdur.setSize(infile.getNumLines()); notes.setSize(infile.getNumLines()); int i, j, k; for (i=0; i<pastdur.getSize(); i++) { pastdur[i].setSize(32); pastdur[i].setGrowth(32); pastdur[i].setSize(0); notes[i].setSize(32); notes[i].setGrowth(32); notes[i].setSize(0); } char buffer[1024] = {0}; int tokencount; int base40; for (i=0; i<infile.getNumLines(); i++) { if (infile[i].getType() != E_humrec_data) { continue; } for (j=0; j<infile[i].getFieldCount(); j++) { if (strcmp(infile[i].getExInterp(j), "**kern") != 0) { continue; } if (strcmp(infile[i][j], ".") == 0) { continue; } tokencount = infile[i].getTokenCount(j); for (k=0; k<tokencount; k++) { infile[i].getToken(buffer, j, k); if (strchr(buffer, ']') != NULL) { // ignore tied notes continue; } if (strchr(buffer, '_') != NULL) { // ignore tied notes continue; } base40 = Convert::kernToBase40(buffer); if (base40 < 0) { continue; } // have an interesting note, so store it notes[i].append(base40); } } } // Now have list of notes and at what time they occur // so generate analysis data: Array<double> base40pc; base40pc.setSize(40); base40pc.setAll(-1.0); // -1 means that the note is the first to // be played on that pitch class in the piece Array<double> oldbase40pc; oldbase40pc.setSize(40); oldbase40pc.setAll(-1.0); double curdur; // current beat location double dist; // distance to last pc int bpc; for (i=0; i<notes.getSize(); i++) { if (notes[i].getSize() == 0) { continue; } oldbase40pc = base40pc; curdur = infile[i].getAbsBeat(); for (j=0; j<notes[i].getSize(); j++) { bpc = notes[i][j] % 40; if (oldbase40pc[bpc] == -1.0) { dist = -1.0; } else { dist = curdur - oldbase40pc[bpc]; } base40pc[bpc] = curdur; pastdur[i].append(dist); } } } ////////////////////////////// // // getAverage -- // double getAverage(HumdrumFile& infile, Array<Array<double> >& pastdist, double abeat, int index) { int i, j; int count = 0; double sum = 0.0; double startdur = infile[index].getAbsBeat(); for (i=index; i>=0; i--) { if (startdur - infile[i].getAbsBeat() > abeat) { break; } for (j=0; j<pastdist[i].getSize(); j++) { if (pastdist[i][j] == -1.0) { sum += infile[i].getAbsBeat(); } else { sum += pastdist[i][j]; } count++; } } if (count > 0) { return sum/count; } return 0; } ////////////////////////////// // // printAnalysis -- does a nauty thing by possibly chaning input // parameter pastdist. // void printAnalysis(HumdrumFile& file, Array >& pastdist) { int i; int jj; Array<double> average; average.setSize(file.getNumLines()); average.setAll(-1); if (averageQ) { for (i=0; i<file.getNumLines(); i++) { if (pastdist[i].getSize() != 0) { average[i] = getAverage(file, pastdist, averagebeat, i); pastdist[i].setSize(1); pastdist[i][0] = average[i]; } } } for (i=0; i<file.getNumLines(); i++) { switch (file[i].getType()) { case E_humrec_data_comment: if (appendQ) { cout << file[i] << "\t" << "!" << "\n"; } break; case E_humrec_data_kern_measure: if (appendQ) { cout << file[i] << "\t"; } cout << file[i][0] << "\n"; break; case E_humrec_interpretation: if (appendQ) { cout << file[i] << "\t"; } if (strncmp(file[i][0], "**", 2) == 0) { cout << "**pdist\n"; } else if (strcmp(file[i][0], "*-") == 0) { cout << "*-" << "\n"; } else { if (appendQ) { cout << "*\n"; } } break; case E_humrec_data: if (appendQ) { cout << file[i] << "\t"; } for (jj=0; jj<pastdist[i].getSize(); jj++) { cout << pastdist[i][jj]; if (jj < pastdist[i].getSize() - 1) { cout << " "; } } cout << "\n"; break; case E_humrec_none: case E_humrec_empty: case E_humrec_global_comment: case E_humrec_bibliography: default: cout << file[i] << "\n"; break; } } } ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("a|assemble=b"); // assemble analysis with input opts.define("g|average=d:4.0"); // average previous number of quarter notes opts.define("debug=b"); // determine bad input line num 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, 2 Dec 2003" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 2 Dec 2003" << 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); } appendQ = opts.getBoolean("assemble"); averageQ = opts.getBoolean("average"); averagebeat = opts.getDouble("average"); } ////////////////////////////// // // example -- example usage of the pcdist program // void example(void) { cout << " \n" << endl; } ////////////////////////////// // // usage -- gives the usage statement for the meter program // void usage(const char* command) { cout << " \n" << endl; } // md5sum: e05a991b469d6153810eaea065f0bcb5 pcdist.cpp [20050403]