// // 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 // Last Modified: Sun Oct 20 17:41:10 PDT 2013 Fixed tie problem // Last Modified: Tue Nov 12 14:37:11 PST 2013 Added column for measure duration // Last Modified: Sat Mar 12 20:41:25 PST 2016 Switched to STL // 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" #include #include #include using namespace std; #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_BARDUR 3100 #define TYPE_BEATDUR 3200 #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 (vector >& notes, vector& measpos, vector& linenum, HumdrumFile& infile, int base, int flags); void printNoteArray (vector >& notes, vector& measpos, vector& linenum, HumdrumFile& infile, vector& bardur, vector& beatdur); void printComments (HumdrumFile& infile, int startline, int stopline, int style); void printExclusiveInterpretations(int basecount); void printLine (vector >& notes, vector >& attacks, vector >& lasts, vector >& nexts, vector& measpos, vector& linenum, vector& bardur, vector& beatdur, HumdrumFile& infile, int index, int style); void usage (const char* command); void example (void); void checkOptions (Options& opts, int argc, char* argv[]); void getNoteAttackIndexes (vector >& attacks, vector >& notes, int offst); void getLastAttackIndexes (vector >& lasts, vector >& notes, int offset); void getNextAttackIndexes (vector >& lasts, vector >& notes, int offset); int noteStartMarker (vector >& notes, int line, int column); int noteEndMarker (vector >& notes, int line, int column); int noteContinueMarker (vector >& notes, int line, int column); int singleNote (vector >& notes, int line, int column); void getMeasureDurations (vector& bardur, HumdrumFile& infile); void getBeatDurations (vector& beatdur, HumdrumFile& infile); // 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 measuredurQ = 1; // used with --no-measure-duration int beatdurQ = 1; // used with --no-beat-duration 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 int zeroQ = 1; // used with -Z 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) { vector > notelist; vector bardur; vector beatdur; vector measpos; vector 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; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // getMeasureDurations -- Calculate the duration of a measure for each // line in the music. // void getMeasureDurations(vector& bardur, HumdrumFile& infile) { int i; double value = infile.getPickupDuration(); bardur.resize(infile.getNumLines()); for (i=0; i& bardur, HumdrumFile& infile) { int i; double value = 1.0; // quarter note bardur.resize(infile.getNumLines()); PerlRegularExpression pre; for (i=0; i >& notes, vector& measpos, vector& linenum, HumdrumFile& infile, int style, int flags) { notes.reserve(infile.getNumLines()); notes.resize(0); measpos.reserve(infile.getNumLines()); measpos.resize(0); linenum.reserve(infile.getNumLines()); linenum.resize(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 vector templist; templist.reserve(1000); vector templistI; templistI.reserve(1000); int value; int firstQ = 1; if (typeQ) { // store even if lineQ is zero! value = TYPE_LINE; linenum.push_back(value); } if (typeQ) { value = TYPE_MEASURE; measpos.push_back(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.resize(templist.size()); int value = TYPE_NOTES; switch (style) { case STYLE_BASE40: value += 40; break; case STYLE_BASE12: value += 12; break; case STYLE_BASE7: value += 7; break; } fill(templistI.begin(), templistI.end(), value); notes.push_back(templistI); } notes.push_back(templist); measpos.push_back(measnum); linenum.push_back(i); } if (endQ) { notes.resize(notes.size()+1); notes.back().resize(notes[notes.size()-2].size()); fill(notes.back().begin(), notes.back().end(), 0); // sustains instead of rests (have to copy .last(-1): // for (i=0; i<(int)notes.last().size(); i++) { // if (notes.back()[i] > 0) { // notes.back()[i] *= -1; // } // } measpos.push_back(measpos.back()); linenum.push_back(linenum.back()); // 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.back() = 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.back()].getBeat() == 1.0) { measpos.back()++; } } } ////////////////////////////// // // printNoteArray -- // void printNoteArray(vector >& notes, vector& measpos, vector& linenum, HumdrumFile& infile, vector& bardur, vector& beatdur) { vector > attacks; vector > lasts; vector > 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<(int)notes.size(); i++) { if (i == 0) { if (commentQ && !typeQ) { printComments(infile, 0, linenum[0], humdrumQ); } else if (commentQ && typeQ) { printComments(infile, 0, linenum[1], humdrumQ); } if (infoQ) { printExclusiveInterpretations(notes[0].size()); } else if (humdrumQ) { // always print exclusive interpretations if Humdrum output printExclusiveInterpretations(notes[0].size()); } if (mathQ) { if (Count <= 1) { cout << mathvar << " = {\n"; } else if (Current == 0) { cout << mathvar << " = {{\n"; } else { cout << "}, {\n"; } } } else if (commentQ) { printComments(infile, linenum[i-1]+1, linenum[i], humdrumQ); } if (typeQ && i == 0) { printLine(notes, attacks, lasts, nexts, measpos, linenum, bardur, beatdur, infile, i, 1); } else { printLine(notes, attacks, lasts, nexts, measpos, linenum, bardur, beatdur, infile, i, 0); } } if (humdrumQ) { int width = 1; if (attackQ) { width++; } if (lastQ) { width++; } if (nextQ) { width++; } if (kernQ) { width++; } int counter = notes[0].size(); counter *= width; counter += indexQ + lineQ + measureQ + beatQ + absoluteQ + linedurQ; // if (attackQ) { counter += notes[0].size(); } // if (lastQ) { counter += notes[0].size(); } // if (nextQ) { counter += notes[0].size(); } for (j=0; j >& lasts, vector >& notes, int offset) { int start = 0; lasts.resize(notes.size()); if (typeQ) { fill(lasts[0].begin(), lasts[0].end(), TYPE_LAST); start = 1; } int i, j; fill(lasts[start].begin(), lasts[start].end(), -1); if ((int)notes.size() == start+1) { return; } vector states; states.resize(notes[0].size()); if (typeQ) { fill(states.begin(), states.end(), offset+1); } else { fill(states.begin(), states.end(), offset); } for (i=0; i<(int)notes.size(); i++) { lasts[i].resize(notes[i].size()); if (i <= start) { fill(lasts[i].begin(), lasts[i].end(), -1); if (typeQ && (i==0)) { fill(lasts[i].begin(), lasts[i].end(), TYPE_LAST); } continue; } for (j=0; j<(int)notes[i].size(); j++) { if (notes[i][j] > 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(vector >& nexts, vector >& notes, int offset) { int start = 0; nexts.resize(notes.size()); if (typeQ) { nexts[0].resize(notes[0].size()); fill(nexts[0].begin(), nexts[0].end(), TYPE_NEXT); start = 1; } int i, j; nexts.back().resize(notes.back().size()); fill(nexts.back().begin(), nexts.back().end(), -1); if ((int)notes.size() == start+1) { return; } for (i=(int)notes.size()-2; i>=start; i--) { nexts[i].resize(notes[i].size()); for (j=0; j<(int)notes[i].size(); j++) { if ((notes[i][j] != 0) && (notes[i+1][j] == 0)) { // next note is a "rest attack" nexts[i][j] = i + 1 + offset; } else if (notes[i+1][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(vector >& attacks, vector >& notes, int offset) { attacks.resize(notes.size()); int i, j; attacks[0].resize(notes[0].size()); fill (attacks[0].begin(), attacks[0].end(), offset); for (i=1; i<(int)attacks.size(); i++) { attacks[i].resize(notes[i].size()); for (j=0; j<(int)attacks[i].size(); j++) { if (notes[i][j] < 0) { // a sustained note, so store index of attack note attacks[i][j] = attacks[i-1][j]; } else if (notes[i][j] > 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) { fill(attacks[0].begin(), attacks[0].end(), 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(vector >& notes, vector >& attacks, vector >& lasts, vector >& nexts, vector& measpos, vector& linenum, vector& bardur, vector& beatdur, 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 (measuredurQ) { if (indexQ || lineQ || measureQ) { if (mathQ) { cout << ","; } cout << "\t"; } if ((i == 0) && (linenum[i] == TYPE_LINE)) { cout << TYPE_BARDUR; } else { cout << bardur[linenum[i]]; } } if (beatdurQ) { if (indexQ || lineQ || measureQ || measuredurQ) { if (mathQ) { cout << ","; } cout << "\t"; } if ((i == 0) && (linenum[i] == TYPE_LINE)) { cout << TYPE_BEATDUR; } else { cout << beatdur[linenum[i]]; } } if (beatQ) { if (indexQ || lineQ || measuredurQ || measureQ || beatdurQ) { if (mathQ) { cout << ","; } cout << "\t"; } if (style == 1) { cout << TYPE_BEAT; } else if (rationalQ) { if (fractionQ) { cout << infile[linenum[i]].getBeatR() - 1; } else { // switched to 0-offset metrical position RationalNumber value = infile[linenum[i]].getBeatR(); value -= 1; value.printTwoPart(cout); } } else { // print beat position as a floating-point number: cout << infile[linenum[i]].getBeat() - 1; } } if (absoluteQ) { if (indexQ || lineQ || measuredurQ || measureQ || beatdurQ || 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 || measuredurQ || measureQ || beatdurQ || 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 || measuredurQ || measureQ || beatdurQ || beatQ || absoluteQ || linedurQ) { if (mathQ) { cout << ","; } } vector values; values.reserve(notes.size() * 10); int vv; int sign; for (j=0; j<(int)notes[i].size(); j++) { vv = notes[i][j]; //if (kernQ && (style == 1) && typeQ) { // int ww = TYPE_KERN; // values.push_back(ww); //} if (vv < TYPE_NOTES) { if (vv < 0) { sign = -1; vv = -vv; } else { sign = +1; } if (vv != 0) { switch (style) { case STYLE_BASE12: vv = Convert::base40ToMidiNoteNumber(vv); break; case STYLE_BASE7: vv = Convert::base40ToDiatonic(vv); break; } } vv *= sign; values.push_back(vv); } else { values.push_back(vv); } if (attackQ) { values.push_back(attacks[i][j]); } if (lastQ) { values.push_back(lasts[i][j]); } if (nextQ) { values.push_back(nexts[i][j]); } } int width = 1; // notes if (attackQ) { width++; } if (lastQ) { width++; } if (nextQ) { width++; } char buffer[1024] = {0}; for (j=0; j<(int)values.size(); j++) { if (kernQ && ((j % width) == 0)) { //if (mathQ) { // cout << ","; //} cout << "\t"; if ((style == 1) && (i == 0)) { cout << TYPE_KERN; } else { if (mathQ || quoteQ) { cout << "\""; } if (kerntieQ && noteStartMarker(notes, i, j / width)) { cout << "["; } if (doubletieQ && singleNote(notes, i, j / width)) { cout << "["; } if (values[j] == 0) { cout << "r"; } else { cout << Convert::base40ToKern(buffer, abs(values[j])); } if (kerntieQ && noteContinueMarker(notes, i, j / width)) { cout << "_"; } else if (kerntieQ && noteEndMarker(notes, i, j / width)) { cout << "]"; } if (doubletieQ && singleNote(notes, i, j / width)) { cout << "]"; } if (mathQ || quoteQ) { cout << "\""; } } if (mathQ) { cout << ","; } } cout << "\t" << values[j]; if (j < (int)values.size()-1) { if (mathQ) { cout << ","; } //cout << "\t"; } } if (mathQ) { cout << "}"; if (i < (int)linenum.size() - 1) { cout << ","; } } cout << endl; } ////////////////////////////// // // singleNote -- true if the note in the column/line is uniq // int singleNote(vector >& 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) && ((int)notes.size() > 1+start)) { lastpitch = notes[line-1][column]; } if (((int)notes.size() > start+1) && (line < (int)notes.size() - 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(vector >& 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) && ((int)notes.size() > 1+start)) { lastpitch = notes[line-1][column]; } if (((int)notes.size() > start+1) && (line < (int)notes.size() - 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(vector >& 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) && ((int)notes.size() > 1+start)) { lastpitch = notes[line-1][column]; } if (((int)notes.size() > start+1) && (line < (int)notes.size() - 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(vector >& 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) && ((int)notes.size() > 1+start)) { // lastpitch = notes[line-1][column]; } if (((int)notes.size() > start+1) && (line < (int)notes.size() - 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 (measuredurQ) { if ((startmark == 0) && mathQ) { cout << "(*"; startmark++; } else { cout << prefix; } cout << "mdur\t"; } if (beatdurQ) { if ((startmark == 0) && mathQ) { cout << "(*"; startmark++; } else { cout << prefix; } cout << "bdur\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