// // Programmer: Craig Stuart Sapp // Creation Date: Mon Apr 15 20:05:01 PDT 2002 // Last Modified: Mon Apr 15 20:05:04 PDT 2002 // Last Modified: Sun Mar 20 23:37:41 PST 2005 (added *rit and *accel) // Last Modified: Sat Oct 8 22:14:11 PDT 2005 (added time interpolation) // Last Modified: Wed Mar 29 20:19:00 PST 2006 (fixed various errors for kglee) // Filename: ...sig/examples/all/gettime.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/gettime.cpp // Syntax: C++; museinfo // // Description: Add a spine indicating the time of performance for // a given line of music. // #include "humdrum.h" #include #include #include // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void example (void); void printAnalysis (HumdrumFile& infile, Array& timings, Array& tempo); void analyzeTiming (HumdrumFile& infile, Array& timings, Array& tempo); void usage (const char* command); void interpolateGeometric (HumdrumFile& infile, Array& tempo, int startindex, int stopindex); int getNextTempoIndex (HumdrumFile& infile, int startindex); void printtime (const char* filename, double totaldur); void doLinearInterpolation (HumdrumFile& infile); void interpolateTimings (Array& timings, HumdrumFile& infile, int startindex, int endindex); void fixendingtimes (Array& timings, HumdrumFile& infile); // global variables Options options; // database for command-line arguments int appendQ = 0; // used with -a option int prependQ = 0; // used with -p option int debugQ = 0; // used with --debug option double offset = 0.0; // used with -o option int style = 's'; // used with -m option double dtempo = 60.0; // used with -d option int tempoQ = 0; // used with -t option int changeQ = 1; // used with -C option int roundQ = 1; // used with -R option int totalQ = 0; // used with --total option int interpQ = 0; // used with -i option /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile; Array timings; Array tempo; // process the command-line options checkOptions(options, argc, argv); // figure out the number of input files to process int numinputs = options.getArgCount(); double totaldur = 0.0; for (int i=0; i 1) { printtime(options.getArg(i+1), timings[timings.getSize()-1]); } } else { printAnalysis(infile, timings, tempo); } } } if (totalQ) { printtime("", totaldur); } return 0; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////// // // doLinearInterpolation -- interpolate the timings values in the // score based on timing values which are currently present. // // #define INVALIDTIME -100000 #define UNKNOWNTIME -1 void doLinearInterpolation(HumdrumFile& infile) { infile.analyzeRhythm("4"); // extract the timing data using -1 for undefined Array timings; Array absbeat; timings.setSize(infile.getNumLines()); timings.setAll(INVALIDTIME); double atime; int i, j; for (i=0; i& timings, HumdrumFile& infile) { int i; int lastdatai = -1; int lastlastdatai = -1; for (i=timings.getSize()-1; i>=0; i--) { if ((lastdatai == -1) && (timings[i] >= 0)) { lastdatai = i; } else if ((lastlastdatai == -1) && (timings[i] >= 0)) { lastlastdatai = i; break; } } if ((lastdatai < 0) || (lastlastdatai < 0)) { return; } double beatincrement = (timings[lastdatai] - timings[lastlastdatai]) / (infile[lastdatai].getAbsBeat() - infile[lastlastdatai].getAbsBeat()); double beatdiff = 0.0; for (i=lastdatai+1; i& timings, HumdrumFile& infile, int startindex, int endindex) { int i; double beatwidth = infile[endindex].getAbsBeat() - infile[startindex].getAbsBeat(); double timewidth = timings[endindex] - timings[startindex]; double lbeat = 0.0; for (i=startindex+1; i= 3600) { hours = (int)(totaldur / 3600); totaldur -= hours * 3600; } if (totaldur >= 60) { minutes = (int)(totaldur / 60); totaldur -= minutes * 60; } if (hours > 0) { cout << hours; cout << ":"; if (minutes < 10) { cout << "0"; } cout << minutes << ":"; if (totaldur < 10) { cout << "0"; } cout << totaldur; cout << " hours" << endl; } else if (minutes > 0) { cout << minutes << ":"; if (totaldur < 10) { cout << "0"; } cout << totaldur; cout << " minutes" << endl; } else { cout << totaldur << " seconds" << endl; } } ////////////////////////////// // // analyzeTiming -- determing the absolute time position of each // line in the file. // void analyzeTiming(HumdrumFile& infile, Array& timings, Array& tempo) { infile.analyzeRhythm("4"); timings.setSize(infile.getNumLines()); timings.setAll(0.0); tempo.setSize(infile.getNumLines()); tempo.setAll(dtempo); tempo[0] = dtempo; double currtempo = dtempo; double input = 0.0; int count; Array tempoindicators; Array tempoindex; tempoindicators.setSize(1000); tempoindicators.setSize(0); tempoindicators.setGrowth(1000); tempoindex.setSize(1000); tempoindex.setSize(0); tempoindex.setGrowth(1000); double ritard = -1.0; double accel = -2.0; int i; int j; for (i=1; i 0) { tempo[i-1] = currtempo; } tempo[i] = currtempo; } } else if (strcmp(infile[i][j], "*accel") == 0) { tempoindicators.append(accel); tempoindex.append(i); } else if (strcmp(infile[i][j], "*rit") == 0) { tempoindicators.append(ritard); tempoindex.append(i); } break; } } tempo[i] = currtempo; timings[i] = timings[i-1] + (infile[i].getAbsBeat() - infile[i-1].getAbsBeat()) * 60.0/currtempo; } if (!changeQ) { // do not adjust for *rit and *accel markers return; } // go back and geometrically interpolate the tempo markings // when there are *accel and *rit markers in the data. for (i=1; i 0)) { interpolateGeometric(infile, tempo, tempoindex[i], tempoindex[i+1]); } } // the following code will have to be debugged (mostly for off-by-one // errors). // adjust the timing values double beatdiff; double increment = 1.0/32.0; double starttempo; double stoptempo; double timesum; double logtem1; double logtem2; double tfraction; double ftempo; double beatduration; int ntindex; double startbeat; double stopbeat; for (i=1; i= increment) { tfraction = ((beatduration - beatdiff) / beatduration); ftempo = pow(10.0, logtem1 + (logtem2 - logtem1) * tfraction); timesum += increment * 60/ftempo; beatdiff -= increment; } if (beatduration > 0.0) { tfraction = ((beatduration - beatdiff) / beatduration); ftempo = pow(10.0, logtem1 + (logtem2 - logtem1) * tfraction); timesum += beatdiff * 60/ftempo; } else { timesum = 0.0; } timings[i] = timings[i-1] + timesum; } } } ////////////////////////////// // // getNextTempoIndex -- // int getNextTempoIndex(HumdrumFile& infile, int startindex) { int i = startindex + 1; int stopindex = -1; while (i < infile.getNumLines()) { if (infile[i].getAbsBeat() > infile[startindex].getAbsBeat()) { stopindex = i; break; } i++; } if (stopindex < 0) { stopindex = infile.getNumLines() - 1; } return stopindex; } ////////////////////////////// // // interpolateGeometric -- // void interpolateGeometric(HumdrumFile& infile, Array& tempo, int startindex, int stopindex) { double duration = 0.0; double newtempo = 0.0; double beatstart = infile[startindex].getAbsBeat(); double beatstop = infile[stopindex].getAbsBeat(); double starttempo = tempo[startindex]; double stoptempo = tempo[stopindex]; double logstart = log10(starttempo); double logstop = log10(stoptempo); double tfraction; duration = beatstop - beatstart; int i; for (i=startindex+1; i& timings, Array& tempo) { int tempomark = 0; int i, j; int m; for (i=0; i