// // Programmer: Craig Stuart Sapp // Creation Date: Tue Aug 30 10:51:26 PDT 2011 // Last Modified: Fri Sep 2 18:25:34 PDT 2011 // Last Modified: Tue Sep 13 13:33:52 PDT 2011 added -k option // Last Modified: Thu Sep 15 01:36:49 PDT 2011 added -D option // Last Modified: Thu Oct 20 22:23:27 PDT 2011 fixed init bug // Filename: ...sig/examples/all/notearray.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/notearray.cpp // Syntax: C++; museinfo // // Description: Generate a two-dimensional numeric array containing // notes in the score in base-40, base-12, or base-7 // representation. Each data line represents a sonority // with attacked notes in that sonority being positive // numbers, and sustained notes from previous sonorities // being negative. // #include "humdrum.h" #ifndef OLDCPP #include using namespace std; #else #include #endif #define STYLE_BASE40 40 #define STYLE_BASE12 12 #define STYLE_BASE7 7 #define TYPE_MIN 999 #define TYPE_NOTES 1000 #define TYPE_KERN 1000 #define TYPE_LINE (2000-1) /* +1 will be added later to make 2000 */ #define TYPE_MEASURE 3000 #define TYPE_BEAT 4000 #define TYPE_ABSOLUTE 5000 #define TYPE_LINEDUR 6000 #define TYPE_ATTACK 7100 #define TYPE_LAST 7200 #define TYPE_NEXT 7300 // function declarations void getNoteArray (Array >& notes, Array& measpos, Array& linenum, HumdrumFile& infile, int base, int flags); void printNoteArray (Array >& notes, Array& measpos, Array& linenum, HumdrumFile& infile); void printComments (HumdrumFile& infile, int startline, int stopline, int style); void printExclusiveInterpretations(int basecount); void printLine (Array >& notes, Array >& attacks, Array >& lasts, Array >& nexts, Array& measpos, Array& linenum, HumdrumFile& infile, int index, int style); void usage (const char* command); void example (void); void checkOptions (Options& opts, int argc, char* argv[]); void getNoteAttackIndexes (Array >& attacks, Array >& notes, int offst); void getLastAttackIndexes (Array >& lasts, Array >& notes, int offset); void getNextAttackIndexes (Array >& lasts, Array >& notes, int offset); int noteStartMarker (Array >& notes, int line, int column); int noteEndMarker (Array >& notes, int line, int column); int noteContinueMarker (Array >& notes, int line, int column); int singleNote (Array >& notes, int line, int column); // global variables Options options; // database for command-line arguments int humdrumQ = 0; // used with -H option int base7Q = 0; // used with -d option int base12Q = 0; // used with -m option int base40Q = 1; // default output type int base = STYLE_BASE40; int measureQ = 1; // used with -M option int beatQ = 1; // used with -B option int commentQ = 1; // used with -C option int rationalQ = 0; // used with -r option int fractionQ = 0; // used with -f option int absoluteQ = 0; // used with -a option int linedurQ = 0; // used with -D option int doubleQ = 0; // used with --double option int lineQ = 0; // used with -l option int mathQ = 0; // used with --mathematica option int susxQ = 1; // used with -S option int bibQ = 0; // used with -b option int infoQ = 1; // used with -I option int octadj = 0; // used with -o option int endQ = 0; // used with -e option int typeQ = 0; // used with -c option int oneQ = 0; // used with -1 option int sepQ = 0; // used with --sep option int Offset = 0; // used with -1/--offset option int OffsetSum = 0; // used for multiple input files int attackQ = 0; // used with --attack option int nextQ = 0; // used with --last option int lastQ = 0; // used with --next option int indexQ = 0; // used with -i option int saQ = 0; // used with --sa option int quoteQ = 0; // used with --quote option int Count = 0; // count of how many input files int Current = 0; // used with --math option int moQ = 0; // used with --mo option int Measure = 0; // additive value for measure number int Mincrement= 0; // used to increment between pieces/movements int kernQ = 0; // used with -k option int kerntieQ = 1; // used with --no-tie option int doubletieQ= 0; // used with -T option RationalNumber Absoffset; // used with --sa option const char* commentStart = "#"; const char* commentStop = ""; const char* mathvar = "data"; // used with --mathematica option const char* beatbase = ""; // used with -t option /////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { Array > notelist; Array metpos; Array measpos; Array linenum; HumdrumFile infile; // process the command-line options checkOptions(options, argc, argv); // figure out the number of input files to process int numinputs = options.getArgCount(); Count = numinputs; Absoffset = 0; for (int i=0; i 1) && (Current < Count - 1)) { // add a separate between input file analyses: if (mathQ) { cout << "(* ********** *)\n"; } else if (humdrumQ) { cout << "!!!!!!!!!!\n"; } else { cout << "##########\n"; } } } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // getNoteArray -- // style: // STYLE_BASE40 40: print as base-40 pitches // STYLE_BASE12 12: print as base-12 pitches // STYLE_BASE7 7: print as base-7 pitches // // flags: // 0: all off: // 1: turn on double-barline rest markers. // void getNoteArray(Array >& notes, Array& measpos, Array& linenum, HumdrumFile& infile, int style, int flags) { notes.setSize(infile.getNumLines()); notes.setSize(0); measpos.setSize(infile.getNumLines()); measpos.setSize(0); linenum.setSize(infile.getNumLines()); linenum.setSize(0); int measnum = 0; int rest = 0; int i, j, ii, jj; int negQ = 0; // prestorage for note lists so that --no-sustain option can be applied Array templist; templist.setSize(1000); templist.setSize(0); Array templistI; templistI.setSize(1000); templistI.setSize(0); int value; int firstQ = 1; if (typeQ) { // store even if lineQ is zero! value = TYPE_LINE; linenum.append(value); } if (typeQ) { value = TYPE_MEASURE; measpos.append(value); } // increment measure number in case of pickups measnum = Measure; for (i=0; i= 0) { negQ = 0; break; } } if (negQ) { continue; } } if (firstQ && typeQ) { firstQ = 0; templistI.setSize(templist.getSize()); int value = TYPE_NOTES; switch (style) { case STYLE_BASE40: value += 40; break; case STYLE_BASE12: value += 12; break; case STYLE_BASE7: value += 7; break; } templistI.setAll(value); notes.increase(); notes.last() = templistI; } notes.increase(); notes.last() = templist; measpos.append(measnum); linenum.append(i); } if (endQ) { notes.increase(); notes.last().setSize(notes.last(-1).getSize()); notes.last().zero(); // sustains instead of rests (have to copy .last(-1): // for (i=0; i 0) { // notes.last()[i] *= -1; // } // } measpos.append(measpos.last()); linenum.append(linenum.last()); // store the data termination line as the line number of the sonority for (i=infile.getNumLines()-1; i>=0; i--) { if (infile[i].isInterpretation()) { linenum.last() = i; break; } } // increment the measure number if the beat of the end // is at 1. This will work unless the last sonority is a // grace note. if (infile[linenum.last()].getBeat() == 1.0) { measpos.last()++; } } } ////////////////////////////// // // printNoteArray -- // void printNoteArray(Array >& notes, Array& measpos, Array& linenum, HumdrumFile& infile) { linenum.allowGrowth(0); measpos.allowGrowth(0); notes.allowGrowth(0); Array > attacks; Array > lasts; Array > nexts; if (attackQ) { getNoteAttackIndexes(attacks, notes, Offset + OffsetSum); } if (lastQ) { getLastAttackIndexes(lasts, notes, Offset + OffsetSum); } if (nextQ) { getNextAttackIndexes(nexts, notes, Offset + OffsetSum); } int i, j; for (i=0; i >& lasts, Array >& notes, int offset) { int start = 0; lasts.setSize(notes.getSize()); if (typeQ) { lasts[0].setAll(TYPE_LAST); start = 1; } int i, j; lasts[start].setAll(-1); if (notes.getSize() == start+1) { return; } Array states; states.setSize(notes[0].getSize()); if (typeQ) { states.setAll(offset+1); } else { states.setAll(offset); } for (i=0; i 0) { // a new note attack, store the note attack index in // the states array after recording the index of the previous note lasts[i][j] = states[j]; states[j] = i + offset; } else if (notes[i][j] < 0) { // note is sustaining, so copy the index of the last attack // from the previous line if (i > start) { lasts[i][j] = lasts[i-1][j]; } else { lasts[i][j] = -1; } } else { // rest: if last line was a rest then this is a rest sustain: if (i > start) { if (notes[i-1][j] == 0) { // rest sustain lasts[i][j] = lasts[i-1][j]; } else { // rest attack lasts[i][j] = states[j]; states[j] = i + offset; } } else { lasts[i][j] = -1; } } } } } ////////////////////////////// // // getNextAttackIndexes -- return an index of the attack portion // of notes (or the first rest in a series of rests) in each voice. // void getNextAttackIndexes(Array >& nexts, Array >& notes, int offset) { int start = 0; nexts.setSize(notes.getSize()); if (typeQ) { nexts[0].setSize(notes[0].getSize()); nexts[0].setAll(TYPE_NEXT); start = 1; } int i, j; nexts.last().setSize(notes.last().getSize()); nexts.last().setAll(-1); if (notes.getSize() == start+1) { return; } for (i=notes.getSize()-2; i>=start; i--) { nexts[i].setSize(notes[i].getSize()); for (j=0; j 0) { // a new note attack, store the note attack index in // the states array after recording the index of the previous note nexts[i][j] = i + 1 + offset; } else { nexts[i][j] = nexts[i+1][j]; } } } } ////////////////////////////// // // getNoteAttackIndexes -- return an index of the attack portion // of notes (or the first rest in a series of rests) in each voice. // void getNoteAttackIndexes(Array >& attacks, Array >& notes, int offset) { attacks.setSize(notes.getSize()); int i, j; attacks[0].setSize(notes[0].getSize()); attacks[0].setAll(offset); for (i=1; i 0) { // note being attacked, so store its index attacks[i][j] = i + offset; } else { // a rest: check to see if last position was a rest. // if so, then this is a "tied rest"; otherwise it is // a "attacked rest". if (notes[i-1][j] == 0) { attacks[i][j] = attacks[i-1][j]; } else { attacks[i][j] = i + offset; } } } } if (typeQ) { attacks[0].setAll(TYPE_ATTACK); } } ////////////////////////////// // // printLine -- print a line of the note array. // style == 0: regular line // style == 1: index line (don't extract beat or absbeat from infile) // void printLine(Array >& notes, Array >& attacks, Array >& lasts, Array >& nexts, Array& measpos, Array& linenum, HumdrumFile& infile, int index, int style) { int& i = index; int j; if (mathQ) { cout << "{"; } if (indexQ) { cout << i + Offset + OffsetSum; } if (lineQ) { if (indexQ) { if (mathQ) { cout << ","; } cout << "\t"; } cout << linenum[i]+1; } if (measureQ) { if (indexQ || lineQ) { if (mathQ) { cout << ","; } cout << "\t"; } cout << measpos[i]; } if (beatQ) { if (indexQ || lineQ || measureQ) { if (mathQ) { cout << ","; } cout << "\t"; } if (style == 1) { cout << TYPE_BEAT; } else if (rationalQ) { if (fractionQ) { cout << infile[linenum[i]].getBeatR(); } else { infile[linenum[i]].getBeatR().printTwoPart(cout); } } else { // print beat position as a floating-point number: cout << infile[linenum[i]].getBeat(); } } if (absoluteQ) { if (indexQ || lineQ || measureQ || beatQ) { if (mathQ) { cout << ","; } cout << "\t"; } if (style == 1) { cout << TYPE_ABSOLUTE; } else if (rationalQ) { if (fractionQ) { cout << (Absoffset + infile[linenum[i]].getAbsBeatR()); } else { RationalNumber sum = Absoffset + infile[linenum[i]].getAbsBeatR(); sum.printTwoPart(cout); } } else { // print beat position as a floating-point number: cout << infile[linenum[i]].getAbsBeat() + Absoffset.getFloat(); } } if (linedurQ) { if (indexQ || lineQ || measureQ || beatQ || absoluteQ) { if (mathQ) { cout << ","; } cout << "\t"; } if (style == 1) { cout << TYPE_LINEDUR; } else if (rationalQ) { if (fractionQ) { cout << (Absoffset + infile[linenum[i]].getDurationR()); } else { RationalNumber num = infile[linenum[i]].getDurationR(); num.printTwoPart(cout); } } else { // print beat position as a floating-point number: cout << infile[linenum[i]].getDuration(); } } if (indexQ || lineQ || measureQ || beatQ || absoluteQ || linedurQ) { if (mathQ) { cout << ","; } } Array values; values.setSize(notes.getSize() * 10); values.setSize(0); int vv; int sign; for (j=0; j >& notes, int line, int column) { int start = 0; if (typeQ) { start = 1; } if (line < start) { return 0; } int pitch = notes[line][column]; int nextpitch = -1; int lastpitch = -1; if ((line > start) && (notes.getSize() > 1+start)) { lastpitch = notes[line-1][column]; } if ((notes.getSize() > start+1) && (line < notes.getSize() - 1)) { nextpitch = notes[line+1][column]; } if (pitch > TYPE_MIN) { return 0; } if (pitch < 0) { // note is a sustain, so not considered return 0; } else if (pitch == 0) { // if the rest is surrounded by non-rests, then mark if ((pitch != lastpitch) && (pitch != nextpitch)) { return 1; } else { return 0; } } else { if (pitch != -nextpitch) { // next sonority does not contain a sustain of the note return 1; } else { return 0; } } } ////////////////////////////// // // noteStartMarker -- // int noteStartMarker(Array >& notes, int line, int column) { int start = 0; if (typeQ) { start = 1; } if (line < start) { return 0; } int pitch = notes[line][column]; int nextpitch = -1; int lastpitch = -1; if ((line > start) && (notes.getSize() > 1+start)) { lastpitch = notes[line-1][column]; } if ((notes.getSize() > start+1) && (line < notes.getSize() - 1)) { nextpitch = notes[line+1][column]; } if (pitch == 0) { // if the first rest in a row then true if ((lastpitch != 0) && (nextpitch == 0)) { // don't include rests which start and stop on the same line return 1; } else { return 0; } } else if (pitch < 0) { return 0; } else { if ((nextpitch < 0) && (nextpitch != -1)) { return 1; } else { return 0; } } } ////////////////////////////// // // noteContinueMarker -- // int noteContinueMarker(Array >& notes, int line, int column) { int start = 0; if (typeQ) { start = 1; } if (line < start) { return 0; } int pitch = notes[line][column]; int nextpitch = -1; int lastpitch = -1; if ((line > start) && (notes.getSize() > 1+start)) { lastpitch = notes[line-1][column]; } if ((notes.getSize() > start+1) && (line < notes.getSize() - 1)) { nextpitch = notes[line+1][column]; } if (pitch == 0) { // if not the first or the last zero than a continue if ((lastpitch == 0) && (nextpitch == 0)) { return 1; } else { return 0; } } else if (pitch > 0) { return 0; } else { if (pitch == nextpitch ) { return 1; } else { return 0; } } } ////////////////////////////// // // noteEndMarker -- // int noteEndMarker(Array >& notes, int line, int column) { int start = 0; if (typeQ) { start = 1; } if (line < start) { return 0; } int pitch = notes[line][column]; int nextpitch = -1; int lastpitch = -1; if ((line > start) && (notes.getSize() > 1+start)) { lastpitch = notes[line-1][column]; } if ((notes.getSize() > start+1) && (line < notes.getSize() - 1)) { nextpitch = notes[line+1][column]; } if (pitch == 0) { // if not the first or the last zero than a continue if (nextpitch != 0) { return 1; } else { return 0; } } else if (pitch > 0) { return 0; } else { if (pitch != nextpitch ) { return 1; } else { return 0; } } } ////////////////////////////// // // printExclusiveInterpretations -- print ** markers at the start of // each column of data. // // Order of optional prefix columns: // lineQ // measureQ // beatQ // absoluteQ // linedurQ // void printExclusiveInterpretations(int basecount) { char basename[1024] = {0}; const char* prefix = "##"; if (humdrumQ || mathQ) { prefix = "**"; } if (kernQ) { strcat(basename, "kern"); strcat(basename, "\t"); } if (base7Q) { // strcat(basename, prefix); strcat(basename, "b7"); } else if (base12Q) { // strcat(basename, prefix); strcat(basename, "b12"); } else { // strcat(basename, prefix); strcat(basename, "b40"); } if (attackQ) { strcat(basename, "\t"); strcat(basename, prefix); strcat(basename, "attk"); } if (lastQ) { strcat(basename, "\t"); strcat(basename, prefix); strcat(basename, "last"); } if (nextQ) { strcat(basename, "\t"); strcat(basename, prefix); strcat(basename, "next"); } int startmark = 0; if (indexQ) { if ((startmark == 0) && mathQ) { cout << "(*"; startmark++; } else { cout << prefix; } cout << "idx\t"; } if (lineQ) { if ((startmark == 0) && mathQ) { cout << "(*"; startmark++; } else { cout << prefix; } cout << "line\t"; } if (measureQ) { if ((startmark == 0) && mathQ) { cout << "(*"; startmark++; } else { cout << prefix; } cout << "bar\t"; } if (beatQ) { if ((startmark == 0) && mathQ) { cout << "(*"; startmark++; } else { cout << prefix; } cout << "beat\t"; } if (absoluteQ) { if ((startmark == 0) && mathQ) { cout << "(*"; startmark++; } else { cout << prefix; } cout << "abs\t"; } if (linedurQ) { if ((startmark == 0) && mathQ) { cout << "(*"; startmark++; } else { cout << prefix; } cout << "ldur\t"; } int i; for (i=0; i