// // Programmer: Craig Stuart Sapp // Creation Date: Mon Sep 16 08:19:10 PDT 2013 Adapted from dissonant.cpp // Filename: ...museinfo/examples/all/cint.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/cint.cpp // Syntax: C++; museinfo // // Description: Calculates counterpoint interval modules in polyphonic // music. // #include "humdrum.h" #include #include "PerlRegularExpression.h" #ifndef OLDCPP #include #include #include #define SSTREAM stringstream #define CSTRING str().c_str() using namespace std; #else #include #include #ifdef VISUAL #include #else #include #endif #define SSTREAM strstream #define CSTRING str() #endif class NoteNode { public: int b40; // base-40 pitch number or 0 if a rest, negative if tied0. int line; // line number in original score of note int spine; // spine number in original score of note int lastint; // interval to last note (or 0 if no last or last is rest) int nextint; // interval to next note (or 0 if no next or last is rest) int serial; // notes serial number int measure; // measure number of note Array hint; // harmonic intervals to other voices Array hvoice; // voice number of harmonic interval NoteNode(void) { clear(); } void clear(void) { serial = b40 = 0; line = spine = -1; lastint = nextint = 0; hvoice.setSize(0); hint.setSize(0); } }; #define REST 0 #define RESTINT -1000000 /////////////////////////////////////////////////////////////////////////// // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void example (void); void usage (const char* command); void processFile (HumdrumFile& infile, const char* filename); void getKernTracks (Array& ktracks, HumdrumFile& infile); void calculateMelodicIntervals(Array >& notes); void markParallels (Array >& notes, HumdrumFile& infile, const char* filename, Array >& names, Array reverselookup); void addMark (HumdrumFile& infile, int line, int spine, char marker); void markParallel (HumdrumFile& infile, Array >& notes, int hint, int i, int j, int k); int validateInterval (Array >& notes, int i, int j, int k); void markDissonances (Array >& notes, HumdrumFile& infile, const char* filename, Array >& names, Array reverselookup); void printDissonanceOutput(HumdrumFile& infile, Array >& notes, Array >& names); void printIntervalInfo (HumdrumFile& infile, int line, int spine, Array >& notes, int noteline, int noteindex, Array >& abbr); void getAbbreviations (Array >& abbreviations, Array >& names); void getAbbreviation (Array& abbr, Array& name); void markNote (HumdrumFile& infile, char mark, int line, int spine); int checkForFourth (Array >& notes, int j, HumdrumFile& infile); // global variables Options options; // database for command-line arguments int debugQ = 0; // used with --debug int labelQ = 1; // used with -l option int rawQ = 0; // used with -r option int raw2Q = 0; // used with --r2 option int fileQ = 0; // used with -f option /////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { checkOptions(options, argc, argv); HumdrumFile infile; int i; // figure out the number of input files to process int numinputs = options.getArgCount(); const char* filename = ""; PerlRegularExpression pre; for (i=0; i >& names, Array& reverselookup, HumdrumFile& infile) { names.setSize(reverselookup.getSize()-1); names.allowGrowth(0); char buffer[1024] = {0}; int value; PerlRegularExpression pre; int i; int j; int track; for (i=0; i > notes; Array > names; Array ktracks; Array reverselookup; int ii; int jj; getKernTracks(ktracks, infile); notes.setSize(ktracks.getSize()); reverselookup.setSize(infile.getMaxTracks()+1); reverselookup.setAll(-1); for (i=0; i current; current.setSize(ktracks.getSize()); int sign; int track; int index; int snum = 0; int measurenumber = 0; for (i=0; i 0) { current[index].serial = ++snum; } } for (j=0; j >& notes, HumdrumFile& infile, const char* filename, Array >& names, Array reverselookup) { int i; int j; int k; int hint; int hval; int dhint; // diatonic harmonic interval int highest; int lowest; int has2nd = 0; int has7th = 0; int has4th = 0; for (j=0; j abs(notes[i][j].b40)) { highest = k; lowest = i; } else { highest = i; lowest = k; } hint = abs(notes[highest][j].b40) - abs(notes[lowest][j].b40); dhint = Convert::base40IntervalToDiatonic(hint) % 7; // store interval as positive for bottom voice's note and // negative for top voice's note. if (notes[lowest][j].b40 > 0) { hval = hint % 40; if (hval != 17) { // suppress 4ths since handled elsewhere notes[lowest][j].hvoice.append(highest); notes[lowest][j].hint.append(hval); } } if (notes[highest][j].b40 > 0) { hval = hint % 40; if (hval != 17) { // suppress 4ths since handled elsewhere hval = -hval; notes[highest][j].hvoice.append(lowest); notes[highest][j].hint.append(hval); } } // markInterval(infile, notes, hint, highest, j, lowest); if (dhint == 1) { has2nd = 1; if (notes[highest][j].b40 > 0) { markNote(infile, '<', notes[highest][j].line, notes[highest][j].spine); } if (notes[lowest][j].b40 > 0) { markNote(infile, '<', notes[lowest][j].line, notes[lowest][j].spine); } } if (dhint == 6) { has7th = 1; if (notes[highest][j].b40 > 0) { markNote(infile, '>', notes[highest][j].line, notes[highest][j].spine); } if (notes[lowest][j].b40 > 0) { markNote(infile, '>', notes[lowest][j].line, notes[lowest][j].spine); } } } } } if (labelQ) { printDissonanceOutput(infile, notes, names); } else { cout << infile; } if (has4th) { cout << "!!!RDF**kern: | = marked note, color=\"#ff0000\", "; cout << "fourth interval above lowest note" << endl; } if (has2nd) { cout << "!!!RDF**kern: < = marked note, color=\"#00ff00\", "; cout << "second interval" << endl; } if (has7th) { cout << "!!!RDF**kern: > = marked note, color=\"#00ff00\", "; cout << "seventh interval" << endl; } } ////////////////////////////// // // checkForFourth -- returns true if a 4th above the lowest note was found. // int checkForFourth(Array >& notes, int j, HumdrumFile& infile) { int i; int lowest = 100000; int lowestindex = -1; int notecount = 0; int output = 0; int hint; for (i=0; i 0) { notes[i][j].hint.append(value); notes[i][j].hvoice.append(lowestindex); markNote(infile, '|', notes[i][j].line, notes[i][j].spine); } value = hint; if (notes[lowestindex][j].b40 > 0) { notes[lowestindex][j].hint.append(value); notes[lowestindex][j].hvoice.append(i); markNote(infile, '|', notes[lowestindex][j].line, notes[lowestindex][j].spine); } } } return output; } ////////////////////////////// // // markNote -- // void markNote(HumdrumFile& infile, char mark, int line, int spine) { Array token; token.setSize(strlen(infile[line][spine])+2); strcpy(token.getBase(), infile[line][spine]); char buffer[2] = {0}; buffer[0] = mark; strcat(token.getBase(), buffer); infile[line].changeField(spine, token.getBase()); } ////////////////////////////// // // getAbbreviations -- // void getAbbreviations(Array >& abbreviations, Array >& names) { abbreviations.setSize(names.getSize()); int i; for (i=0; i& abbr, Array& name) { PerlRegularExpression pre; abbr.setSize(strlen(name.getBase())+1); strcpy(abbr.getBase(), name.getBase()); pre.sar(abbr, "(?<=[a-zA-Z])[a-zA-Z]*", "", ""); pre.tr(abbr, "123456789", "abcdefghi"); } ////////////////////////////// // // printDissonanceOutput -- // void printDissonanceOutput(HumdrumFile& infile, Array >& notes, Array >& names) { Array linemap; linemap.setSize(infile.getNumLines()); linemap.setAll(-1); int i, k; for (k=0; k= 0) { linemap[notes[k][i].line] = i; } } } Array > abbreviations; getAbbreviations(abbreviations, names); int j; int n; int value; int track; int nexttrack; int noteindex; PerlRegularExpression pre; PerlRegularExpression pre2; for (i=0; i > tokens; pre2.getTokens(tokens, ",", pre.getSubmatch(2)); for (n=0; n >& notes, int noteline, int noteindex, Array >& abbr) { // [20120323] fixed spine split problem? if (noteindex >= notes.getSize()) { return; } if (notes[noteindex][noteline].hint.getSize() == 0) { cout << "."; return; } SSTREAM out; int m; int dhint; int msize = notes[noteindex][noteline].hint.getSize(); int hint; int pcount = 0; for (m=0; m output; output.setSize(strlen(out.CSTRING)+1); strcpy(output.getBase(), out.CSTRING); PerlRegularExpression pre; pre.sar(output, ",$", "", ""); cout << output; } ////////////////////////////// // // markParallel -- // void markParallel(HumdrumFile& infile, Array >& notes, int hint, int i, int j, int k) { char marker = '<'; // cint octaves/unisons if (hint == 23) { marker = '>'; // cint fifths } int ii; int jj; // mark first note in cint motion ii = notes[i][j].line; jj = notes[i][j].spine; if (strcmp(infile[ii][jj], ".") == 0) { int ti; int tj; ti = infile[ii].getDotLine(jj); tj = infile[ii].getDotSpine(jj); ii = ti; jj = tj; } if (strcmp(infile[ii][jj], ".") != 0) { // if (strchr(infile[ii][jj], marker) == NULL) { addMark(infile, ii, jj, marker); // } } // mark second note in cint motion ii = notes[k][j].line; jj = notes[k][j].spine; if (strcmp(infile[ii][jj], ".") == 0) { int ti; int tj; ti = infile[ii].getDotLine(jj); tj = infile[ii].getDotSpine(jj); ii = ti; jj = tj; } if (strcmp(infile[ii][jj], ".") != 0) { // if (strchr(infile[ii][jj], marker) == NULL) { addMark(infile, ii, jj, marker); // } } int m; // mark third note in cint motion for (m=j+1; m >& notes) { int i, j; int lastint = RESTINT; int lastnote = 0; // caluculate the intervals to previous notes: for (i=0; i=0; j--) { notes[i][j].nextint = nextint; if (notes[i][j].b40 >= 0) { nextint = notes[i][j].lastint; } } } } ////////////////////////////// // // getKernTracks -- return a list of track number for **kern spines. // void getKernTracks(Array& ktracks, HumdrumFile& infile) { int i, j; ktracks.setSize(infile.getMaxTracks()); ktracks.setSize(0); int track; for (i=0; i