// // Programmer: Craig Stuart Sapp // Creation Date: Mon Jul 18 11:23:42 PDT 2005 // Last Modified: Tue Sep 1 13:54:42 PDT 2009 (added -f, and -p options) // Last Modified: Wed Sep 2 13:26:58 PDT 2009 (added -t option) // Last Modified: Sat Sep 5 15:21:29 PDT 2009 (added sub-spine features) // Last Modified: Tue Sep 8 11:43:46 PDT 2009 (added co-spine extraction) // Filename: ...sig/examples/all/extractx.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/extractx.cpp // Syntax: C++; museinfo // // Description: C++ implementation of the Humdrum Toolkit extract command. // #include "humdrum.h" #include "PerlRegularExpression.h" #include #include #ifndef OLDCPP #include #include #else #include #include #endif // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void excludeFields (HumdrumFile& infile, Array& field, Array& subfield, Array& model); void extractFields (HumdrumFile& infile, Array& field, Array& subfield, Array& model); void extractTrace (HumdrumFile& infile, const char* tracefile); void getInterpretationFields (Array& field, Array& subfield, Array& model, HumdrumFile& infile, const char* interps, int state); //void extractInterpretations (HumdrumFile& infile, const char* interps); void example (void); void usage (const char* command); void fillFieldData (Array& field, Array& subfield, Array& model, const char* fieldstring, HumdrumFile& infile); void processFieldEntry (Array& field, Array& subfield, Array& model, const char* string, HumdrumFile& infile); void removeDollarsFromString (Array& buffer, int maxtrack); int isInList (int number, Array& listofnum); void getTraceData (Array& startline, Array >& fields, const char* tracefile, HumdrumFile& infile); void printTraceLine (HumdrumFile& infile, int line, Array& field); void dealWithSpineManipulators(HumdrumFile& infile, int line, Array& field, Array& subfield, Array& model); void storeToken (Array >& storage, const char* string); void storeToken (Array >& storage, int index, const char* string); void printMultiLines (Array& vsplit, Array& vserial, Array >& tempout); void reverseSpines (Array& field, Array& subfield, Array& model, HumdrumFile& infile, const char* exinterp); void getSearchPat (Array& spat, int target, const char* modifier); void expandSpines (Array& field, Array& subfield, Array& model, HumdrumFile& infile, const char* interp); void dealWithSecondarySubspine(Array& field, Array& subfield, Array& model, int targetindex, HumdrumFile& infile, int line, int spine, int submodel); void dealWithCospine (Array& field, Array& subfield, Array& model, int targetindex, HumdrumFile& infile, int line, int cospine, int comodel, int submodel, const char* cointerp); void printCotokenInfo (int& start, HumdrumFile& infile, int line, int spine, Array >& cotokens, Array& spineindex, Array& subspineindex); // global variables Options options; // database for command-line arguments int excludeQ = 0; // used with -x option int expandQ = 0; // used with -e option const char* expandInterp = ""; // used with -E option int interpQ = 0; // used with -i option const char* interps = ""; // used with -i option int debugQ = 0; // used with --debug option int fieldQ = 0; // used with -f or -p option const char* fieldstring = ""; // used with -f or -p option Array field; // used with -f or -p option Array subfield; // used with -f or -p option Array model; // used with -p, or -e options and similar int countQ = 0; // used with -C option int traceQ = 0; // used with -t option const char* tracefile = ""; // used with -t option int reverseQ = 0; // used with -r option const char* reverseInterp = "**kern"; // used with -r and -R options. // sub-spine "b" expansion model: how to generate data for a secondary // spine if the primary spine is not divided. Models are: // 'd': duplicate primary spine (or "a" subspine) data (default) // 'n': null = use a null token // 'r': rest = use a rest instead of a primary spine note (in **kern) // data. 'n' will be used for non-kern spines when 'r' is used. int submodel = 'd'; // used with -m option const char* editorialInterpretation = "yy"; const char* cointerp = "**kern"; // used with -c option int comodel = 0; // used with -M option const char* subtokenseparator = " "; // used with a future option int interpstate = 0; // used -I or with -i /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile, outfile; // 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& field, Array& subfield, Array& model, HumdrumFile& infile, const char* interps, int state) { Array > sstrings; // search strings sstrings.setSize(100); sstrings.setSize(0); sstrings.setGrowth(1000); int i, j, k; Array buffer; buffer.setSize(strlen(interps)+1); strcpy(buffer.getBase(), interps); PerlRegularExpression pre; pre.sar(buffer, "\\s+", "", "g"); // remove spaces from the search string. int index; while (pre.search(buffer, "^([^,]+)")) { sstrings.setSize(sstrings.getSize()+1); index = sstrings.getSize()-1; sstrings[index].setSize(strlen(pre.getSubmatch(1))+1); strcpy(sstrings[index].getBase(), pre.getSubmatch()); pre.sar(buffer, "^[^,]+,?", "", ""); } if (debugQ) { cout << "!! Interpretation strings to search for: " << endl; for (i=0; i tracks; tracks.setSize(infile.getMaxTracks()+1); tracks.setAll(0); tracks.allowGrowth(0); for (i=0; i& field, Array& subfield, Array& model, HumdrumFile& infile, const char* interp) { Array splits; splits.setSize(infile.getMaxTracks()+1); splits.allowGrowth(0); splits.setAll(0); int i, j; for (i=0; i dummyfield; Array dummysubfield; Array dummymodel; getInterpretationFields(dummyfield, dummysubfield, model, infile, interp, 1); Array interptracks; interptracks.setSize(infile.getMaxTracks()+1); interptracks.allowGrowth(0); interptracks.setAll(0); for (i=0; i& field, Array& subfield, Array& model, HumdrumFile& infile, const char* exinterp) { Array target; target.setSize(infile.getMaxTracks()+1); target.allowGrowth(0); target.setAll(0); int t; for (t=1; t<=infile.getMaxTracks(); t++) { if (strcmp(infile.getTrackExInterp(t), exinterp) == 0) { target[t] = 1; } } field.setSize(infile.getMaxTracks()*2); field.setSize(0); int i, j; int lasti = target.getSize(); for (i=target.getSize()-1; i>0; i--) { if (target[i]) { lasti = i; field.append(i); for (j=i+1; j& field, Array& subfield, Array& model, const char* fieldstring, HumdrumFile& infile) { int maxtrack = infile.getMaxTracks(); field.setSize(maxtrack); field.setGrowth(maxtrack); field.setSize(0); subfield.setSize(maxtrack); subfield.setGrowth(maxtrack); subfield.setSize(0); model.setSize(maxtrack); model.setGrowth(maxtrack); model.setSize(0); PerlRegularExpression pre; Array buffer; buffer.setSize(strlen(fieldstring)+1); strcpy(buffer.getBase(), fieldstring); pre.sar(buffer, "\\s", "", "gs"); int start = 0; int value = 0; value = pre.search(buffer.getBase(), "^([^,]+,?)"); while (value != 0) { start += value - 1; start += strlen(pre.getSubmatch(1)); processFieldEntry(field, subfield, model, pre.getSubmatch(), infile); value = pre.search(buffer.getBase() + start, "^([^,]+,?)"); } } ////////////////////////////// // // processFieldEntry -- // 3-6 expands to 3 4 5 6 // $ expands to maximum spine track // $-1 expands to maximum spine track minus 1, etc. // void processFieldEntry(Array& field, Array& subfield, Array& model, const char* string, HumdrumFile& infile) { int maxtrack = infile.getMaxTracks(); int modletter; int subletter; PerlRegularExpression pre; Array buffer; buffer.setSize(strlen(string)+1); strcpy(buffer.getBase(), string); // remove any comma left at end of input string (or anywhere else) pre.sar(buffer, ",", "", "g"); // first remove $ symbols and replace with the correct values removeDollarsFromString(buffer, infile.getMaxTracks()); int zero = 0; if (pre.search(buffer.getBase(), "^(\\d+)-(\\d+)$")) { int firstone = strtol(pre.getSubmatch(1), NULL, 10); int lastone = strtol(pre.getSubmatch(2), NULL, 10); if ((firstone < 1) && (firstone != 0)) { cerr << "Error: range token: \"" << string << "\"" << " contains too small a number at start: " << firstone << endl; cerr << "Minimum number allowed is " << 1 << endl; exit(1); } if ((lastone < 1) && (lastone != 0)) { cerr << "Error: range token: \"" << string << "\"" << " contains too small a number at end: " << lastone << endl; cerr << "Minimum number allowed is " << 1 << endl; exit(1); } if (firstone > maxtrack) { cerr << "Error: range token: \"" << string << "\"" << " contains number too large at start: " << firstone << endl; cerr << "Maximum number allowed is " << maxtrack << endl; exit(1); } if (lastone > maxtrack) { cerr << "Error: range token: \"" << string << "\"" << " contains number too large at end: " << lastone << endl; cerr << "Maximum number allowed is " << maxtrack << endl; exit(1); } int i; if (firstone > lastone) { for (i=firstone; i>=lastone; i--) { field.append(i); subfield.append(zero); model.append(zero); } } else { for (i=firstone; i<=lastone; i++) { field.append(i); subfield.append(zero); model.append(zero); } } } else if (pre.search(buffer.getBase(), "^(\\d+)([a-z]*)")) { int value = strtol(pre.getSubmatch(1), NULL, 10); modletter = 0; subletter = 0; if (strchr(pre.getSubmatch(2), 'a') != NULL) { subletter = 'a'; } if (strchr(pre.getSubmatch(), 'b') != NULL) { subletter = 'b'; } if (strchr(pre.getSubmatch(), 'c') != NULL) { subletter = 'c'; } if (strchr(pre.getSubmatch(), 'd') != NULL) { modletter = 'd'; } if (strchr(pre.getSubmatch(), 'n') != NULL) { modletter = 'n'; } if (strchr(pre.getSubmatch(), 'r') != NULL) { modletter = 'r'; } if ((value < 1) && (value != 0)) { cerr << "Error: range token: \"" << string << "\"" << " contains too small a number at end: " << value << endl; cerr << "Minimum number allowed is " << 1 << endl; exit(1); } if (value > maxtrack) { cerr << "Error: range token: \"" << string << "\"" << " contains number too large at start: " << value << endl; cerr << "Maximum number allowed is " << maxtrack << endl; exit(1); } field.append(value); if (value == 0) { subfield.append(zero); model.append(zero); } else { subfield.append(subletter); model.append(modletter); } } } ////////////////////////////// // // removeDollarsFromString -- substitute $ sign for maximum track count. // void removeDollarsFromString(Array& buffer, int maxtrack) { PerlRegularExpression pre; char buf2[128] = {0}; int value2; if (pre.search(buffer.getBase(), "\\$$")) { sprintf(buf2, "%d", maxtrack); pre.sar(buffer, "\\$$", buf2); } if (pre.search(buffer.getBase(), "\\$(?![\\d-])")) { // don't know how this case could happen, however... sprintf(buf2, "%d", maxtrack); pre.sar(buffer, "\\$(?![\\d-])", buf2, "g"); } if (pre.search(buffer.getBase(), "\\$0")) { // replace $0 with maxtrack (used for reverse orderings) sprintf(buf2, "%d", maxtrack); pre.sar(buffer, "\\$0", buf2, "g"); } while (pre.search(buffer.getBase(), "\\$(-?\\d+)")) { value2 = maxtrack - (int)fabs(strtol(pre.getSubmatch(1), NULL, 10)); sprintf(buf2, "%d", value2); pre.sar(buffer, "\\$-?\\d+", buf2); } } ////////////////////////////// // // excludeFields -- print all spines except the ones in the list of fields. // void excludeFields(HumdrumFile& infile, Array& field, Array& subfield, Array& model) { int i; int j; int start = 0; for (i=0; i& field, Array& subfield, Array& model) { PerlRegularExpression pre; int i; int j; int t; int start = 0; int target; int subtarget; int modeltarget; Array spat; for (i=0; i& field, Array& subfield, Array& model, int targetindex, HumdrumFile& infile, int line, int cospine, int comodel, int submodel, const char* cointerp) { Array > cotokens; cotokens.setSize(50); cotokens.setSize(0); cotokens.setGrowth(200); char buffer[1024]; int i, j, k; int index; if (infile[line].isInterpretation()) { cout << infile[line][cospine]; return; } if (infile[line].isMeasure()) { cout << infile[line][cospine]; return; } if (infile[line].isLocalComment()) { cout << infile[line][cospine]; return; } int count = infile[line].getTokenCount(cospine); for (k=0; k spineindex; Array subspineindex; spineindex.setSize(infile.getMaxTracks()*2); subspineindex.setSize(infile.getMaxTracks()*2); spineindex.setSize(0); subspineindex.setSize(0); spineindex.setGrowth(1000); subspineindex.setGrowth(1000); for (j=0; j buff; int start = 0; for (i=0; i >& cotokens, Array& spineindex, Array& subspineindex) { int i; int found = 0; for (i=0; i& field, Array& subfield, Array& model, int targetindex, HumdrumFile& infile, int line, int spine, int submodel) { int& i = line; int& j = spine; PerlRegularExpression pre; Array buffer; switch (infile[line].getType()) { case E_humrec_data_comment: if ((submodel == 'n') || (submodel == 'r')) { cout << "!"; } else { cout << infile[i][j]; } break; case E_humrec_data_kern_measure: cout << infile[i][j]; break; case E_humrec_interpretation: if ((submodel == 'n') || (submodel == 'r')) { cout << "*"; } else { cout << infile[i][j]; } break; case E_humrec_data: if (submodel == 'n') { cout << "."; } else if (submodel == 'r') { if (strcmp(infile[i][j], ".") == 0) { cout << "."; } else if (strchr(infile[i][j], 'q') != NULL) { cout << "."; } else if (strchr(infile[i][j], 'Q') != NULL) { cout << "."; } else { buffer.setSize(strlen(infile[i][j])+1); strcpy(buffer.getBase(), infile[i][j]); if (pre.search(buffer, "{")) { cout << "{"; } pre.sar(buffer, "[^}pPqQ0-9.;]", "", "g"); pre.search(buffer, "([0-9]+)", ""); cout << pre.getSubmatch(1); pre.search(buffer, "(\\.*)", ""); cout << pre.getSubmatch(1); if (strstr(infile[i][j], "rr") != NULL) { cout << "rr"; } else { cout << "r"; } cout << editorialInterpretation; pre.sar(buffer, "[0-9.]", "", "g"); cout << buffer.getBase(); } } else { cout << infile[i][j]; } break; default: cerr << "Should not get to this line of code" << endl; exit(1); } } ////////////////////////////// // // getSearchPat -- // void getSearchPat(Array& spat, int target, const char* modifier) { if (strlen(modifier) > 20) { cerr << "Error in GetSearchPat" << endl; exit(1); } spat.setSize(32); strcpy(spat.getBase(), "\\("); char buffer[32] = {0}; sprintf(buffer, "%d", target); strcat(spat.getBase(), buffer); strcat(spat.getBase(), "\\)"); strcat(spat.getBase(), modifier); spat.setSize(strlen(spat.getBase())+1); } ////////////////////////////// // // dealWithSpineManipulators -- check for proper Humdrum syntax of // spine manipulators (**, *-, *x, *v, *^) when creating the output. // void dealWithSpineManipulators(HumdrumFile& infile, int line, Array& field, Array& subfield, Array& model) { Array vmanip; // counter for *v records on line vmanip.setSize(infile[line].getFieldCount()); vmanip.allowGrowth(0); vmanip.setAll(0); Array xmanip; // counter for *x record on line xmanip.setSize(infile[line].getFieldCount()); xmanip.allowGrowth(0); xmanip.setAll(0); int i = 0; int j; for (j=0; j fieldoccur; // nth occurance of an input spine in the output fieldoccur.setSize(field.getSize()); fieldoccur.allowGrowth(0); fieldoccur.setAll(0); Array trackcounter; // counter of input spines occurances in output trackcounter.setSize(infile.getMaxTracks()+1); trackcounter.allowGrowth(0); trackcounter.setAll(0); for (i=0; i > tempout; Array vserial; Array xserial; Array fpos; // input column of output spine tempout.setSize(1000); tempout.setGrowth(1000); tempout.setSize(0); vserial.setSize(1000); vserial.setGrowth(1000); vserial.setSize(0); xserial.setSize(1000); xserial.setGrowth(1000); xserial.setSize(0); fpos.setSize(1000); fpos.setGrowth(1000); fpos.setSize(0); Array spat; Array spinepat; PerlRegularExpression pre; int subtarget; int modeltarget; int xdebug = 0; int vdebug = 0; int suppress = 0; int t; int target; int tval; for (t=0; t 1) { // check the last item in the list int index = xserial.getSize()-1; if (strcmp(tempout[index].getBase(), "*x") == 0) { if (xserial[index] != xserial[index-1]) { xserial[index] = 0; tempout[index].setSize(tempout[index].getSize()-1); strcpy(tempout[index].getBase(), "*"); } } } // check for proper *v syntax ///////////////////////////////// Array vsplit; vsplit.setSize(vserial.getSize()); vsplit.allowGrowth(0); vsplit.setAll(0); // identify necessary line splits for (i=0; i 1) { if (vserial[i+1]) { vsplit[i+1] = 1; } } } } // remove single *v spines: for (i=0; i 0) { if (vsplit[vsplit.getSize()-1]) { if (strcmp(tempout[tempout.getSize()-1].getBase(), "*v") == 0) { tempout[tempout.getSize()-1].setSize(2); strcpy(tempout[tempout.getSize()-1].getBase(), "*"); vsplit[vsplit.getSize()-1] = 0; } } } int vcount = 0; for (i=0; i& vsplit, Array& vserial, Array >& tempout) { int i; int splitpoint = -1; for (i=0; i >& storage, const char* string) { storage.setSize(storage.getSize()+1); int index = storage.getSize()-1; storeToken(storage, index, string); } void storeToken(Array >& storage, int index, const char* string) { storage[index].setSize(strlen(string)+1); strcpy(storage[index].getBase(), string); } ////////////////////////////// // // isInList -- returns true if first number found in list of numbers. // returns the matching index plus one. // int isInList(int number, Array& listofnum) { int i; for (i=0; i& startline, Array >& fields, const char* tracefile, HumdrumFile& infile) { char buffer[1024] = {0}; PerlRegularExpression pre; int linenum; startline.setSize(10000); startline.setGrowth(10000); startline.setSize(0); fields.setSize(10000); fields.setGrowth(10000); fields.setSize(0); ifstream input; input.open(tracefile); if (!input.is_open()) { cerr << "Error: cannot open file for reading: " << tracefile << endl; exit(1); } Array temps; Array field; Array subfield; Array model; input.getline(buffer, 1024); while (!input.eof()) { if (pre.search(buffer, "^\\s*$")) { continue; } if (!pre.search(buffer, "(\\d+)")) { continue; } linenum = strtol(pre.getSubmatch(1), NULL, 10); linenum--; // adjust so that line 0 is the first line in the file temps.setSize(strlen(buffer)+1); strcpy(temps.getBase(), buffer); pre.sar(temps, "\\d+", "", ""); pre.sar(temps, "[^,\\s\\d\\$\\-].*", ""); // remove any possible comments pre.sar(temps, "\\s", "", "g"); if (pre.search(temps.getBase(), "^\\s*$")) { // no field data to process online continue; } startline.append(linenum); fillFieldData(field, subfield, model, temps.getBase(), infile); fields.append(field); input.getline(buffer, 1024); } } ////////////////////////////// // // extractTrace -- // void extractTrace(HumdrumFile& infile, const char* tracefile) { Array startline; Array > fields; getTraceData(startline, fields, tracefile, infile); int i, j; if (debugQ) { for (i=0; i& field) { int j; int t; int start = 0; int target; start = 0; for (t=0; t buffer; buffer.setSize(1024); buffer.setSize(1); strcpy(buffer.getBase(), ""); for (i=0; i