// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Thu Sep 9 21:30:46 PDT 2004 // Last Modified: Thu Sep 9 21:30:48 PDT 2004 // Filename: ...sig/examples/all/barnum.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/barnum.cpp // Syntax: C++; museinfo // // Description: Number, renumber or remove measure numbers from Humdrum files. // #include "humdrum.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 processFile(HumdrumFile& file); void removeBarNumbers(HumdrumFile& infile); void printWithoutBarNumbers(HumdrumRecord& humrecord); void printWithBarNumbers(HumdrumRecord& humrecord, int measurenum); void printSingleBarNumber(const char* string, int measurenum); // global variables Options options; // database for command-line arguments int removeQ = 0; // used with -r option int startnum = 1; // used with -s option int allQ = 0; // used with -a option int debugQ = 0; // used with --debug option /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile, outfile; // process the command-line options checkOptions(options, argc, argv); // if no command-line arguments read data file from standard input int numinputs = options.getArgCount(); if (numinputs < 1) { infile.read(cin); } else { infile.read(options.getArg(1)); } if (removeQ) { removeBarNumbers(infile); } else{ processFile(infile); } return 0; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////// // // removeBarNumbers -- You guessed it. // void removeBarNumbers(HumdrumFile& infile) { int i; for (i=0; i<infile.getNumLines(); i++) { if (infile[i].getType() != E_humrec_data_measure) { cout << infile[i] << "\n"; continue; } printWithoutBarNumbers(infile[i]); } } ////////////////////////////// // // printWithoutBarNumbers -- // void printWithoutBarNumbers(HumdrumRecord& humrecord) { int i; int j; int length; for (i=0; i<humrecord.getFieldCount(); i++) { if (humrecord[i][0] != '=') { cout << humrecord[i]; } else { length = strlen(humrecord[i]); for (j=0; j<length; j++) { if (!isdigit(humrecord[i][j])) { cout << humrecord[i][j]; } } } if (i < humrecord.getFieldCount()-1) { cout << "\t"; } } cout << "\n"; } ////////////////////////////// // // processFile -- // void processFile(HumdrumFile& infile) { infile.analyzeRhythm("4"); Array<int> measureline; // line number in the file where measure occur Array<double> measurebeats; // duration of measure Array<double> timesigbeats; // duration according to timesignature Array<int> control; // control = numbered measure Array<int> measurenums; // output measure numbers measureline.setSize(infile.getNumLines()); measureline.setSize(0); measurebeats.setSize(infile.getNumLines()); measurebeats.setSize(0); timesigbeats.setSize(infile.getNumLines()); timesigbeats.setSize(0); int i; double timesigdur = 0.0; double timetop = 4; double timebot = 1; double value = 1; double lastvalue = 1; for (i=0; i<infile.getNumLines(); i++) { if (debugQ) { cout << "LINE " << i+1 << "\t" << infile[i] << endl; } if (infile[i].getType() == E_humrec_interpretation) { if ((strncmp(infile[i][0], "*M", 2) == 0) && (strchr(infile[i][0], '/') != NULL)) { timetop = Convert::kernTimeSignatureTop(infile[i][0]); timebot = Convert::kernTimeSignatureBottomToDuration(infile[i][0]); timesigdur = timetop * timebot; // fix last timesigbeats value if (timesigbeats.getSize() > 0) { timesigbeats[timesigbeats.getSize()-1] = timesigdur; measurebeats[measurebeats.getSize()-1] = lastvalue * timebot; } } } else if (infile[i].getType() == E_humrec_data_measure) { measureline.append(i); lastvalue = infile[i].getBeat(); // shouldn't use timebot (now analyzing rhythm by "4") // value = lastvalue * timebot; value = lastvalue; measurebeats.append(value); timesigbeats.append(timesigdur); } } if (measurebeats.getSize() == 0) { // no barlines, nothing to do... cout << infile; return; } // Identify controlling/non-controlling barlines // at each measure line determine one of three cases: // // (1) all ok -- the summation of durations in the measure // matches the current time sign // (2) a partial measure -- the measure durations do not // add up to the time signature, but the measure is // at the start/end of a musical section such as the // beginning of a piece, end of a piece, or between // repeat bar dividing a full measure. // (3) the sum of the durations does not match the // time signature because the durations are incorrectly // given. // control.setSize(measureline.getSize()); measurenums.setSize(measureline.getSize()); control.setAll(-1); measurenums.setAll(-1); // if the time signature and the number of beats in a measure // agree, then the bar is worth numbering: for (i=0; i<control.getSize(); i++) { if (measurebeats[i] == timesigbeats[i]) { control[i] = 1; } } // determine first bar (which is marked with a negative value) // if there is a pickup bar if (measurebeats[0] < 0) { if (-measurebeats[0] == timesigbeats[0]) { control[0] = 1; } } // Check for intermediate barlines which split one measure for (i=control.getSize()-2; i>=0; i--) { if ((control[i] == 1) || (control[i+1] == 1)) { continue; } if (timesigbeats[i] != timesigbeats[i+1]) { continue; } if ((measurebeats[i]+measurebeats[i+1]) == timesigbeats[i]) { control[i] = 1; control[i+1] = 0; } } // if two (or more) non-controlling bars occur in a row, then // make them controlling: for (i=0; i<control.getSize()-1; i++) { if ((control[i] < 1) && (control[i+1] < 1)) { while ((i < control.getSize()) && (control[i] < 1)) { control[i++] = 1; } } } // if a measure contains no beats, then it is not a controlling barline for (i=0; i<control.getSize(); i++) { if (measurebeats[i] == 0) { control[i] = 0; } } // if the first bar is not a pickup measure, but there is no // starting measure, then subtract one from the starting barline // count; int offset = 0; int dataq = 0; for (i=0; i<infile.getNumLines(); i++) { if (infile[i].isData()) { dataq = 1; continue; } if (infile[i].getType() == E_humrec_data_measure) { if ((measurebeats[0] > 0) && dataq) { offset = 1; } break; } } if (allQ) { control.setAll(1); offset = 0; } // assign the measure numbers; int mnum = startnum + offset; for (i=0; i<measurenums.getSize(); i++) { if (control[i] == 1) { measurenums[i] = mnum++; } } if (debugQ) { cout << "cont\tnum\tbeats" << endl; for (i=0; i<control.getSize(); i++) { cout << control[i] << "\t" << measurenums[i] << "\t" << measurebeats[i] << "\t" << timesigbeats[i] << endl; } } // ready to print the new barline numbers int mindex = 0; for (i=0; i<infile.getNumLines(); i++) { if (infile[i].getType() != E_humrec_data_measure) { cout << infile[i] << "\n"; continue; } if (measurenums[mindex] < 0) { printWithoutBarNumbers(infile[i]); } else { printWithBarNumbers(infile[i], measurenums[mindex]); } mindex++; } } ////////////////////////////// // // printWithBarNumbers -- // void printWithBarNumbers(HumdrumRecord& humrecord, int measurenum) { int i; for (i=0; i<humrecord.getFieldCount(); i++) { printSingleBarNumber(humrecord[i], measurenum); if (i < humrecord.getFieldCount() -1) { cout << "\t"; } } cout << "\n"; } ////////////////////////////// // // printSingleBarNumber -- // void printSingleBarNumber(const char* string, int measurenum) { int length = strlen(string); int i; for (i=0; i<length; i++) { if (string[i] == '=' && string[i+1] != '=') { cout << string[i] << measurenum; } else if (!isdigit(string[i])) { cout << string[i]; } } } ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("r|remove=b", "Remove barlines from the file"); opts.define("s|start=i:1", "starting barline number"); opts.define("a|all=b", "print numbers on all barlines"); opts.define("debug=b"); // print debug info 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, Sep 2004" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: 10 Sep 2004" << 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); } removeQ = opts.getBoolean("remove"); startnum = opts.getInteger("start"); debugQ = opts.getBoolean("debug"); allQ = opts.getBoolean("all"); } ////////////////////////////// // // example -- example usage of the quality program // void example(void) { cout << " \n" << endl; } ////////////////////////////// // // usage -- gives the usage statement for the meter program // void usage(const char* command) { cout << " \n" << endl; } // md5sum: dc8a875e92aded1fc1ae7353f83977fa barnum.cpp [20050403]