// // Programmer: Craig Stuart Sapp // Creation Date: Sat May 23 21:08:48 PDT 1998 // Last Modified: Fri Jul 3 14:18:04 PDT 1998 // Last Modified: Sat Oct 14 20:26:15 PDT 2000 revised for museinfo 1.0 // Last Modified: Wed Nov 29 12:14:41 PST 2000 use internal analysis // Last Modified: Tue Apr 21 00:41:11 PDT 2009 fixed spine manip printing // Last Modified: Thu May 14 20:25:17 PDT 2009 -U option added // Last Modified: Mon Apr 26 06:21:58 PDT 2010 -n, -s options added // Last Modified: Thu Mar 10 15:06:00 PST 2011 -i option added // Last Modified: Wed Mar 16 14:16:01 PDT 2011 added --iv option // Filename: ...sig/examples/all/sonority2.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/sonority2.cpp // Syntax: C++; museinfo // // Description: Analyzes **kern data for timeslice chord qualities // #include "humdrum.h" #include "Matrix.h" #include #include #ifndef OLDCPP #include #else #include #endif // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void example (void); void processRecords (HumdrumFile& infile); void usage (const char* command); void fillStringWithNotes (char* string, ChordQuality& quality, HumdrumFile& infile, int line); int identifyBassNote (SigCollection& notes, HumdrumFile& infile, int line, Array& sounding); int transitionalSonority(ChordQuality& quality, HumdrumFile& infile, int line); void printTriadImage (HumdrumFile& infile, int rows, int cols); void printBarlines (HumdrumFile& infile, int numberheight, int numberwidth); double getMeasureSize (HumdrumFile& infile, int width); void printLegend (int legendheight, int legendwidth); void printAttackMarker (HumdrumFile& infile, int line); void printAttackMarker (HumdrumFile& infile, int line); // global variables Options options; // database for command-line arguments char unknown[256] = {0}; // space for unknown chord simplification int chordinit; // for initializing chord detection function int explicitQ = 0; // used with -U option int notesQ = 0; // used with -n option int suppressQ = 0; // used with -s option int parenQ = 1; // used with -P option int ivQ = 0; // used with --iv option int forteQ = 0; // used with --forte option int tnQ = 0; // used with --tn option int tniQ = 0; // used with --tni option int attackQ = 0; // used with -x option int appendQ = 0; // used with -a option int imageQ = 0; // used with -I option int imagex = 800; // used with -I option int imagey = 20; // used with -I option int octaveVal = -100; // used with -o option int barlinesQ = 0; // used with -b option int legendQ = 0; // used with -l option int outlineQ = 1; // const char* notesep = " "; // used with -N option const char* colorindex[26]; /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile, outfile; // 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 cq; infile.analyzeSonorityQuality(cq); infile.analyzeRhythm("4"); Array > triads; triads.setSize(3); triads[0].setSize(cols); triads[0].setAll(24); triads[1].setSize(cols); triads[1].setAll(24); triads[2].setSize(cols); triads[2].setAll(24); colorindex[0] = "0 255 0"; // C major colorindex[1] = "38 255 140"; // C-sharp major colorindex[2] = "63 95 255"; // D major colorindex[3] = "228 19 83"; // E-flat major colorindex[4] = "255 0 0"; // E major colorindex[5] = "255 255 0"; // F major colorindex[6] = "192 255 0"; // F-sharp major colorindex[7] = "93 211 255"; // G major colorindex[8] = "129 50 255"; // A-flat major colorindex[9] = "205 41 255"; // A major colorindex[10] = "255 160 0"; // B-flat major colorindex[11] = "255 110 10"; // B major colorindex[12] = "0 161 0"; // C minor colorindex[13] = "15 191 90"; // C-sharp minor colorindex[14] = "37 61 181"; // D minor colorindex[15] = "184 27 75"; // E-flat minor colorindex[16] = "175 0 0"; // E minor colorindex[17] = "220 200 0"; // F minor colorindex[18] = "140 200 0"; // F-sharp minor colorindex[19] = "65 163 181"; // G minor colorindex[20] = "100 28 181"; // G-sharp minor colorindex[21] = "136 13 181"; // A minor colorindex[22] = "181 93 20"; // B-flat minor colorindex[23] = "211 107 0"; // B minor colorindex[24] = "255 255 255"; // background colorindex[25] = "0 0 0"; // silence double start; double end; int inversion; int starti; int endi; int minQ; int majQ; int i, m, j, ii; int rootindex; for (i=0; i= cols) { starti = cols-1; } if (endi >= cols) { endi = cols-1; } rootindex = Convert::base40ToMidiNoteNumber(cq[i].getRoot()); if (minQ) { rootindex += 12; } inversion = cq[i].getInversion(); for (ii=starti; ii<=endi; ii++) { triads[inversion][ii] = rootindex; } } int barheight = 0; int barwidth = 0; if (barlinesQ) { barheight = 11; barwidth = cols; } int legendheight = 0; int legendwidth = 0; if (legendQ) { legendheight = 100; legendwidth = cols; } int value = 24; Matrix image(rows*2, cols, value); for (i=triads.getSize()-1; i>=0; i--) { int start = int(i/2.0 * rows); for (m=0; m= image.getRowCount()) { ii = image.getRowCount() - 1; } for (j=0; j=0; i--) { for (j=0; j > xaxis; xaxis.setSize(numberheight-1); xaxis.allowGrowth(0); for (i=0; i barcount(10000); barcount.allowGrowth(0); barcount.setAll(0); double measuresize = getMeasureSize(infile, numberwidth); int size; int style = 0; int position; int number; for (i=0; i= 0) && (number < barcount.getSize())) { style = barcount[number]; barcount[number]++; } else { style = 0; } position = int(numberwidth * infile[i].getAbsBeat() / infile.getTotalDuration() + 0.5); if ((number % 100) == 0) { size = 10; } else if ((number % 50) == 0) { size = 8; } else if ((number % 10) == 0) { size = 6; } else if ((number % 5) == 0) { size = 4; } else { size = 2; if (measuresize < 3) { // don't display single measure ticks if they // are too closely spaced size = 0; } } } int color; if ((position >= 0) && (size > 0)) { for (j=0; j0) { xaxis[j][position-1] = color; } if (position > legend; legend.setSize(legendheight); legend.allowGrowth(0); int i, j; for (i=0; i diatonic(8); diatonic.allowGrowth(0); diatonic[0] = 0; diatonic[1] = 2; diatonic[2] = 4; diatonic[3] = 5; diatonic[4] = 7; diatonic[5] = 9; diatonic[6] = 11; int v, lastv = -1; for (i=startrow; i<=endrow; i++) { for (j=startcol; j<=endcol; j++) { v = diatonic[int((double)(j-startcol)/(endcol-startcol+1)*7)]; if (dooutline && ((v != lastv) || (j == endcol) || (i==startrow) || (i==endrow))) { legend[i][j] = 25; } else if (i > (endrow + startrow)/2) { // major keys legend[i][j] = v; } else { // minor keys legend[i][j] = v+12; } lastv = v; } } int blackkeyheight = 2 * (endrow - startrow) / 3; int blackend = startrow + blackkeyheight; int blackstartcol = startcol; int blackendcol = endcol; blackstartcol = blackstartcol + (endcol - startcol) / 96; lastv = 0; for (i=startrow; i<=blackend; i++) { for (j=blackstartcol; j<=blackendcol; j++) { v = int((double)(j-blackstartcol)/(blackendcol-blackstartcol+1)*12); if ((v != lastv) || (i==startrow)) { if ((v != 0) && (v != 5)) { legend[i][j] = 25; } lastv = v; continue; } if (!((v==1)||(v==3)||(v==6)||(v==8)||(v==10))) { continue; } if ((i==blackend)) { legend[i][j] = 25; } else if (i > (blackend + startrow)/2) { // major keys legend[i][j] = v; } else { // minor keys legend[i][j] = v+12; } lastv = v; } } Array transcolor; transcolor.setSize(26); transcolor.setAll(0); transcolor[24] = colorindex[24]; transcolor[25] = colorindex[25]; int transpose = 0; int rrotate = 0; for (i=0; i<12; i++) { transcolor[i] = colorindex[(i+transpose+rrotate) % 12]; transcolor[i+12] = colorindex[((i+transpose+rrotate) % 12)+12]; } for (i=0; i cq; infile.analyzeSonorityQuality(cq); ChordQuality quality; int foundstart = 0; char aString[512] = {0}; for (int i=0; i iv; infile.getIntervalVector(iv, i); cout << "<"; for (int ii=0; ii 0) { cout << ","; } cout << iv[ii]; if (ii < 5) { cout << ","; } } cout << ">" << endl; } else if (forteQ) { const char* name = infile.getForteSetName(i); cout << name; if (tnQ) { if (strcmp(name, "3-11") == 0) { if (strcmp(cq[i].getTypeName(), "min") == 0) { cout << "A"; } else if (strcmp(cq[i].getTypeName(), "maj") == 0) { cout << "B"; } } } if (tniQ) { int inversion = -1; if (strcmp(name, "3-11") == 0) { if ((strcmp(cq[i].getTypeName(), "min") == 0) || (strcmp(cq[i].getTypeName(), "maj") == 0)) { inversion = cq[i].getInversion(); } if (inversion >= 0) { cout << char('a'+inversion); } } } if (attackQ) { printAttackMarker(infile, i); } cout << endl; } else if (notesQ == 0) { quality = cq[i]; quality.makeString(aString, explicitQ); if (strcmp(aString, "") != 0) { if (strcmp(aString, unknown) == 0 || ( quality.getType()==E_chord_note && options.getBoolean("root")) ) { char tempbuffer[128] = {0}; strcpy(tempbuffer, aString); strcpy(aString, options.getString("unknown")); strcat(aString, tempbuffer); } if (suppressQ && transitionalSonority(quality, infile, i)) { strcpy(aString, "."); } } else { strcpy(aString, "rest"); } cout << aString << endl; } else { quality = cq[i]; fillStringWithNotes(aString, quality, infile, i); cout << aString << endl; } break; default: cerr << "Error on line " << (i+1) << " of input" << endl; cerr << "record type = " << infile[i].getType() << endl; exit(1); } } } ////////////////////////////// // // printAttackMarker -- print an "x" if the there is any note at // the start of the region which is not attacked (i.e., suspended // from a previous sonority. // void printAttackMarker(HumdrumFile& infile, int line) { int j, ii, jj; int& i = line; int dotQ; for (j=0; j notes; quality.getNotesInChord(notes); Array octave; octave.setSize(notes.getSize()); octave.allowGrowth(0); octave.setAll(0); Array sounding; sounding.setSize(notes.getSize()); sounding.allowGrowth(0); sounding.setAll(0); // int bassindex = identifyBassNote(notes, infile, line, sounding); int i; for (i=0; i notes; quality.getNotesInChord(notes); Array octave; octave.setSize(notes.getSize()); octave.allowGrowth(0); octave.setAll(4); Array sounding; sounding.setSize(notes.getSize()); sounding.allowGrowth(0); sounding.setAll(0); int bassindex = identifyBassNote(notes, infile, line, sounding); if (bassindex >= 0) { octave[bassindex] = 3; //if (notes[bassindex] >= 40) { // octave[bassindex] += -2; //} } int i; if (suppressQ) { for (i=0; i= 0) { // Convert::base40ToKern(buffer, (notes[i]%40) + octaveVal * 40); //} else { // Convert::base40ToKern(buffer, notes[i] + ((octave[i]+4) * 40)); //} Convert::base40ToKern(buffer, notes[i]%40 + (octave[i] * 40)); if (parenQ && (sounding[i] == 0)) { strcat(string, "("); } strcat(string, buffer); if (parenQ && (sounding[i] == 0)) { strcat(string, ")"); } if (i < notes.getSize() - 1) { strcat(string, notesep); } } } ////////////////////////////// // // identifyBassnote -- // int identifyBassNote(SigCollection& notes, HumdrumFile& infile, int line, Array& sounding) { int j, k; int output = -1; int minval = 1000000; int value; int tcount; char buffer[128] = {0}; Array soundQ(40); soundQ.setAll(0); sounding.setSize(notes.getSize()); sounding.setAll(0); int pline; int pspine; int dotQ = 0; if (notes.getSize() == 0) { return -1; } for (j=0; j 100000) { return -1; } minval = minval % 12; int i; int tval; for (i=0; i= 0) { if (soundQ[notes[i]%40]) { sounding[i] = 1; } } tval = Convert::base40ToMidiNoteNumber(notes[i]); if (tval < 0) { continue; } tval = tval % 12; if (tval == minval) { output = i; // break; need to supress this because of sounding tests } } return output; } ////////////////////////////// // // usage -- gives the usage statement for the sonority program // void usage(const char* command) { cout << " \n" "Analyzes **kern data and generates a **qual spine which gives the chord \n" "quality of the **kern spines. Currently, input spines cannot split or \n" "join. \n" " \n" "Usage: " << command << " [-a][-i|-r|-t] [input1 [input2 ...]] \n" " \n" "Options: \n" " -a = assemble the **qual analysis spine with input data \n" " -i = displays the **qual chord inversion only \n" " -r = displays the **qual chord root only \n" " -t = displays the **qual chord type only \n" " --options = list of all options, aliases and default values \n" " \n" << endl; } // md5sum: c1cc61fb24d51daddeaf667365673f20 sonority.cpp [20110317]