// // 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 // Last Modified: Tue Apr 9 08:07:21 PDT 2013 Enabled multiple segment input // Last Modified: Mon Nov 11 23:41:54 PST 2013 Output null interpretations // Last Modified: Mon Nov 11 23:49:10 PST 2013 Defaut time is seconds // 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 #include #include #include #include "humdrum.h" // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void example (void); void printAnalysis (HumdrumFile& infile, vector& timings, vector& tempo, int setcount); void analyzeTiming (HumdrumFile& infile, vector& timings, vector& tempo); void usage (const char* command); void interpolateGeometric (HumdrumFile& infile, vector& tempo, int startindex, int stopindex); int getNextTempoIndex (HumdrumFile& infile, int startindex); void printtime (const string& filename, double totaldur); void doLinearInterpolation (HumdrumFile& infile, int setcount); void interpolateTimings (vector& timings, HumdrumFile& infile, int startindex, int endindex); void fixendingtimes (vector& 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[]) { HumdrumFileSet infiles; vector timings; vector tempo; checkOptions(options, argc, argv); infiles.read(options); double totaldur = 0.0; int i; for (i=0; i 1) { printtime(infiles[i].getFilename(), timings[(int)timings.size()-1]); } } else { printAnalysis(infiles[i], timings, tempo, infiles.getCount()); } } } 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 // #define UNKNOWNTIME 0 void doLinearInterpolation(HumdrumFile& infile, int setcount) { infile.analyzeRhythm("4"); // extract the timing data using -1 for undefined vector timings(infile.getNumLines(), INVALIDTIME); vector absbeat; double atime; for (int i=0; i 1) { infile.printNonemptySegmentLabel(cout); } int tfound = 0; for (int i=0; i& timings, HumdrumFile& infile) { int i; int lastdatai = -1; int lastlastdatai = -1; for (i=(int)timings.size()-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<(int)timings.size(); i++) { if (timings[i] == UNKNOWNTIME) { beatdiff = infile[i].getAbsBeat() - infile[lastdatai].getAbsBeat(); timings[i] = timings[lastdatai] + beatdiff * beatincrement; } } } ////////////////////////////// // // interpolateTimings -- do the actual interpolation work. // void interpolateTimings(vector& 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, vector& timings, vector& tempo) { infile.analyzeRhythm("4"); timings.resize(infile.getNumLines()); std::fill(timings.begin(), timings.end(), 0.0); tempo.resize(infile.getNumLines()); std::fill(tempo.begin(), tempo.end(), dtempo); tempo[0] = dtempo; double currtempo = dtempo; double input = 0.0; int count; vector tempoindicators; vector tempoindex; tempoindicators.reserve(1000); tempoindex.reserve(1000); double ritard = -1.0; double accel = -2.0; for (int i=1; i 0) { tempo[i-1] = currtempo; } tempo[i] = currtempo; } } else if (strcmp(infile[i][j], "*accel") == 0) { tempoindicators.push_back(accel); tempoindex.push_back(i); } else if (strcmp(infile[i][j], "*rit") == 0) { tempoindicators.push_back(ritard); tempoindex.push_back(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 (int i=1; i<(int)tempoindicators.size()-1; i++) { if ((tempoindicators[i] < 0) && (tempoindicators[i+1] > 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 (int 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, vector& 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, vector& tempo, int setcount) { int tempomark = 0; int i, j; int m; if (setcount > 1) { infile.printNonemptySegmentLabel(cout); } for (i=0; i", 2) == 0) { // expansion label cout << infile[i][0]; } else { cout << "*"; } if (prependQ) { cout << "\t" << infile[i]; } cout << "\n"; } break; } } } ////////////////////////////// // // usage -- gives the usage statement for the quality program // void usage(const char* command) { cout << " \n" << endl; } // md5sum: 7d14b04b406a149037c509dcd0ca540f gettime.cpp [20170605]