// // Programmer: Craig Stuart Sapp // Creation Date: Thu Jun 14 12:18:18 PDT 2012 // Last Modified: Fri Jun 15 16:31:09 PDT 2012 // Filename: ...sig/examples/all/prettystar.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/prettystar.cpp // Syntax: C++; museinfo // // Description: Extract all spines from a multi-spine file into // single-column output. // #include "humdrum.h" #include "SigString.h" #include "PerlRegularExpression.h" using namespace std; #define TYPE_USED (-100) /* bookkeeping */ #define TYPE_UNKNOWN (-1) /* cannot categorize */ // EXAMPLES: #define TYPE_EMPTY (0) /* * */ #define TYPE_STAFF (1) /* *staff4 */ #define TYPE_SYSSTAFF (2) /* *staff:4 */ #define TYPE_TRANSP (3) /* *ITrd-4c-7 */ #define TYPE_ICLASS (4) /* *ICvox */ #define TYPE_IGROUP (5) /* *IGstrings */ #define TYPE_ITYPE (6) /* *Ivox */ #define TYPE_INAME (7) /* *I"Flute */ #define TYPE_IABBR (8) /* *I'Fl */ #define TYPE_INUM (9) /* *I#2 */ #define TYPE_EXPAND (10) /* *>[A,A,B] */ #define TYPE_EXPANDVAR (11) /* *>norep[A,A,B] */ #define TYPE_OCLEF (12) /* *oclefG2 */ #define TYPE_CLEF (13) /* *clefF4 */ #define TYPE_KEYSIG (14) /* *k[f#] */ #define TYPE_KEY (15) /* *B-:dor */ #define TYPE_TIMESIG (16) /* *M4/4 */ #define TYPE_METSIG (17) /* *met(c|) */ #define TYPE_TEMPO (18) /* *MM120 */ #define TYPE_RSCALE (19) /* *rscale:1/2 */ #define TYPE_TACET (20) /* *xtacet */ #define TYPE_HAND (21) /* *rh, *lh */ #define TYPE_TIMEBASE (22) /* *tb16 */ #define TYPE_EXPANDLABEL (23) /* *>A */ #define TYPE_MAX (23) #define NAME_UNKNOWN "unknown" /* cannot categorize */ #define NAME_EMPTY "empty" /* * */ #define NAME_STAFF "staff" /* *staff4 */ #define NAME_SYSSTAFF "sysstaff" /* *staff:4 */ #define NAME_TRANSP "transp" /* *ITrd-4c-7 */ #define NAME_ICLASS "iclass" /* *ICvox */ #define NAME_IGROUP "igroup" /* *IGstrings */ #define NAME_ITYPE "itype" /* *Ivox */ #define NAME_INAME "iname" /* *I"Flut */ #define NAME_IABBR "iabbr" /* *I'Fl */ #define NAME_INUM "inum" /* *I#2 */ #define NAME_OCLEF "oclef" /* *oclefG2 */ #define NAME_CLEF "clef" /* *clefF4 */ #define NAME_KEYSIG "keysig" /* *k[f#] */ #define NAME_KEY "key" /* *B-:dor */ #define NAME_TIMESIG "timesig" /* *M4/4 */ #define NAME_METSIG "metsig" /* *met(c|) */ #define NAME_TEMPO "tempo" /* *MM120 */ #define NAME_RSCALE "rscale" /* *rscale:1/2 */ #define NAME_TACET "tacet" /* *tacet */ #define NAME_HAND "hand" /* *rh, *lh */ #define NAME_TIMEBASE "timebase" /* *tb16 */ #define NAME_EXPAND "exp" /* *>[A,A,B] */ #define NAME_EXPANDVAR "expvar" /* *>norep[A,A,B] */ #define NAME_EXPANDLABEL "expmark" /* *>A */ // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void example (void); void usage (const string& command); void printBlocks (HumdrumFile& infile); void sortAllBlocks (HumdrumFile& infile); int validline (HumdrumFile& infile, int i); int getInterpretationCount(HumdrumFile& infile, int line); char* getInterpName (char* buffer, HumdrumRecord& line, int index); int getInterpNum (HumdrumRecord& line, int index); void printUnknownInterpretations(HumdrumFile& infile); void getBlockList (HumdrumFile& infile, vector& starti, vector& endi, int initQ); void printSortedInterpretations(HumdrumFile& infile, int starti, int endi, int blockcount); int nameToNumber (const string& name); const char* numberToName (int number); void processInterpretationType(int target, HumdrumFile& infile, int starti, vector >& types, int blockcount); void printInterpretationType(int target, HumdrumFile& infile, int starti, vector >& types, int blockcount); int hasType (int target, vector >& types, int blocktype); void printUnknownLines (HumdrumFile& infile, int starti, vector >& types); void checkForWarnings (HumdrumFile& infile, int starti, int endi, vector >& types); int checkForMixedInterpretations(vector& types); void seachForInterpretation (HumdrumFile& infile, const string& SearchString); void seachListForInterpretation(HumdrumFile& infile, const string& SearchString); // block parsing functions: void fillFieldData (vector& field, const string& fieldstring, HumdrumFile& infile); void processFieldEntry (vector& field, const string& string, HumdrumFile& infile, int maxblock); void removeDollarsFromString(string& buffer, int maxblock); // global variables Options options; // database for command-line arguments int listblocksQ = 0; // used with -l option int listunknownQ = 0; // used with -u option int typeQ = 0; // used with -t option int keysigQ = 0; // used with -k option int filenameQ = 0; // used with -f option int searchQ = 0; // used with -s option string SearchString = ""; // used with -s option string FILENAME = ""; // used with -f option int unknownlastQ = 0; // used with --last option int warnQ = 0; // used with -w option int blockQ = 0; // used with -b option vector BlockProcess; // used with -b option string BlockString = ""; // used with -b option int debugQ = 0; // used with --debug option vector FirstSort; // used with -F option string FirstString = "1"; // used with -F option int searchlistQ = 0; // used with -L option string ListString = ""; // used with -L option /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile; // 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[A,A,B] */ // #define NAME_EXPANDVAR "expvar" /* *>norep[A,A,B] */ // #define NAME_EXPANDLABEL "explevel" /* *>A */ // char* getInterpName(char* b, HumdrumRecord& line, int index) { if (strcmp(line[index], "*") == 0) { strcpy(b, NAME_EMPTY); return b; } if (line.isClef(index)) { strcpy(b, NAME_CLEF); return b; } if (line.isOriginalClef(index)) { strcpy(b, NAME_OCLEF); return b; } if (line.isKey(index)) { strcpy(b, NAME_KEY); return b; } if (line.isKeySig(index)) { strcpy(b, NAME_KEYSIG); return b; } if (line.isTempo(index)) { strcpy(b, NAME_TEMPO); return b; } if (line.isTimeSig(index)) { strcpy(b, NAME_TIMESIG); return b; } if (line.isMetSig(index)) { strcpy(b, NAME_METSIG); return b; } if (line.isTranspose(index)) { strcpy(b, NAME_TRANSP); return b; } if (line.isInstrumentType(index)) { strcpy(b, NAME_ITYPE); return b; } if (line.isInstrumentClass(index)) { strcpy(b, NAME_ICLASS); return b; } if (line.isInstrumentName(index)) { strcpy(b, NAME_INAME); return b; } if (line.isInstrumentAbbr(index)) { strcpy(b, NAME_IABBR); return b; } if (line.isInstrumentNum(index)) { strcpy(b, NAME_INUM); return b; } if (line.isLabelExpansion(index)) { strcpy(b, NAME_EXPAND); return b; } if (line.isLabelVariant(index)) { strcpy(b, NAME_EXPANDVAR); return b; } if (line.isLabelMarker(index)) { strcpy(b, NAME_EXPANDLABEL); return b; } if (line.isStaffNumber(index)) { strcpy(b, NAME_STAFF); return b; } if (line.isSysStaffNumber(index)) { strcpy(b, NAME_SYSSTAFF); return b; } PerlRegularExpression pre; if (pre.search(line[index], "^\\*x?tacet$")) { strcpy(b, NAME_TACET); return b; } if (pre.search(line[index], "^\\*[lr]h$", "i")) { strcpy(b, NAME_HAND); return b; } if (pre.search(line[index], "^\\*tb\\d", "")) { strcpy(b, NAME_TIMEBASE); return b; } if (pre.search(line[index], "^\\*IG", "")) { strcpy(b, NAME_IGROUP); return b; } if (pre.search(line[index], "^\\*x?rscale:\\d+/?\\d*$")) { strcpy(b, NAME_RSCALE); return b; } strcpy(b, NAME_UNKNOWN); return b; } ////////////////////////////// // // getInterpNum -- // int getInterpNum(HumdrumRecord& line, int index) { if (strcmp(line[index], "*") == 0) { return TYPE_EMPTY; } if (line.isClef(index)) { return TYPE_CLEF; } if (line.isOriginalClef(index)) { return TYPE_OCLEF; } if (line.isKey(index)) { return TYPE_KEY; } if (line.isKeySig(index)) { return TYPE_KEYSIG; } if (line.isTempo(index)) { return TYPE_TEMPO; } if (line.isTimeSig(index)) { return TYPE_TIMESIG; } if (line.isMetSig(index)) { return TYPE_METSIG; } if (line.isTranspose(index)) { return TYPE_TRANSP; } if (line.isInstrumentType(index)) { return TYPE_ITYPE; } if (line.isInstrumentClass(index)) { return TYPE_ICLASS; } if (line.isInstrumentName(index)) { return TYPE_INAME; } if (line.isInstrumentAbbr(index)) { return TYPE_IABBR; } if (line.isInstrumentNum(index)) { return TYPE_INUM; } if (line.isLabelExpansion(index)) { return TYPE_EXPAND; } if (line.isLabelVariant(index)) { return TYPE_EXPANDVAR; } if (line.isLabelMarker(index)) { return TYPE_EXPANDLABEL; } if (line.isStaffNumber(index)) { return TYPE_STAFF; } if (line.isSysStaffNumber(index)) { return TYPE_SYSSTAFF; } PerlRegularExpression pre; if (pre.search(line[index], "^\\*x?tacet$")) { return TYPE_TACET; } if (pre.search(line[index], "^\\*[lr]h$", "i")) { return TYPE_HAND; } if (pre.search(line[index], "^\\*tb\\d", "")) { return TYPE_TIMEBASE; } if (pre.search(line[index], "^\\*IG", "")) { return TYPE_IGROUP; } if (pre.search(line[index], "^\\*x?rscale:\\d+/?\\d*$")) { return TYPE_RSCALE; } return TYPE_UNKNOWN; } ////////////////////////////// // // numberToName -- // const char* numberToName(int number) { switch (number) { case TYPE_EMPTY: return NAME_EMPTY; case TYPE_STAFF: return NAME_STAFF; case TYPE_SYSSTAFF: return NAME_SYSSTAFF; case TYPE_TRANSP: return NAME_TRANSP; case TYPE_ICLASS: return NAME_ICLASS; case TYPE_IGROUP: return NAME_IGROUP; case TYPE_ITYPE: return NAME_ITYPE; case TYPE_INAME: return NAME_INAME; case TYPE_IABBR: return NAME_IABBR; case TYPE_INUM: return NAME_INUM; case TYPE_EXPAND: return NAME_EXPAND; case TYPE_EXPANDVAR: return NAME_EXPANDVAR; case TYPE_OCLEF: return NAME_OCLEF; case TYPE_CLEF: return NAME_CLEF; case TYPE_KEYSIG: return NAME_KEYSIG; case TYPE_KEY: return NAME_KEY; case TYPE_TIMESIG: return NAME_TIMESIG; case TYPE_METSIG: return NAME_METSIG; case TYPE_TEMPO: return NAME_TEMPO; case TYPE_RSCALE: return NAME_RSCALE; case TYPE_TACET: return NAME_TACET; case TYPE_HAND: return NAME_HAND; case TYPE_TIMEBASE: return NAME_TIMEBASE; case TYPE_EXPANDLABEL: return NAME_EXPANDLABEL; } return NAME_UNKNOWN; } ////////////////////////////// // // searchForInterpretation -- // void seachForInterpretation(HumdrumFile& infile, const string& SearchString) { vector starti; vector endi; getBlockList(infile, starti, endi, 0); int i, j; int testval; int b; int target; int count = 0; PerlRegularExpression pre; if (pre.search(SearchString, "^/")) { string searchstring = SearchString; pre.sar(searchstring, "^/", ""); pre.sar(searchstring, "/$", ""); for (b=0; b<(int)starti.size(); b++) { if (starti[b] < 0) { continue; } for (i=starti[b]; i<=endi[b]; i++) { for (j=0; j 0) { cout << endl; } } ////////////////////////////// // // searchListForInterpretation -- // void seachListForInterpretation(HumdrumFile& infile, const string& SearchString) { vector starti; vector endi; getBlockList(infile, starti, endi, 0); int i, j; int testval; int b; int target; PerlRegularExpression pre; if (pre.search(SearchString, "^/")) { string searchstring = SearchString; pre.sar(searchstring, "^/", ""); pre.sar(searchstring, "/$", ""); for (b=0; b<(int)starti.size(); b++) { if (starti[b] < 0) { continue; } for (i=starti[b]; i<=endi[b]; i++) { for (j=0; j unknowns; char buffer[1024] = {0}; for (int i=0; i unknowns; int count; int starti; int endi; int blockcount = 0; for (int i=0; i > types; int rows = endi - starti + 1; int cols = infile[starti].getFieldCount(); if (cols != infile[endi].getFieldCount()) { cerr << "Funny error" << endl; exit(1); } types.resize(rows); for (int i=0; i<(int)types.size(); i++) { types[i].resize(cols); for (int j=0; j<(int)types[i].size(); j++) { types[i][j] = getInterpNum(infile[starti+i], j); } } if (warnQ) { checkForWarnings(infile, starti, endi, types); return; } vector sortOrder; sortOrder.reserve(TYPE_MAX*2); int value; if (FirstSort[blockcount] == 0) { // force expandlabel to be sorted on top of block // if the block is not a first-type. value = TYPE_EXPANDLABEL; sortOrder.push_back(value); } // Add other interpretations for (int i=0; i >& types) { int i, j; int mixed = 0; static string LASTFILENAME = "XAEASDGASGAEG"; for (i=0; i<(int)types.size(); i++) { mixed = checkForMixedInterpretations(types[i]); if (mixed) { if (filenameQ && (LASTFILENAME != FILENAME)) { cout << FILENAME << "\t=================" << "\n"; LASTFILENAME = FILENAME; } cout << "!!WARNING: mixed interpretation types on line " << starti+i+1 << "\n"; cout << infile[starti+i] << "\n"; } for (j=0; j<(int)types[i].size(); j++) { if (types[i][j] == TYPE_UNKNOWN) { if (filenameQ && (LASTFILENAME != FILENAME)) { cout << FILENAME << "\t=================" << "\n"; LASTFILENAME = FILENAME; } cout << "!!UNKNOWN interpretation on line " << starti+i+1 << ":\t" << infile[starti+i][j] << "\n"; } } } } ////////////////////////////// // // checkForMixedInterpretations -- // int checkForMixedInterpretations(vector& types) { double found = 123456; int i; for (i=0; i<(int)types.size(); i++) { if (types[i] == TYPE_USED) { // shouldn't happen, but just in case continue; } if (types[i] == TYPE_EMPTY) { continue; } if (found == 123456) { found = types[i]; continue; } if (found != types[i]) { return 1; } } return 0; } ////////////////////////////// // // printUnknownLines -- // void printUnknownLines(HumdrumFile& infile, int starti, vector >& types) { // first print all lines which consist only of // unknowns, used, or empty interpretations. int i, j; int hasunknown; for (i=0; i<(int)types.size(); i++) { hasunknown = 0; for (j=0; j<(int)types[i].size(); j++) { if (types[i][j] == TYPE_UNKNOWN) { hasunknown = 1; break; } } if (hasunknown) { for (j=0; j<(int)types[i].size(); j++) { if (types[i][j] == TYPE_UNKNOWN) { cout << infile[starti+i][j]; } else { cout << "*"; } if (j<(int)types[i].size()-1) { cout << "\t"; } } cout << "\n"; } } } ////////////////////////////// // // processInterpretationType -- // void processInterpretationType(int target, HumdrumFile& infile, int starti, vector >& types, int blockcount) { int hastype = hasType(target, types, blockcount); while (hastype) { printInterpretationType(target, infile, starti, types, blockcount); if (target == TYPE_KEYSIG) { blockcount++; // prevent recursive auto keysig printing } hastype = hasType(target, types, blockcount); if ((hastype > 1) && blockcount) { hastype = 0; } } } ////////////////////////////// // // hasType -- // int hasType(int target, vector >& types, int blockcount) { int i, j; if ((blockcount == 0) && keysigQ && (target == TYPE_KEYSIG)) { return 2; } for (i=0; i<(int)types.size(); i++) { for (j=0; j<(int)types[i].size(); j++) { if (types[i][j] == target) { return 1; } } } return 0; } ////////////////////////////// // // printInterpretationType -- // void printInterpretationType(int target, HumdrumFile& infile, int starti, vector >& types, int blockcount) { int i, j; int found; for (j=0; j<(int)types[0].size(); j++) { found = -1; for (i=0; i<(int)types.size(); i++) { if (target == types[i][j]) { found = i; types[i][j] = TYPE_USED; break; } } if (found >= 0) { cout << infile[starti+found][j]; } else { if (keysigQ && (blockcount == 0) && (target == TYPE_KEYSIG)) { cout << "*k[]"; } else { cout << "*"; } } if (j<(int)types[0].size()-1) { cout << "\t"; } } cout << "\n"; } ////////////////////////////// // // getInterpretationCount -- // int getInterpretationCount(HumdrumFile& infile, int line) { int i; int count = 0; for (i=line; i& starti, vector& endi, int initQ) { starti.reserve(10000); starti.resize(0); endi.reserve(10000); endi.resize(0); int minusone = -1; int i; int count; int blockcount = 0; for (i=0; i& field, const string& fieldstring, HumdrumFile& infile) { vector starti; vector endi; getBlockList(infile, starti, endi, 1); int maxblock = (int)starti.size(); if (debugQ) { cout << "BLOCK COUNT = " << maxblock << endl; } field.resize(maxblock); std::fill(field.begin(), field.end(), 0); vector tempfield; tempfield.reserve(maxblock); PerlRegularExpression pre; string buffer = fieldstring; pre.sar(buffer, "\\s", "", "gs"); int start = 0; int value = 0; value = pre.search(buffer, "^([^,]+,?)"); while (value != 0) { start += value - 1; start += strlen(pre.getSubmatch(1)); processFieldEntry(tempfield, pre.getSubmatch(), infile, maxblock); value = pre.search(buffer.c_str() + start, "^([^,]+,?)"); } int i; for (i=0; i<(int)tempfield.size(); i++) { field[tempfield[i]-1] = 1; } } ////////////////////////////// // // processFieldEntry -- // 3-6 expands to 3 4 5 6 // $ expands to maximum block number // $-1 expands to maximum spine track minus 1, etc. // void processFieldEntry(vector& field, const string& astring, HumdrumFile& infile, int maxblock) { PerlRegularExpression pre; string buffer = astring; // remove any comma left at end of input string (or anywhere else) pre.sar(buffer, ",", "", "g"); if (debugQ) { cout << "MAXBLOCK = " << maxblock << endl; cout << "INPUT BLOCK STRING TO DOLLAR: " << buffer << endl; } // first remove $ symbols and replace with the correct values removeDollarsFromString(buffer, maxblock); if (debugQ) { cout << "OUTPUT BLOCK STRING FROM DOLLAR: " << buffer << endl; } if (pre.search(buffer, "^(\\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: \"" << astring << "\"" << " 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: \"" << astring << "\"" << " contains too small a number at end: " << lastone << endl; cerr << "Minimum number allowed is " << 1 << endl; exit(1); } if (firstone > maxblock) { cerr << "Error: range token: \"" << astring << "\"" << " contains number too large at start: " << firstone << endl; cerr << "Maximum number allowed is " << maxblock << endl; exit(1); } if (lastone > maxblock) { cerr << "Error: range token: \"" << astring << "\"" << " contains number too large at end: " << lastone << endl; cerr << "Maximum number allowed is " << maxblock << endl; exit(1); } int i; if (firstone > lastone) { for (i=firstone; i>=lastone; i--) { field.push_back(i); } } else { for (i=firstone; i<=lastone; i++) { field.push_back(i); } } } else if (pre.search(buffer, "^(\\d+)")) { int value = strtol(pre.getSubmatch(1), NULL, 10); if ((value < 1) && (value != 0)) { cerr << "Error: range token: \"" << astring << "\"" << " contains too small a number at end: " << value << endl; cerr << "Minimum number allowed is " << 1 << endl; exit(1); } if (value > maxblock) { cerr << "Error: range token: \"" << astring << "\"" << " contains number too large at start: " << value << endl; cerr << "Maximum number allowed is " << maxblock << endl; exit(1); } field.push_back(value); } } ////////////////////////////// // // removeDollarsFromString -- substitute $ sign for maximum track count. // void removeDollarsFromString(string& buffer, int maxblock) { PerlRegularExpression pre; char buf2[128] = {0}; int value2; if (debugQ) { cout << "IN DOLLAR STRING MAXBLOCK = " << maxblock << endl; } if (pre.search(buffer, "\\$$")) { sprintf(buf2, "%d", maxblock); pre.sar(buffer, "\\$$", buf2); } if (debugQ) { cout << "IN DOLLAR STRING = " << buffer << endl; } if (pre.search(buffer, "\\$(?![\\d-])")) { // don't know how this case could happen, however... sprintf(buf2, "%d", maxblock); pre.sar(buffer, "\\$(?![\\d-])", buf2, "g"); } if (pre.search(buffer, "\\$0")) { // replace $0 with maxblock (used for reverse orderings) sprintf(buf2, "%d", maxblock); pre.sar(buffer, "\\$0", buf2, "g"); } while (pre.search(buffer, "\\$(-?\\d+)")) { value2 = maxblock - (int)fabs(strtol(pre.getSubmatch(1), NULL, 10)); sprintf(buf2, "%d", value2); pre.sar(buffer, "\\$-?\\d+", buf2); } } // // Spine field list extraction functions // ///////////////////////////////////////////////////////////////////////////