// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Fri Mar 18 22:08:55 PST 2005 // Last Modified: Sat Jun 3 18:46:57 PDT 2006 (changed tempo interp direction) // Last Modified: Sat Jun 3 18:46:57 PDT 2006 (added fill option) // Filename: ...sig/examples/all/time2tempo.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/time2tempo.cpp // Syntax: C++; museinfo // // Description: // #include "humdrum.h" #include <string.h> #include <stdio.h> // function declarations void checkOptions(Options& opts, int argc, char* argv[]); void example(void); void printAnalysis(HumdrumFile& infile, Array<double>& timings, Array<double>& tempo); void getTimings(HumdrumFile& infile, Array<double>& timings, Array<double>& tempo); void usage(const char* command); // global variables Options options; // database for command-line arguments int appendQ = 0; // used with -a option int prependQ = 0; // used with -p option int fillQ = 0; // used with -f option int roundQ = 0; // used with -r option int debugQ = 0; // used with --debug option /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile; Array<double> timings; Array<double> tempo; // 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)); } getTimings(infile, timings, tempo); printAnalysis(infile, timings, tempo); } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // getTimings -- Get an array of the times for each line in the // input file from a **time spine. Currently only look for // the first **time spine in the file. // void getTimings(HumdrumFile& infile, Array<double>& timings, Array<double>& tempo) { infile.analyzeRhythm("4"); int i; int j; timings.setSize(infile.getNumLines()); tempo.setSize(infile.getNumLines()); timings.setAll(-1.0); tempo.setAll(-1.0); double atime; int secondsQ = 0; // get the timing values from the **time spine. for (i=0; i<infile.getNumLines(); i++) { if (infile[i].getType() == E_humrec_interpretation) { for (j=0; j<infile[i].getFieldCount(); j++) { if (strcmp(infile[i].getExInterp(j), "**time") == 0) { if (strcmp(infile[i][j], "*u=sec") == 0) { // measuring time in seconds. secondsQ = 1; } else if (strcmp(infile[i][j], "*u=msec") == 0) { secondsQ = 0; } break; } } } if (infile[i].getType() != E_humrec_data) { continue; } for (j=0; j<infile[i].getFieldCount(); j++) { // just looking for the first **time spine for now... if (strcmp(infile[i].getExInterp(j), "**time") != 0) { continue; } if (strcmp(infile[i][j], ".") == 0) { timings[i] = -1.0; } else { if (sscanf(infile[i][j], "%lf", &atime) == 1) { timings[i] = atime; if (secondsQ) { // convert seconds measurements into milliseconds timings[i] *= 1000.0; } } else { timings[i] = -1.0; } } break; } } // the times have been extracted from the Humdrum data, so now // convert them into tempo markings. int lastindex = 0; double beatdur; double timedur; double atempo; for (i=0; i<infile.getNumLines(); i++) { if (timings[i] < 0.0) { continue; } beatdur = infile[i].getAbsBeat() - infile[lastindex].getAbsBeat(); timedur = (timings[i] - timings[lastindex])/1000.0; atempo = 60.0 * beatdur / timedur; tempo[lastindex] = atempo; if (roundQ) { tempo[lastindex] = (int)(tempo[lastindex] + 0.5); } lastindex = i; } // set all zero tempos to be the same as the previous // tempo marking. if (fillQ) { for (i=1; i<infile.getNumLines(); i++) { if (tempo[i] <= 0.0) { tempo[i] = tempo[i-1]; } } } } ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("a|append=b", "append analysis to input data"); opts.define("p|prepend=b", "prepend analysis to input data"); opts.define("r|round=b", "round output tempos to nearest integer"); opts.define("f|fill=b", "fill tempo spine removing null tokens"); 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, March 2004" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 4 June 2006" << 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"); roundQ = opts.getBoolean("round"); fillQ = opts.getBoolean("fill"); prependQ = opts.getBoolean("prepend"); if (appendQ) { // exclusive options prependQ = 0; } } ////////////////////////////// // // example -- example usage of the addtime program // void example(void) { cout << " \n" << endl; } ////////////////////////////// // // printAnalysis -- // void printAnalysis(HumdrumFile& infile, Array<double>& timings, Array<double>& tempo) { int tempomark = 1; // disabled for now double lasttempo = -1.0; int i; int m; for (i=0; i<infile.getNumLines(); i++) { switch (infile[i].getType()) { case E_humrec_global_comment: case E_humrec_bibliography: case E_humrec_none: case E_humrec_empty: cout << infile[i].getLine() << "\n"; break; case E_humrec_data: if (appendQ) { cout << infile[i].getLine() << "\t"; } if (tempomark == 0) { tempomark = 1; cout << "*MM" << tempo[i] << "\t"; for (m=0; m<infile[i].getFieldCount(); m++) { cout << "*"; if (m < infile[i].getFieldCount() - 1) { cout << "\t"; } } cout << "\n"; } if (!fillQ && tempo[i] <= 0.0) { cout << "."; } else if (!fillQ && tempo[i] == lasttempo) { cout << "."; } else { cout << tempo[i]; lasttempo = tempo[i]; } if (prependQ) { cout << "\t" << infile[i].getLine(); } cout << "\n"; break; case E_humrec_data_comment: if (appendQ) { cout << infile[i].getLine() << "\t"; } if (infile[i].equalFieldsQ("**kern")) { cout << infile[i][0]; } else { cout << "!"; } if (prependQ) { cout << "\t" << infile[i].getLine(); } cout << "\n"; break; case E_humrec_data_measure: if (appendQ) { cout << infile[i].getLine() << "\t"; } if (infile[i].equalFieldsQ("**kern")) { cout << infile[i][0]; } else { cout << "="; } if (prependQ) { cout << "\t" << infile[i].getLine(); } cout << "\n"; break; case E_humrec_data_interpretation: if (appendQ) { cout << infile[i].getLine() << "\t"; } if (strncmp(infile[i][0], "**", 2) == 0) { cout << "**tempo"; } else if (strcmp(infile[i][0], "*-") == 0) { cout << "*-"; } else if (strncmp(infile[i][0], "*MM", 3) == 0) { tempomark = 1; cout << infile[i][0]; } else { cout << "*"; } if (prependQ) { cout << "\t" << infile[i].getLine(); } cout << "\n"; break; } } } ////////////////////////////// // // usage -- gives the usage statement for the quality program // void usage(const char* command) { cout << " \n" << endl; } // md5sum: 3bc6af6a088a036d00da4efc0f00977f time2tempo.cpp [20060701]