// // Programmer: Craig Stuart Sapp // 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 #include #include #ifndef OLDCPP #include #define SSTREAM stringstream #define CSTRING str().c_str() using namespace std; #else #ifdef VISUAL #include /* for windows 95 */ #else #include #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& Bfeatures, Array& Blines, Array& Dfeatures, Array& Dlines, Array& tickanalysis); RationalNumber getPickupDuration (HumdrumFile& file); void fillSearchString (Array& searcher, const char* string); void printSearchResults (HumdrumFile& infile, Array& Bfeatures, Array& Blines, Array& Dfeatures, Array& Dlines); void printSearchResultsFinal(Array& linematch, HumdrumFile& infile, Array& Bfeatures, Array& Blines, Array& Dfeatures, Array& Dloines); void doBeatSearch (Array& results, HumdrumFile& infile, Array search, Array& Bfeatures, Array& Blines); void doDurSearch (Array& results, HumdrumFile& infile, Array search, Array& Dfeatures, Array& Dlines); void doDurSearch (Array& results, HumdrumFile& infile, Array search, Array& Dfeatures, Array& Dlines); void mergeResults (Array& output, Array& input1, Array& input2); void printSequence (Array& pattern); void printSequence (Array& pattern); void fillMeasureInfo (HumdrumFile& infile, Array& measures); void doComparison (Array& results, Array& line, Array& search, Array& data, HumdrumFile& infile); int checkForWildcard (Array& sequence); void extractBeatFeatures(HumdrumFile& infile, Array& line, Array& data); void extractDurFeatures (HumdrumFile& infile, Array& line, Array& data); void printSequence (Array& features, Array& lines, Array& search, int startline); void printSequence (Array& features, Array& lines, Array& search, int startline); void printSequence (Array& features, Array& lines, Array& search, int startline); void printMatchesWithData(Array& linematch, HumdrumFile& infile); void fillAttackArray (HumdrumFile& infile, Array& attacks); int getCountForLine (HumdrumFile& infile, int line); int doTickAnalysis (Array& 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 Bsearch; // used with -B option Array 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 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 Bfeatures; // used to extract beat data from input Array Dfeatures; // used to extract duration data from input Array Blines; // used to extract beat data from input Array 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 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 pretick(tickanalysis.getSize()); int minrhy = infile.getMinTimeBase(); if (minrhy <= 0.0) { return 1; } RationalNumber value; int monitor = 0; for (i=0; i& 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& Bfeatures, Array& Blines, Array& Dfeatures, Array& Dlines) { Array Bresults; Array 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 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) { int i; for (i=0; i& sequence) { int i; for (i=0; i& linematch, HumdrumFile& infile) { int i; int counter = 1; Array lookup; lookup.setSize(infile.getNumLines()); lookup.allowGrowth(0); lookup.setAll(-1); for (i=0; i& linematch, HumdrumFile& infile, Array& Bfeatures, Array& Blines, Array& Dfeatures, Array& Dlines) { cout << "!!matches: " << linematch.getSize() << "\n"; if (appendQ || prependQ) { printMatchesWithData(linematch, infile); return; } Array 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& features, Array& lines, Array& search, int startline) { int index = -1; int i; for (i=0; i& features, Array& lines, Array& search, int startline) { int index = -1; int i; for (i=0; i& features, Array& lines, Array& search, int startline) { int index = -1; int i; for (i=0; i& features, Array& lines, Array& search, int startline) { int index = -1; int i; for (i=0; i& features, Array& lines, Array& search, int startline) { int index = -1; int i; for (i=0; i& measures) { int i; measures.setSize(infile.getNumLines()); measures.allowGrowth(0); measures.setAll(0.0); double current = 0.0; for (i=0; i& 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= 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& results, HumdrumFile& infile, Array search, Array& Bfeatures, Array& Blines) { // extractBeatFeatures(infile, Blines, Bfeatures); Array doubleBfeatures; doubleBfeatures.setSize(Bfeatures.getSize()); int i; for (i=0; i& line, Array& 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& line, Array& 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 0) { data[data.getSize()-1] += bval; } continue; } line.append(lval); data.append(bval); } } ////////////////////////////// // // doComparison -- // void doComparison(Array& results, Array& line, Array& search, Array& 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 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& results, HumdrumFile& infile, Array search, Array& Dfeatures, Array& Dlines) { // extractDurFeatures(infile, Dlines, Dfeatures); doComparison(results, Dlines, search, Dfeatures, infile); } void doDurSearch(Array& results, HumdrumFile& infile, Array search, Array& Dfeatures, Array& Dlines) { int i; Array doubleDfeatures(Dfeatures.getSize()); for (i=0; i& Bfeatures, Array& Blines, Array& Dfeatures, Array& Dlines, Array& tickanalysis) { int lastmeasureline = -1; int pickupstate = 0; int suppressreturn = 0; int i; Array abstick; if (tickQ) { unsigned long csum = 0; abstick.setSize(tickanalysis.getSize()); abstick.setAll(0); for (i=0; i Binfo; Array 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& 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]