//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// 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"
#ifndef OLDCPP
using namespace std;
#endif
#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 char* 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, Array<int>& starti,
Array<int>& endi, int initQ);
void printSortedInterpretations(HumdrumFile& infile, int starti, int endi,
int blockcount);
int nameToNumber(const char* name);
const char* numberToName(int number);
void processInterpretationType(int target, HumdrumFile& infile,
int starti, Array<Array<int> >& types,
int blockcount);
void printInterpretationType(int target, HumdrumFile& infile, int starti,
Array<Array<int> >& types, int blockcount);
int hasType(int target, Array<Array<int> >& types,
int blocktype);
void printUnknownLines(HumdrumFile& infile, int starti,
Array<Array<int> >& types);
void checkForWarnings(HumdrumFile& infile, int starti, int endi,
Array<Array<int> >& types);
int checkForMixedInterpretations(Array<int>& types);
void seachForInterpretation(HumdrumFile& infile,
const char* SearchString);
void seachListForInterpretation(HumdrumFile& infile,
const char* SearchString);
// block parsing functions:
void fillFieldData(Array<int>& field, const char* fieldstring,
HumdrumFile& infile);
void processFieldEntry(Array<int>& field, const char* string,
HumdrumFile& infile, int maxblock);
void removeDollarsFromString(Array<char>& 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
const char* SearchString = ""; // used with -s option
const char* 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
Array<int> BlockProcess; // used with -b option
const char* BlockString = ""; // used with -b option
int debugQ = 0; // used with --debug option
Array<int> FirstSort; // used with -F option
const char* FirstString = "1"; // used with -F option
int searchlistQ = 0; // used with -L option
const char* 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<numinputs || i==0; i++) {
infile.clear();
// if no command-line arguments read data file from standard input
if (numinputs < 1) {
infile.read(cin);
FILENAME = "<STDIN>";
} else {
FILENAME = options.getArg(i+1);
infile.read(FILENAME);
}
fillFieldData(BlockProcess, BlockString, infile);
fillFieldData(FirstSort, FirstString, infile);
if (debugQ) {
int i;
cout << "!! BLOCK INFORMATION: ";
for (i=0; i<BlockProcess.getSize(); i++) {
cout << BlockProcess[i] << " ";
}
cout << endl;
cout << "!! FIRST INFORMATION: ";
for (i=0; i<FirstSort.getSize(); i++) {
cout << FirstSort[i] << " ";
}
cout << endl;
}
if (listblocksQ) {
printBlocks(infile);
} else if (listunknownQ) {
if (filenameQ) {
cout << FILENAME << "\n";
}
printUnknownInterpretations(infile);
} else if (searchQ) {
if (filenameQ) {
cout << FILENAME << "\n";
}
seachForInterpretation(infile, SearchString);
} else if (searchlistQ) {
if (filenameQ) {
cout << FILENAME << "\n";
}
seachListForInterpretation(infile, ListString);
} else {
sortAllBlocks(infile);
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// printSearchList --
//
void printSearchList(void) {
int i;
for (i=1; i<=TYPE_MAX; i++) {
cout << numberToName(i) << "\n";
}
}
//////////////////////////////
//
// getInterpType --
// #define NAME_UNKNOWN "unknown" /* cannot categorize */
// #define NAME_EMPTY "empty" /* * */
// #define NAME_STAFF "staff" /* *staff4 */
// #define NAME_STAFFC "sysstaff" /* *staff:4 */
// #define NAME_OCLEF "oclef" /* *oclefG2 */
// #define NAME_CLEF "clef" /* *clefF4 */
// #define NAME_KEY "key" /* *B-:dor */
// #define NAME_KEYSIG "keysig" /* *k[f#] */
// #define NAME_TIMESIG "timesig" /* *M4/4 */
// #define NAME_METSIG "metsig" /* *met(c|) */
// #define NAME_TEMPO "tempo" /* *MM120 */
// #define NAME_TRANSP "transpose" /* *ITrd-4c-7 */
// #define NAME_ITYPE "instrument" /* *Ivox */
// #define NAME_ICLASS "iclass" /* *ICvox */
// #define NAME_INUM "inum" /* *I#2 */
// #define NAME_INAME "iname" /* *I"Flut */
// #define NAME_IABBR "iabbr" /* *I'Fl */
// #define NAME_EXPAND "exp" /* *>[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 char* SearchString) {
Array<int> starti;
Array<int> endi;
getBlockList(infile, starti, endi, 0);
int i, j;
int testval;
int b;
int target;
int count = 0;
PerlRegularExpression pre;
if (pre.search(SearchString, "^/")) {
Array<char> searchstring;
searchstring.setSize(strlen(SearchString)+1);
strcpy(searchstring.getBase(), SearchString);
pre.sar(searchstring, "^/", "");
pre.sar(searchstring, "/$", "");
for (b=0; b<starti.getSize(); b++) {
if (starti[b] < 0) {
continue;
}
for (i=starti[b]; i<=endi[b]; i++) {
for (j=0; j<infile[i].getFieldCount(); j++) {
if (pre.search(infile[i][j], searchstring.getBase())) {
if (count++ != 0) {
cout << ",";
}
cout << b+1;
break;
}
}
}
}
} else {
target = nameToNumber(SearchString);
for (b=0; b<starti.getSize(); b++) {
if (starti[b] < 0) {
continue;
}
for (i=starti[b]; i<=endi[b]; i++) {
for (j=0; j<infile[i].getFieldCount(); j++) {
testval = getInterpNum(infile[i], j);
if (testval == target) {
if (count++ != 0) {
cout << ",";
}
cout << b+1;
break;
}
}
}
}
}
if (count > 0) {
cout << endl;
}
}
//////////////////////////////
//
// searchListForInterpretation --
//
void seachListForInterpretation(HumdrumFile& infile, const char* SearchString) {
Array<int> starti;
Array<int> endi;
getBlockList(infile, starti, endi, 0);
int i, j;
int testval;
int b;
int target;
PerlRegularExpression pre;
if (pre.search(SearchString, "^/")) {
Array<char> searchstring;
searchstring.setSize(strlen(SearchString)+1);
strcpy(searchstring.getBase(), SearchString);
pre.sar(searchstring, "^/", "");
pre.sar(searchstring, "/$", "");
for (b=0; b<starti.getSize(); b++) {
if (starti[b] < 0) {
continue;
}
for (i=starti[b]; i<=endi[b]; i++) {
for (j=0; j<infile[i].getFieldCount(); j++) {
if (pre.search(infile[i][j], searchstring.getBase())) {
cout << infile[i][j] << "\n";
}
}
}
}
} else {
target = nameToNumber(SearchString);
for (b=0; b<starti.getSize(); b++) {
if (starti[b] < 0) {
continue;
}
for (i=starti[b]; i<=endi[b]; i++) {
for (j=0; j<infile[i].getFieldCount(); j++) {
testval = getInterpNum(infile[i], j);
if (testval == target) {
cout << infile[i][j] << "\n";
}
}
}
}
}
}
//////////////////////////////
//
// nameToNumber --
//
int nameToNumber(const char* name) {
if (strcmp(NAME_UNKNOWN, name) == 0) { return TYPE_UNKNOWN; }
if (strcmp(NAME_EMPTY, name) == 0) { return TYPE_EMPTY; }
if (strcmp(NAME_STAFF, name) == 0) { return TYPE_STAFF; }
if (strcmp(NAME_SYSSTAFF, name) == 0) { return TYPE_SYSSTAFF; }
if (strcmp(NAME_TRANSP, name) == 0) { return TYPE_TRANSP; }
if (strcmp(NAME_ICLASS, name) == 0) { return TYPE_ICLASS; }
if (strcmp(NAME_ITYPE, name) == 0) { return TYPE_ITYPE; }
if (strcmp(NAME_INAME, name) == 0) { return TYPE_INAME; }
if (strcmp(NAME_IABBR, name) == 0) { return TYPE_IABBR; }
if (strcmp(NAME_INUM, name) == 0) { return TYPE_INUM; }
if (strcmp(NAME_OCLEF, name) == 0) { return TYPE_OCLEF; }
if (strcmp(NAME_CLEF, name) == 0) { return TYPE_CLEF; }
if (strcmp(NAME_KEY, name) == 0) { return TYPE_KEY; }
if (strcmp(NAME_KEYSIG, name) == 0) { return TYPE_KEYSIG; }
if (strcmp(NAME_TIMESIG, name) == 0) { return TYPE_TIMESIG; }
if (strcmp(NAME_METSIG, name) == 0) { return TYPE_METSIG; }
if (strcmp(NAME_TEMPO, name) == 0) { return TYPE_TEMPO; }
if (strcmp(NAME_EXPAND, name) == 0) { return TYPE_EXPAND; }
if (strcmp(NAME_EXPANDVAR, name) == 0) { return TYPE_EXPANDVAR; }
if (strcmp(NAME_EXPANDLABEL, name) == 0) { return TYPE_EXPANDLABEL; }
if (strcmp(NAME_TACET, name) == 0) { return TYPE_TACET; }
if (strcmp(NAME_HAND, name) == 0) { return TYPE_HAND; }
if (strcmp(NAME_TIMEBASE, name) == 0) { return TYPE_TIMEBASE; }
if (strcmp(NAME_IGROUP, name) == 0) { return TYPE_IGROUP; }
if (strcmp(NAME_RSCALE, name) == 0) { return TYPE_RSCALE; }
return TYPE_UNKNOWN;
}
//////////////////////////////
//
// printUnknownInterpretations --
//
void printUnknownInterpretations(HumdrumFile& infile) {
Array<SigString> unknowns;
unknowns.setSize(0);
char buffer[1024] = {0};
int i, j;
for (i=0; i<infile.getNumLines(); i++) {
if (!validline(infile, i)) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
if (keysigQ && (!infile[i].isExInterp(j, "**kern"))) {
continue;
}
getInterpName(buffer, infile[i], j);
if (strcmp(buffer, "unknown") != 0) {
continue;
}
cout << infile[i][j] << endl;
}
}
}
//////////////////////////////
//
// sortAllBlocks --
//
void sortAllBlocks(HumdrumFile& infile) {
Array<SigString> unknowns;
unknowns.setSize(0);
int i, j;
int count;
int starti;
int endi;
int blockcount = 0;
for (i=0; i<infile.getNumLines(); i++) {
if (!validline(infile, i)) {
if (!warnQ) {
cout << infile[i] << "\n";
}
continue;
}
starti = i;
count = getInterpretationCount(infile, i);
if (BlockProcess[blockcount] == 0) {
// this block is not supposed to be altered
for (j=0; j<count; j++) {
cout << infile[i+j] << "\n";
}
i += count - 1;
blockcount++;
continue;
}
i += count - 1;
endi = i;
printSortedInterpretations(infile, starti, endi, blockcount++);
}
}
//////////////////////////////
//
// printSortedInterpretations --
//
void printSortedInterpretations(HumdrumFile& infile, int starti, int endi,
int blockcount) {
Array<Array<int> > types;
int rows = endi - starti + 1;
int cols = infile[starti].getFieldCount();
if (cols != infile[endi].getFieldCount()) {
cerr << "Funny error" << endl;
exit(1);
}
types.setSize(rows);
types.allowGrowth(0);
int i, j;
for (i=0; i<types.getSize(); i++) {
types[i].setSize(cols);
types[i].allowGrowth(0);
for (j=0; j<types[i].getSize(); j++) {
types[i][j] = getInterpNum(infile[starti+i], j);
}
}
if (warnQ) {
checkForWarnings(infile, starti, endi, types);
return;
}
Array<int> sortOrder;
sortOrder.setSize(TYPE_MAX*2);
sortOrder.setSize(0);
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.append(value);
}
// Add other interpretations
for (i=0; i<TYPE_MAX; i++) {
value = i+1;
if ((FirstSort[blockcount] == 0) && (value == TYPE_EXPANDLABEL)) {
// do nothing
} else {
sortOrder.append(value);
}
}
sortOrder.allowGrowth(0);
if (FirstSort[blockcount] == 0) {
processInterpretationType(TYPE_EXPANDLABEL, infile, starti, types,
!FirstSort[blockcount]);
}
if (!unknownlastQ) {
printUnknownLines(infile, starti, types);
}
for (i=0; i<sortOrder.getSize(); i++) {
processInterpretationType(sortOrder[i], infile, starti, types,
!FirstSort[blockcount]);
}
if (unknownlastQ) {
printUnknownLines(infile, starti, types);
}
}
//////////////////////////////
//
// checkForWarnings --
//
void checkForWarnings(HumdrumFile& infile, int starti, int endi,
Array<Array<int> >& types) {
int i, j;
int mixed = 0;
static const char* LASTFILENAME = "XAEASDGASGAEG";
for (i=0; i<types.getSize(); i++) {
mixed = checkForMixedInterpretations(types[i]);
if (mixed) {
if (filenameQ && (strcmp(LASTFILENAME, FILENAME) != 0)) {
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<types[i].getSize(); j++) {
if (types[i][j] == TYPE_UNKNOWN) {
if (filenameQ && (strcmp(LASTFILENAME, FILENAME) != 0)) {
cout << FILENAME << "\t=================" << "\n";
LASTFILENAME = FILENAME;
}
cout << "!!UNKNOWN interpretation on line " << starti+i+1 << ":\t"
<< infile[starti+i][j] << "\n";
}
}
}
}
//////////////////////////////
//
// checkForMixedInterpretations --
//
int checkForMixedInterpretations(Array& types) {
double found = 123456;
int i;
for (i=0; i<types.getSize(); 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,
Array<Array<int> >& types) {
// first print all lines which consist only of
// unknowns, used, or empty interpretations.
int i, j;
int hasunknown;
for (i=0; i<types.getSize(); i++) {
hasunknown = 0;
for (j=0; j<types[i].getSize(); j++) {
if (types[i][j] == TYPE_UNKNOWN) {
hasunknown = 1;
break;
}
}
if (hasunknown) {
for (j=0; j<types[i].getSize(); j++) {
if (types[i][j] == TYPE_UNKNOWN) {
cout << infile[starti+i][j];
} else {
cout << "*";
}
if (j<types[i].getSize()-1) {
cout << "\t";
}
}
cout << "\n";
}
}
}
//////////////////////////////
//
// processInterpretationType --
//
void processInterpretationType(int target, HumdrumFile& infile,
int starti, Array<Array<int> >& 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, Array >& types, int blockcount) {
int i, j;
if ((blockcount == 0) && keysigQ && (target == TYPE_KEYSIG)) {
return 2;
}
for (i=0; i<types.getSize(); i++) {
for (j=0; j<types[i].getSize(); j++) {
if (types[i][j] == target) {
return 1;
}
}
}
return 0;
}
//////////////////////////////
//
// printInterpretationType --
//
void printInterpretationType(int target, HumdrumFile& infile, int starti,
Array<Array<int> >& types, int blockcount) {
int i, j;
int found;
for (j=0; j<types[0].getSize(); j++) {
found = -1;
for (i=0; i<types.getSize(); 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<types[0].getSize()-1) {
cout << "\t";
}
}
cout << "\n";
}
//////////////////////////////
//
// getInterpretationCount --
//
int getInterpretationCount(HumdrumFile& infile, int line) {
int i;
int count = 0;
for (i=line; i<infile.getNumLines(); i++) {
if (validline(infile, i)) {
count++;
} else {
break;
}
}
return count;
}
//////////////////////////////
//
// getBlockList --
//
void getBlockList(HumdrumFile& infile, Array<int>& starti, Array<int>& endi,
int initQ) {
starti.setSize(10000);
starti.setGrowth(100000);
starti.setSize(0);
endi.setSize(10000);
endi.setGrowth(100000);
endi.setSize(0);
int minusone = -1;
int i;
int count;
int blockcount = 0;
for (i=0; i<infile.getNumLines(); i++) {
if (!validline(infile, i)) {
continue;
}
if (!initQ) {
if (BlockProcess[blockcount] == 0) {
// ignore this interpretation block
count = getInterpretationCount(infile, i);
i += count - 1;
blockcount++;
starti.append(minusone);
endi.append(minusone);
continue;
}
}
starti.append(i);
count = getInterpretationCount(infile, i);
i += count - 1;
endi.append(i);
blockcount++;
}
}
//////////////////////////////
//
// printBlocks --
//
void printBlocks(HumdrumFile& infile) {
int i, j;
int k;
int count;
int blocknum = 0;
char buffer[1024] = {0};
for (i=0; i<infile.getNumLines(); i++) {
if (!validline(infile, i)) {
continue;
}
count = getInterpretationCount(infile, i);
if (BlockProcess[blocknum] == 0) {
i += count - 1;
blocknum++;
continue;
}
blocknum++;
cout << "!!Blocknum=" << blocknum
<< "\tstart=" << i+1
<< "\tend=" << i+count
<< endl;
for (j=i; j<i+count; j++) {
cout << infile[j] << endl;
if (typeQ) {
for (k=0; k<infile[j].getFieldCount(); k++) {
cout << "!" << getInterpName(buffer, infile[j], k);
if (k < infile[j].getFieldCount()-1) {
cout << "\t";
}
}
cout << "\n";
}
}
i += count - 1;
}
}
//////////////////////////////
//
// validline -- true if an interpretation line with no exclusive
// interpretations and no spine manipulators.
//
int validline(HumdrumFile& infile, int i) {
if (!infile[i].isInterpretation()) {
return 0;
}
if (strncmp(infile[i][0], "**", 2) == 0) {
return 0;
}
if (infile[i].isSpineManipulator()) {
// *^ *v *+ *x ** interpreations are not allowed
// to mix with tandem interpreatations
if (warnQ) {
int j;
for (j=0; j<infile[i].getFieldCount(); j++) {
if (strcmp(infile[i][j], "*") == 0) {
continue;
}
if (strcmp(infile[i][j], "*v") == 0) {
continue;
}
if (strcmp(infile[i][j], "*^") == 0) {
continue;
}
if (strcmp(infile[i][j], "*x") == 0) {
continue;
}
if (strcmp(infile[i][j], "*+") == 0) {
continue;
}
if (strcmp(infile[i][j], "*-") == 0) {
continue;
}
if (strncmp(infile[i][j], "**", 2) == 0) {
continue;
}
cout << "!!ERROR: mixing tandem and spine "
<< "manipulator interpretations on line " << i+1 << ":\n";
cout << infile[i] << "\n";
break;
}
}
return 0;
}
return 1;
}
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("t|type=b", "Display the interpretation type");
opts.define("l|list=b", "Display a list of the interpretation blocks");
opts.define("u|unknown=b", "Display a list unknown interpretations");
opts.define("last=b", "Place unknown interpreations last");
opts.define("k|keysig=b", "Add key signatures if not present");
opts.define("f|filename=b", "Print filename (used with -u)");
opts.define("w|warn=b", "Warning about mismatched or unknown interps");
opts.define("b|block=s:1-$","Process only specified blocks");
opts.define("s|search=s:", "Search for a partcular interpretation");
opts.define("S|search-list=b","Display search list");
opts.define("F|first=s:1", "Treat the block list as sorting by first");
opts.define("L|list-search=s", "List interpretations of a particular type");
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, June 2012" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: June 2012" << 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 (opts.getBoolean("search-list")) {
printSearchList();
exit(0);
}
blockQ = opts.getBoolean("block");
BlockString = opts.getString("block");
typeQ = opts.getBoolean("type");
listblocksQ = opts.getBoolean("list");
listunknownQ = opts.getBoolean("unknown");
keysigQ = opts.getBoolean("keysig");
filenameQ = opts.getBoolean("filename");
unknownlastQ = opts.getBoolean("last");
warnQ = opts.getBoolean("warn");
debugQ = opts.getBoolean("debug");
searchQ = opts.getBoolean("search");
SearchString = opts.getString("search");
FirstString = opts.getString("first");
searchlistQ = opts.getBoolean("list-search");
ListString = opts.getString("list-search");
}
//////////////////////////////
//
// example -- example usage of the quality program
//
void example(void) {
cout <<
" \n"
" \n"
<< endl;
}
//////////////////////////////
//
// usage -- gives the usage statement for the meter program
//
void usage(const char* command) {
cout <<
" \n"
" \n"
<< endl;
}
///////////////////////////////////////////////////////////////////////////
//
// Spine field list extraction functions
//
//////////////////////////////
//
// fillFieldData --
//
void fillFieldData(Array<int>& field, const char* fieldstring,
HumdrumFile& infile) {
Array<int> starti;
Array<int> endi;
getBlockList(infile, starti, endi, 1);
int maxblock = starti.getSize();
if (debugQ) {
cout << "BLOCK COUNT = " << maxblock << endl;
}
field.setSize(maxblock);
field.setGrowth(0);
field.setAll(0);
Array<int> tempfield;
tempfield.setSize(maxblock);
tempfield.setSize(0);
PerlRegularExpression pre;
Array<char> 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(tempfield, pre.getSubmatch(), infile, maxblock);
value = pre.search(buffer.getBase() + start, "^([^,]+,?)");
}
int i;
for (i=0; i<tempfield.getSize(); 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(Array<int>& field, const char* string,
HumdrumFile& infile, int maxblock) {
PerlRegularExpression pre;
Array<char> 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");
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.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 > maxblock) {
cerr << "Error: range token: \"" << string << "\""
<< " contains number too large at start: " << firstone << endl;
cerr << "Maximum number allowed is " << maxblock << endl;
exit(1);
}
if (lastone > maxblock) {
cerr << "Error: range token: \"" << string << "\""
<< " 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.append(i);
}
} else {
for (i=firstone; i<=lastone; i++) {
field.append(i);
}
}
} else if (pre.search(buffer.getBase(), "^(\\d+)")) {
int value = strtol(pre.getSubmatch(1), NULL, 10);
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 > maxblock) {
cerr << "Error: range token: \"" << string << "\""
<< " contains number too large at start: " << value << endl;
cerr << "Maximum number allowed is " << maxblock << endl;
exit(1);
}
field.append(value);
}
}
//////////////////////////////
//
// removeDollarsFromString -- substitute $ sign for maximum track count.
//
void removeDollarsFromString(Array& buffer, int maxblock) {
PerlRegularExpression pre;
char buf2[128] = {0};
int value2;
if (debugQ) {
cout << "IN DOLLAR STRING MAXBLOCK = " << maxblock << endl;
}
if (pre.search(buffer.getBase(), "\\$$")) {
sprintf(buf2, "%d", maxblock);
pre.sar(buffer, "\\$$", buf2);
}
if (debugQ) {
cout << "IN DOLLAR STRING = " << buffer << endl;
}
if (pre.search(buffer.getBase(), "\\$(?![\\d-])")) {
// don't know how this case could happen, however...
sprintf(buf2, "%d", maxblock);
pre.sar(buffer, "\\$(?![\\d-])", buf2, "g");
}
if (pre.search(buffer.getBase(), "\\$0")) {
// replace $0 with maxblock (used for reverse orderings)
sprintf(buf2, "%d", maxblock);
pre.sar(buffer, "\\$0", buf2, "g");
}
while (pre.search(buffer.getBase(), "\\$(-?\\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
//
///////////////////////////////////////////////////////////////////////////
// md5sum: 0e713a16488534ca9d497bf76e394a27 prettystar.cpp [20120615]