Goto: [ Program Documentation ]
// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Sun Oct 22 15:33:41 PDT 2000 // Last Modified: Sun May 26 19:39:01 PDT 2002 (mostly finished) // Last Modified: Tue Mar 16 05:53:19 PST 2010 (added *M meter description) // Last Modified: Wed Apr 21 14:31:44 PDT 2010 (added search feature) // Last Modified: Wed May 19 15:30:49 PDT 2010 (added tick & rational values) // Filename: ...sig/examples/all/beat.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/beat.cpp // Syntax: C++; museinfo // // Description: Generates metrical location data for **kern entries // Test functions for the built-in rhythmic analysis // in the HumdrumFile class. Should give the same // output as the beat program. // // There are two cases when an incomplete measure needs to // be counted backwards. These cases will be handled by // the beat program: // (1) an initial pickup beat // (2) a repeat sign breaks a true measure // // There is a bug that needs fixing: // The *M2/2 interpretations are erased (at least with the -s option) // // five types of outputs can be given: // -s = sum the number of beats in a measure // = display the beat (default if no other output type given) // -d = duration // -c = cumulative running total beat/duration // #include "humdrum.h" #include <math.h> #include <string.h> #include <ctype.h> #ifndef OLDCPP #include <sstream> #define SSTREAM stringstream #define CSTRING str().c_str() using namespace std; #else #ifdef VISUAL #include <strstrea.h> /* for windows 95 */ #else #include <strstream.h> #endif #define SSTREAM strstream #define CSTRING str() #endif // function declarations void checkOptions(Options& opts, int argc, char* argv[]); void example(void); void usage(const char* command); void printOutput(HumdrumFile& file, Array<RationalNumber>& Bfeatures, Array<int>& Blines, Array<RationalNumber>& Dfeatures, Array<int>& Dlines, Array<int>& tickanalysis); RationalNumber getPickupDuration(HumdrumFile& file); void fillSearchString(Array<double>& searcher, const char* string); void printSearchResults(HumdrumFile& infile, Array<RationalNumber>& Bfeatures, Array<int>& Blines, Array<RationalNumber>& Dfeatures, Array<int>& Dlines); void printSearchResultsFinal(Array<int>& linematch, HumdrumFile& infile, Array<RationalNumber>& Bfeatures, Array<int>& Blines, Array<RationalNumber>& Dfeatures, Array<int>& Dloines); void doBeatSearch(Array<int>& results, HumdrumFile& infile, Array<double> search, Array<RationalNumber>& Bfeatures, Array<int>& Blines); void doDurSearch(Array<int>& results, HumdrumFile& infile, Array<double> search, Array<RationalNumber>& Dfeatures, Array<int>& Dlines); void doDurSearch(Array<int>& results, HumdrumFile& infile, Array<double> search, Array<double>& Dfeatures, Array<int>& Dlines); void mergeResults(Array<int>& output, Array<int>& input1, Array<int>& input2); void printSequence(Array<double>& pattern); void printSequence(Array<RationalNumber>& pattern); void fillMeasureInfo(HumdrumFile& infile, Array<double>& measures); void doComparison(Array<int>& results, Array<int>& line, Array<double>& search, Array<double>& data, HumdrumFile& infile); int checkForWildcard(Array<double>& sequence); void extractBeatFeatures(HumdrumFile& infile, Array<int>& line, Array<RationalNumber>& data); void extractDurFeatures(HumdrumFile& infile, Array<int>& line, Array<RationalNumber>& data); void printSequence(Array<double>& features, Array<int>& lines, Array<double>& search, int startline); void printSequence(Array<RationalNumber>& features, Array<int>& lines, Array<RationalNumber>& search, int startline); void printSequence(Array<RationalNumber>& features, Array<int>& lines, Array<double>& search, int startline); void printMatchesWithData(Array<int>& linematch, HumdrumFile& infile); void fillAttackArray(HumdrumFile& infile, Array<int>& attacks); int getCountForLine(HumdrumFile& infile, int line); int doTickAnalysis(Array<int>& tickanalysis, HumdrumFile& infile); RationalNumber getDurationOfFirstMeasure(HumdrumFile& file); // global variables Options options; // database for command-line arguments int appendQ = 0; // used with -a option int prependQ = 0; // used with -p option int durQ = 0; // used with -d option int absQ = 0; // used with -t option int beatQ = 0; // used with -b option int sumQ = 0; // used with -s option int zeroQ = 0; // zero offset instead of 1 for first beat int nullQ = 0; // used with -n option Array<double> Bsearch; // used with -B option Array<double> Dsearch; // used with -D option double Rvalue = -1.0; // used with -R option double Tolerance = 0.001; // used for rounding int Attack = 1; // used with -A option Array<int> Attacks; // used with -A option int tickQ = 0; // used with -t option int rationalQ= 0; // used with -r option int tpwQ = 0; // used with --tpw option int tpqQ = 0; // used with --tpq option const char* beatbase = "4"; // used with --beatsize option int uQ = 0; // used for -f and -u interactions /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile; Array<RationalNumber> Bfeatures; // used to extract beat data from input Array<RationalNumber> Dfeatures; // used to extract duration data from input Array<int> Blines; // used to extract beat data from input Array<int> Dlines; // used to extract duration data from input // 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 infile.analyzeRhythm(beatbase); Array<int> tickanalysis; tickanalysis.setSize(infile.getNumLines()); tickanalysis.setAll(0); int tickfactor = 1; if (tickQ) { tickfactor = doTickAnalysis(tickanalysis, infile); } if (tpwQ) { cout << infile.getMinTimeBase() * tickfactor << endl; exit(0); } else if (tpqQ) { cout << infile.getMinTimeBase() * tickfactor /4.0 << endl; exit(0); } fillAttackArray(infile, Attacks); extractBeatFeatures(infile, Blines, Bfeatures); extractDurFeatures(infile, Dlines, Dfeatures); if (Bsearch.getSize() > 0 || Dsearch.getSize() > 0) { printSearchResults(infile, Bfeatures, Blines, Dfeatures, Dlines); } else { printOutput(infile, Bfeatures, Blines, Dfeatures, Dlines, tickanalysis); } } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // doTickAnalysis -- // int doTickAnalysis(Array& tickanalysis, HumdrumFile& infile) { int i; tickanalysis.setSize(infile.getNumLines()); Array<RationalNumber> pretick(tickanalysis.getSize()); int minrhy = infile.getMinTimeBase(); if (minrhy <= 0.0) { return 1; } RationalNumber value; int monitor = 0; for (i=0; i<infile.getNumLines()-1; i++) { value = ((infile[i+1].getAbsBeatR()-infile[i].getAbsBeatR())/4)*minrhy; pretick[i] = value; if (value.getDenominator() != 1) { monitor = 1; } } if (monitor == 0) { for (i=0; i<pretick.getSize(); i++) { tickanalysis[i] = pretick[i].getNumerator(); } return 1; } for (i=0; i<pretick.getSize(); i++) { // estimate a multiplication of 4 to remove fractional part. tickanalysis[i] = pretick[i].getNumerator() * 4; } return 4; } ////////////////////////////// // // fillAttackArray -- // void fillAttackArray(HumdrumFile& infile, Array & attacks) { int i; attacks.setSize(infile.getNumLines()); attacks.allowGrowth(0); attacks.setAll(0); if (Attack <= 0) { // don't need to waste time analyzing the attack structure of the data... return; } int count; for (i=0; i<infile.getNumLines(); i++) { count = 0; if (infile[i].isData()) { count = getCountForLine(infile, i); } attacks[i] = count; } } ////////////////////////////// // // getCountForLine -- return the number of note attacks on the given // line in the Humdrum File. Only **kern data is examined. Rests // and tied notes are ignored when counting attacks. // int getCountForLine(HumdrumFile& infile, int line) { int j, k; char buffer[128] = {0}; int output = 0; int tcount; for (j=0; j<infile[line].getFieldCount(); j++) { if (!infile[line].isExInterp(j, "**kern")) { continue; } tcount = infile[line].getTokenCount(j); for (k=0; k<tcount; k++) { infile[line].getToken(buffer, j, k); if (strchr(buffer, 'r') != NULL) { // ignore rests continue; } if (strcmp(buffer, ".") == 0) { // ignore null tokens continue; } if (strchr(buffer, '_') != NULL) { // ignore notes which are in the middle of a series of tied notes continue; } if (strchr(buffer, ']') != NULL) { // ignore notes which are at the end of a series of tied notes continue; } output++; } } return output; } ////////////////////////////// // // printSearchResults -- Search for beat and/or duration patterns // in the composition rhythmic data // void printSearchResults(HumdrumFile& infile, Array<RationalNumber>& Bfeatures, Array<int>& Blines, Array<RationalNumber>& Dfeatures, Array<int>& Dlines) { Array<int> Bresults; Array<int> Dresults; Bresults.setSize(100000); Bresults.setGrowth(100000); Bresults.setSize(0); Dresults.setSize(100000); Dresults.setGrowth(100000); Dresults.setSize(0); if ((Bsearch.getSize() > 0) && (Dsearch.getSize() > 0)) { doBeatSearch(Bresults, infile, Bsearch, Bfeatures, Blines); doDurSearch(Dresults, infile, Dsearch, Dfeatures, Dlines); Array<int> finalresults; mergeResults(finalresults, Bresults, Dresults); cout << "!!parallel beat search: "; printSequence(Bsearch); cout << endl; cout << "!!parallel duration search: "; printSequence(Dsearch); cout << endl; printSearchResultsFinal(finalresults, infile, Bfeatures, Blines, Dfeatures, Dlines); } else if (Bsearch.getSize() > 0) { doBeatSearch(Bresults, infile, Bsearch, Bfeatures, Blines); cout << "!!beat search: "; printSequence(Bsearch); cout << endl; printSearchResultsFinal(Bresults, infile, Bfeatures, Blines, Dfeatures, Dlines); } else if (Dsearch.getSize() > 0) { doDurSearch(Dresults, infile, Dsearch, Dfeatures, Dlines); cout << "!!duration search: "; printSequence(Dsearch); cout << endl; printSearchResultsFinal(Dresults, infile, Bfeatures, Blines, Dfeatures, Dlines); } else { cout << "ERROR in search" << endl; } } ////////////////////////////// // // printSequence -- // void printSequence(Array & pattern) { int i; for (i=0; i<pattern.getSize(); i++) { if (pattern[i] < 0) { cout << "*"; } else { cout << pattern[i]; } if (i < pattern.getSize()-1) { cout << ' '; } } } void printSequence(Array & pattern) { int i; for (i=0; i<pattern.getSize(); i++) { if (pattern[i] < 0) { cout << "*"; } else { cout << pattern[i]; } if (i < pattern.getSize()-1) { cout << ' '; } } } ////////////////////////////// // // checkForWildcard -- returns true if any of the values are negative. // int checkForWildcard(Array & sequence) { int i; for (i=0; i<sequence.getSize(); i++) { if (sequence[i] < 0.0) { return 1; } } return 0; } ////////////////////////////// // // printMatchesWithData -- // void printMatchesWithData(Array & linematch, HumdrumFile& infile) { int i; int counter = 1; Array<int> lookup; lookup.setSize(infile.getNumLines()); lookup.allowGrowth(0); lookup.setAll(-1); for (i=0; i<linematch.getSize(); i++) { lookup[linematch[i]] = counter++; } for (int i=0; i<infile.getNumLines(); i++) { switch (infile[i].getType()) { /* case E_humrec_data_comment: break; */ case E_humrec_data_kern_measure: if (prependQ) { cout << infile[i][0] << "\t"; cout << infile[i] << "\n"; } else if (appendQ) { cout << infile[i] << "\t"; cout << infile[i][0] << "\n"; } else { cout << infile[i][0] << "\n"; } break; case E_humrec_interpretation: if (appendQ) { cout << infile[i] << "\t"; } if (strncmp(infile[i][0], "**", 2) == 0) { cout << "**match"; } else if (strcmp(infile[i][0], "*-") == 0) { cout << "*-"; } else { cout << "*"; } if (prependQ) { cout << "\t" << infile[i]; } cout << "\n"; break; case E_humrec_data: if (appendQ) { cout << infile[i] << "\t"; } if (lookup[i] < 0) { cout << "."; } else { cout << lookup[i]; } if (prependQ) { cout << "\t" << infile[i]; } cout << "\n"; break; case E_humrec_local_comment: if (appendQ) { cout << infile[i] << "\t"; } cout << "!"; if (prependQ) { cout << "\t" << infile[i]; } cout << "\n"; break; case E_humrec_none: case E_humrec_empty: case E_humrec_global_comment: case E_humrec_bibliography: default: cout << infile[i] << "\n"; break; } } } ////////////////////////////// // // printSearchResultsFinal -- // void printSearchResultsFinal(Array<int>& linematch, HumdrumFile& infile, Array<RationalNumber>& Bfeatures, Array<int>& Blines, Array<RationalNumber>& Dfeatures, Array<int>& Dlines) { cout << "!!matches: " << linematch.getSize() << "\n"; if (appendQ || prependQ) { printMatchesWithData(linematch, infile); return; } Array<double> measures; fillMeasureInfo(infile, measures); int hasBWildcard = checkForWildcard(Bsearch); int hasDWildcard = checkForWildcard(Dsearch); int i; cout << "**line\t**bar\t**beat\t**absb"; if (hasBWildcard) { cout << "\t**bseq"; } if (hasDWildcard) { cout << "\t**dseq"; } cout << "\n"; for (i=0; i<linematch.getSize(); i++) { cout << linematch[i]-1; cout << "\t" << measures[linematch[i]]; if (zeroQ) { cout << "\t" << infile[linematch[i]].getBeat()-1; } else { cout << "\t" << infile[linematch[i]].getBeat(); } cout << "\t" << infile[linematch[i]].getAbsBeat(); if (hasBWildcard) { cout << "\t"; printSequence(Bfeatures, Blines, Bsearch, linematch[i]); } if (hasDWildcard) { cout << "\t"; printSequence(Dfeatures, Dlines, Dsearch, linematch[i]); } cout << endl; } cout << "*-\t*-\t*-\t*-"; if (hasBWildcard) { cout << "\t*-"; } if (hasDWildcard) { cout << "\t*-"; } cout << "\n"; } /////////////////////////////// // // printSequence -- // void printSequence(Array<double>& features, Array<int>& lines, Array<double>& search, int startline) { int index = -1; int i; for (i=0; i<lines.getSize(); i++) { if (lines[i] == startline) { index = i; break; } } if (index < 0) { cout << "."; return; } int stopindex = index + search.getSize() - 1; for (i=index; (i<features.getSize()) && (i<=stopindex); i++) { cout << features[i]; if (i < stopindex) { cout << " "; } } } void printSequence(Array<RationalNumber>& features, Array<int>& lines, Array<double>& search, int startline) { int index = -1; int i; for (i=0; i<lines.getSize(); i++) { if (lines[i] == startline) { index = i; break; } } if (index < 0) { cout << "."; return; } int stopindex = index + search.getSize() - 1; for (i=index; (i<features.getSize()) && (i<=stopindex); i++) { cout << features[i]; if (i < stopindex) { cout << " "; } } } /*void printSequence(Array<double>& features, Array<int>& lines, Array<double>& search, int startline) { int index = -1; int i; for (i=0; i<lines.getSize(); i++) { if (lines[i] == startline) { index = i; break; } } if (index < 0) { cout << "."; return; } int stopindex = index + search.getSize() - 1; for (i=index; (i<features.getSize()) && (i<=stopindex); i++) { cout << features[i]; if (i < stopindex) { cout << " "; } } } */ /* void printSequence(Array<double>& features, Array<int>& lines, Array<double>& search, int startline) { int index = -1; int i; for (i=0; i<lines.getSize(); i++) { if (lines[i] == startline) { index = i; break; } } if (index < 0) { cout << "."; return; } int stopindex = index + search.getSize() - 1; for (i=index; (i<features.getSize()) && (i<=stopindex); i++) { cout << features[i]; if (i < stopindex) { cout << " "; } } } */ void printSequence(Array<RationalNumber>& features, Array<int>& lines, Array<RationalNumber>& search, int startline) { int index = -1; int i; for (i=0; i<lines.getSize(); i++) { if (lines[i] == startline) { index = i; break; } } if (index < 0) { cout << "."; return; } int stopindex = index + search.getSize() - 1; for (i=index; (i<features.getSize()) && (i<=stopindex); i++) { cout << features[i]; if (i < stopindex) { cout << " "; } } } ////////////////////////////// // // fillMeasureInfo -- // void fillMeasureInfo(HumdrumFile& infile, Array & measures) { int i; measures.setSize(infile.getNumLines()); measures.allowGrowth(0); measures.setAll(0.0); double current = 0.0; for (i=0; i<infile.getNumLines(); i++) { if (infile[i].isMeasure()) { sscanf(infile[i][0], "=%lf", ¤t); } measures[i] = current; } } ////////////////////////////// // // mergeResults -- do an intersection of two lists of sorted integers // void mergeResults(Array & output, Array & input1, Array & input2) { int i, j; int maxsize = input1.getSize(); if (input2.getSize() < maxsize) { maxsize = input2.getSize(); } output.setSize(maxsize); output.setSize(0); if (maxsize == 0) { return; } int similar; j=0; for (i=0; i<input1.getSize(); i++) { while ((j<input2.getSize()) && (input2[j] < input1[i])) { j++; } if (j >= input2.getSize()) { break; } if (input2[j] == input1[i]) { similar = input2[j]; output.append(similar); } } } ////////////////////////////// // // doBeatSearch -- search for specific beat pattern in data. // void doBeatSearch(Array<int>& results, HumdrumFile& infile, Array<double> search, Array<RationalNumber>& Bfeatures, Array<int>& Blines) { // extractBeatFeatures(infile, Blines, Bfeatures); Array<double> doubleBfeatures; doubleBfeatures.setSize(Bfeatures.getSize()); int i; for (i=0; i<doubleBfeatures.getSize(); i++) { doubleBfeatures[i] = Bfeatures[i].getFloat(); } doComparison(results, Blines, search, doubleBfeatures, infile); } ////////////////////////////// // // extractBeatFeatures -- // void extractBeatFeatures(HumdrumFile& infile, Array<int>& line, Array<RationalNumber>& data) { line.setSize(infile.getNumLines()); line.setSize(0); data.setSize(infile.getNumLines()); data.setSize(0); int lval; RationalNumber bval; int i; for (i=0; i<infile.getNumLines(); i++) { if (!infile[i].isData()) { continue; } bval = infile[i].getBeatR(); lval = i; if (Attacks[i] < Attack) { // ignore lines which do not have enough note onsets continue; } line.append(lval); data.append(bval); } } ////////////////////////////// // // extractDurFeatures -- // void extractDurFeatures(HumdrumFile& infile, Array<int>& line, Array<RationalNumber>& data) { line.setSize(infile.getNumLines()); line.setSize(0); data.setSize(infile.getNumLines()); data.setSize(0); int lval; RationalNumber bval; int i; for (i=0; i<infile.getNumLines(); i++) { if (!infile[i].isData()) { continue; } bval = infile[i].getDurationR(); if (zeroQ) { bval = bval - 1; } lval = i; if (Attacks[i] < Attack) { // ignore lines which do not have enough note onsets, // adding duration of current line to last data line // which exceeds the onset threshold test. if (data.getSize() > 0) { data[data.getSize()-1] += bval; } continue; } line.append(lval); data.append(bval); } } ////////////////////////////// // // doComparison -- // void doComparison(Array<int>& results, Array<int>& line, Array<double>& search, Array<double>& data, HumdrumFile& infile) { results.setSize(data.getSize() - search.getSize() + 1); results.setSize(0); double startdur; double stopdur; int match; int i, j; for (i=0; i<data.getSize() - search.getSize() + 1; i++) { match = 1; for (j=0; j<search.getSize(); j++) { if (search[j] < 0) { // for wildcard match (*) continue; } if (fabs(search[j] - data[i+j]) > Tolerance) { match = 0; break; } } if (match) { if (Rvalue > 0) { startdur = infile[line[i]].getAbsBeat(); stopdur = infile[line[i+search.getSize()-1]].getAbsBeat(); if (fabs(Rvalue - (stopdur-startdur)) < Tolerance) { results.append(line[i]); } } else { results.append(line[i]); } } } } ////////////////////////////// // // doDurSearch -- search for specific beat pattern in data. // void doDurSearch(Array<int>& results, HumdrumFile& infile, Array<double> search, Array<double>& Dfeatures, Array<int>& Dlines) { // extractDurFeatures(infile, Dlines, Dfeatures); doComparison(results, Dlines, search, Dfeatures, infile); } void doDurSearch(Array<int>& results, HumdrumFile& infile, Array<double> search, Array<RationalNumber>& Dfeatures, Array<int>& Dlines) { int i; Array<double> doubleDfeatures(Dfeatures.getSize()); for (i=0; i<doubleDfeatures.getSize(); i++) { doubleDfeatures[i] = Dfeatures[i].getFloat(); } doComparison(results, Dlines, search, doubleDfeatures, infile); } ////////////////////////////// // // getPickupDuration -- // RationalNumber getPickupDuration(HumdrumFile& file) { int i; for (i=0; i<file.getNumLines(); i++) { if (!file[i].isMeasure()) { continue; } return file[i].getAbsBeatR(); } RationalNumber nothing(-1,1); return nothing; } ////////////////////////////// // // printOutput -- // void printOutput(HumdrumFile& file, Array<RationalNumber>& Bfeatures, Array<int>& Blines, Array<RationalNumber>& Dfeatures, Array<int>& Dlines, Array<int>& tickanalysis) { int lastmeasureline = -1; int pickupstate = 0; int suppressreturn = 0; int i; Array<unsigned long> abstick; if (tickQ) { unsigned long csum = 0; abstick.setSize(tickanalysis.getSize()); abstick.setAll(0); for (i=0; i<tickanalysis.getSize(); i++) { abstick[i] = csum; csum += tickanalysis[i]; } } RationalNumber minrhy(file.getMinTimeBase(), 4); RationalNumber rat; Array<RationalNumber> Binfo; Array<RationalNumber> Dinfo; Binfo.setSize(file.getNumLines()); Binfo.allowGrowth(0); Binfo.setAll(-1); Dinfo.setSize(file.getNumLines()); Dinfo.allowGrowth(0); Dinfo.setAll(-1); int measurecount = 0; for (i=0; i<Blines.getSize(); i++) { Binfo[Blines[i]] = Bfeatures[i]; if (Binfo[Blines[i]] == file[Blines[i]].getAbsBeatR()) { Binfo[Blines[i]]++; Binfo[Blines[i]] -= file.getPickupDurationR(); } if (zeroQ) { Binfo[Blines[i]]--; } } for (i=0; i<Dlines.getSize(); i++) { Dinfo[Dlines[i]] = Dfeatures[i]; } for (i=0; i<file.getNumLines(); i++) { switch (file[i].getType()) { /*case E_humrec_data_comment: if (appendQ) { cout << file[i] << "\t" << "!" << "\n"; } else if (prependQ) { cout << "!\t" << file[i] << "\n"; } else { cout << file[i] << "\n"; } break; */ case E_humrec_data_kern_measure: if (prependQ) { cout << file[i][0] << "\t"; cout << file[i] << "\n"; } else if (appendQ) { cout << file[i] << "\t"; cout << file[i][0] << "\n"; } else { cout << file[i][0] << "\n"; } lastmeasureline = i; measurecount++; break; case E_humrec_interpretation: if (appendQ) { cout << file[i] << "\t"; } if (strncmp(file[i][0], "**", 2) == 0) { if (absQ && !tickQ) { cout << "**absb"; } else if (absQ && tickQ && !rationalQ) { cout << "**atick"; } else if (absQ && tickQ && rationalQ) { cout << "**adur"; } else if (tickQ && durQ && !rationalQ) { cout << "**dtick"; } else if (tickQ && durQ && rationalQ) { cout << "**dur"; } else if (durQ && !tickQ) { cout << "**dur"; } else { cout << "**beat"; } } else if (strcmp(file[i][0], "*-") == 0) { cout << "*-"; } else { if ((strncmp(file[i][0], "*M", 2) == 0) && (strchr(file[i][0], '/') != NULL)) { cout << file[i][0]; } else if (strncmp(file[i][0], "*MM", 3) == 0) { cout << file[i][0]; } else if (appendQ || prependQ) { cout << "*"; } else { cout << "*"; } } if (prependQ) { cout << "\t" << file[i]; } cout << "\n"; break; case E_humrec_data: if (appendQ) { cout << file[i] << "\t"; } if (file[i][0][0] == '=') { pickupstate++; } if (durQ) { // cout << file[i].getDuration(); if (Dinfo[i] >= 0) { if (tickQ && !rationalQ) { cout << tickanalysis[i]; } else if (tickQ && rationalQ) { rat.setValue(tickanalysis[i], file.getMinTimeBase()); if (uQ) { rat *= 4; } cout << rat << " = " << tickanalysis[i] << " x " << file.getMinTimeBase(); } else { cout << Dinfo[i].getFloat(); } } else { if (nullQ || appendQ || prependQ) { cout << "."; } else { suppressreturn = 1; } } } else if (absQ) { if (tickQ && !rationalQ) { cout << abstick[i]; } else if (tickQ && rationalQ) { RationalNumber anumber(abstick[i], file.getMinTimeBase()); if (uQ) { anumber *= 4; } anumber.printTwoPart(cout); } else { cout << file[i].getAbsBeat(); } } else if (sumQ) { if (lastmeasureline > 0) { cout << fabs(file[lastmeasureline].getBeat()); pickupstate++; lastmeasureline = -1; } else if (pickupstate < 1) { if (!file.getPickupDurationR().isNegative()) { if (measurecount == 0) { cout << getDurationOfFirstMeasure(file).getFloat(); } else { cout << file.getPickupDuration(); } } else if (file.getPickupDurationR().isZero()) { cout << file.getTotalDurationR().getFloat(); } else { cout << file.getTotalDurationR().getFloat(); } pickupstate++; lastmeasureline = -1; } else { if (appendQ || prependQ) { cout << "."; } else { if (nullQ) { cout << "."; } else { suppressreturn = 1; } } } } else if (beatQ) { if (Binfo[i] >= 0) { if (!tickQ && !rationalQ) { cout << Binfo[i].getFloat(); } else if (tickQ && !rationalQ) { cout << (Binfo[i] * minrhy); } else { Binfo[i].printTwoPart(cout); } } else { if (nullQ || appendQ || prependQ) { cout << "."; } else { suppressreturn = 1; } } } if (prependQ) { cout << "\t" << file[i]; } if (suppressreturn) { suppressreturn = 0; } else { cout << "\n"; } break; case E_humrec_local_comment: if (appendQ) { cout << file[i] << "\t"; } cout << "!"; if (prependQ) { cout << "\t" << file[i]; } 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; } } } ////////////////////////////// // // getDurationOfFirstMeasure -- // RationalNumber getDurationOfFirstMeasure(HumdrumFile& file) { int i; RationalNumber output(0,1); for (i=0; i<file.getNumLines(); i++) { if (file[i].getType() == E_humrec_data_measure) { break; } if (file[i].getType() != E_humrec_data) { continue; } output += file[i].getDurationR(); } return output; } ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("a|append=b"); // append analysis to input opts.define("p|prepend=b"); // prepend analysis to input opts.define("base|timebase=s:"); // rhythmic unit of one beat opts.define("b|beat=b"); // display beat of note in measure opts.define("c|abs|total-beat=b"); // cumulative, absolute beat location opts.define("d|dur|duration=b"); // display rhymic duration of records opts.define("s|sum=b"); // sum the duration of each measure opts.define("z|zero|zero-offset=b"); // first beat is represented by a 0 opts.define("n|nulls|keep-nulls=b"); // doesn't remove nulls with -s option opts.define("B=s"); // Do a composite beat search opts.define("D=s"); // Do a composite duration search opts.define("R=d:-1.0"); // Limit total duration range of search opts.define("u|beatsize=s:4"); // beat unit opts.define("A|attacks|attack=i:1"); // Minimum num of note onsets for event opts.define("t|tick=b", "display durations as tick values"); opts.define("f|rational=b", "display durations as rational values"); opts.define("tpw=b", "display only ticks per whole note"); opts.define("tpq=b", "display only ticks per quarter note"); 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, Oct 2000" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 21 April 2010" << 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); } if (options.getBoolean("zero")) { zeroQ = 1; } appendQ = opts.getBoolean("append"); prependQ = opts.getBoolean("prepend"); durQ = opts.getBoolean("duration"); absQ = opts.getBoolean("total-beat"); beatQ = opts.getBoolean("beat"); sumQ = opts.getBoolean("sum"); nullQ = opts.getBoolean("keep-nulls"); tickQ = opts.getBoolean("tick"); rationalQ = opts.getBoolean("rational"); tpwQ = opts.getBoolean("tpw"); tpqQ = opts.getBoolean("tpq"); Rvalue = opts.getDouble("R"); beatbase = opts.getString("beatsize"); uQ = opts.getBoolean("beatsize"); if (rationalQ) { tickQ = 1; } Attack = opts.getInteger("attack"); if (Attack < 0) { Attack = 0; } Bsearch.setSize(0); Dsearch.setSize(0); if (opts.getBoolean("B")) { fillSearchString(Bsearch, opts.getString("B")); } if (opts.getBoolean("D")) { fillSearchString(Dsearch, opts.getString("D")); } if (prependQ && appendQ) { prependQ = 1; appendQ = 0; } if (prependQ || appendQ) { nullQ = 1; } // display beat information if no other output option is given. if (!(absQ || durQ)) { beatQ = 1; } } ////////////////////////////// // // fillSearchString -- // void fillSearchString(Array & searcher, const char* string) { int len = strlen(string); char* tempstr; tempstr = new char[len+1]; strcpy(tempstr, string); char* ptr; ptr = strtok(tempstr, " \t\n:;,"); double value; searcher.setSize(1000); searcher.setGrowth(1000); searcher.setSize(0); while(ptr != NULL) { if (strcmp(ptr, "*") == 0) { value = -1; } else { value = atof(ptr); } searcher.append(value); ptr = strtok(NULL, " \t\n:;,"); } delete [] tempstr; } ////////////////////////////// // // example -- example usage of the quality program // void example(void) { cout << " \n" "# example usage of the meter program. \n" "# analyze a Bach chorale for meter position: \n" " meter chor217.krn \n" " \n" "# display the metrical location spine with original data: \n" " meter -a chor217.krn \n" " \n" << endl; } ////////////////////////////// // // usage -- gives the usage statement for the meter program // void usage(const char* command) { cout << " \n" "Analyzes **kern data and generates a rhythmic analysis which gives \n" "the beat location of **kern data records in the measure. Currently, \n" "input spines cannot split or join. \n" " \n" "Usage: " << command << " [-a][-b base-rhythm][-s|-d][input1 [input2 ...]]\n" " \n" "Options: \n" " -a = assemble the analysis spine with the input data. \n" " -b = set the base rhythm for analysis to specified kern rhythm value. \n" " -d = gives the duration of each kern record in beat measurements. \n" " -s = sum the beat count in each measure. \n" " --options = list of all options, aliases and default values \n" " \n" << endl; } // md5sum: 73039771851e574d20683314636364f6 beat.cpp [20100602]