// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // 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 <stdlib.h> #include <string.h> #ifndef OLDCPP #include <iostream> #else #include <iostream.h> #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<int>& notes, HumdrumFile& infile, int line, Array<int>& 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<numinputs || i==0; i++) { chordinit = 1; infile.clear(); // if no command-line arguments read data file from standard input if (numinputs < 1) { infile.read(cin); } else { infile.read(options.getArg(i+1)); } // analyze the input file according to command-line options if (imageQ) { printTriadImage(infile, imagey, imagex); } else { processRecords(infile); } } return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // printTriadImage -- // void printTriadImage(HumdrumFile& infile, int rows, int cols) { Array<ChordQuality> cq; infile.analyzeSonorityQuality(cq); infile.analyzeRhythm("4"); Array<Array<int> > 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<infile.getNumLines(); i++) { if (!infile[i].isData()) { continue; } if (strcmp(cq[i].getTypeName(), "min") == 0) { minQ = 1; } else { minQ = 0; } if (strcmp(cq[i].getTypeName(), "maj") == 0) { majQ = 1; } else { majQ = 0; } if (!(majQ || minQ)) { cerr << cq[i] << "\t" << cq[i].getTypeName() << endl; continue; } start = infile[i].getAbsBeat(); end = start + infile[i].getDuration(); starti = int(start / infile.getTotalDuration() * cols + 0.5); endi = int(end / infile.getTotalDuration() * cols + 0.5); if (starti < 0) { starti = 0; } if (endi < 0) { endi = 0; } if (starti >= 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<int> image(rows*2, cols, value); for (i=triads.getSize()-1; i>=0; i--) { int start = int(i/2.0 * rows); for (m=0; m<rows; m++) { ii = (int)(m + start); if (ii >= image.getRowCount()) { ii = image.getRowCount() - 1; } for (j=0; j<triads[i].getSize(); j++) { if (triads[i][j] < 24) { image.cell(ii,j) = triads[i][j]; } // cout << colorindex[triads[i][j]] << " "; //cout << triads[i][j] << " "; } //cout << "\n"; } } // print Image: cout << "P3\n"; cout << cols << " " << rows*2 + barheight + legendheight << "\n"; cout << "255\n"; for (i=image.getRowCount()-1; i>=0; i--) { for (j=0; j<image.getColumnCount(); j++) { cout << colorindex[image.cell(i,j)] << ' '; } cout << "\n"; } if (barlinesQ) { printBarlines(infile, barheight, barwidth); } if (legendQ) { printLegend(legendheight, legendwidth); } } /////////////////////////////// // // printBarlines -- print Barline numbers as lines underneath // the plot. // void printBarlines(HumdrumFile& infile, int numberheight, int numberwidth) { int i, j; Array<Array<int> > xaxis; xaxis.setSize(numberheight-1); xaxis.allowGrowth(0); for (i=0; i<xaxis.getSize(); i++) { xaxis[i].setSize(numberwidth); xaxis[i].allowGrowth(0); xaxis[i].setAll(24); } // bar counter keeps track of multiple repeats of the same // music. Array<int> 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<infile.getNumLines(); i++) { if (!infile[i].isMeasure()) { continue; } size = 0; position = -1; if (sscanf(infile[i][0], "=%d", &number)) { if ((number >= 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; j<size; j++) { if (style == 0) { color = 25; } else if (style == 1) { color = 4; // red (in default color) } else if (style == 2) { color = 2; // blue (in default color) } else if (style == 3) { color = 0; // green (in default color) } else { color = 11; // orange (in default color) } xaxis[j][position] = color; if (j==9) { if (position>0) { xaxis[j][position-1] = color; } if (position<xaxis[0].getSize()-1) { xaxis[j][position+1] = color; } } } } } // print a empty line so that small measure markers can be seen for (i=0; i<xaxis[0].getSize(); i++) { cout << ' ' << colorindex[24]; } cout << '\n'; for (i=0; i<xaxis.getSize(); i++) { for (j=0; j<xaxis[i].getSize(); j++) { cout << ' ' << colorindex[xaxis[i][j]]; } cout << '\n'; } } ////////////////////////////// // // getMeasureSize -- return the pixel size of a single measure. // double getMeasureSize(HumdrumFile& infile, int width) { int i; int bar = -100; int lastbar = -1000; int line = -100; int lastline = -1000; int number; for (i=0; i<infile.getNumLines(); i++) { if (!infile[i].isMeasure()) { continue; } if (sscanf(infile[i][0], "=%d", &number)) { bar = number; line = i; if (bar == lastbar + 1) { return (infile[line].getAbsBeat() - infile[lastline].getAbsBeat()) / infile.getTotalDuration() * width; } else { lastbar = bar; lastline = line; } } } return 5; } /////////////////////////////// // // printLegend -- print key color mappings as a keyboard // void printLegend(int legendheight, int legendwidth) { Array<Array<int> > legend; legend.setSize(legendheight); legend.allowGrowth(0); int i, j; for (i=0; i<legend.getSize(); i++) { legend[i].setSize(legendwidth); legend[i].allowGrowth(0); legend[i].setAll(24); // set to background color } int startrow = legendheight / 5; int endrow = legendheight - 1; int startcol = legendwidth / 5; int endcol = legendwidth - startcol - 1; int dooutline = outlineQ; if (legendwidth < 100) { // don't print outline on a small legend dooutline = 0; } Array<int> 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<const char*> 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<legend.getSize(); i++) { for (j=0; j<legend[i].getSize(); j++) { cout << ' ' << transcolor[legend[i][j]]; } cout << "\n"; } } ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("t|type=b", "show only chord type"); opts.define("i|inversion=b", "show only chord inversion"); opts.define("r|root=b", "show only chord root"); opts.define("a|assemble|append=b", "append analysis to input data"); opts.define("f|format=s:t:i:r", "control display style"); opts.define("u|unknown=s:X", "control display of unknowns"); opts.define("U|unknown-pcs=b", "print pcs of unknown sonrities"); opts.define("d|debug=b", "determine bad input line num"); opts.define("n|notes=b", "display pitch classes in sonority"); opts.define("iv=b", "print interval vector"); opts.define("x|sonor|suspension=b", "print marker if not all start attacks"); opts.define("forte=b", "print forte interval vector set name"); opts.define("Tn|tn=b", "print forte set with subsets"); opts.define("Tni|tni=b", "print forte set with subsets/inversion"); opts.define("s|suppress=b", "suppress data if overlapping sonority"); opts.define("I|image=s:800x20", "display image of major/minor chords"); opts.define("P|paren-off=b", "suppress parentheses for overlapping"); opts.define("N|separator=s: ", "characters to separate pitch classes"); opts.define("o|octave=i:4", "characters to separate pitch classes"); opts.define("b|barlines=b", "display barlines at bottom of image"); opts.define("l|legend=b", "display color mapping"); 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, May 1998" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: Nov 2000" << 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("root")) { ChordQuality::setDisplay("r"); } else if (opts.getBoolean("type")) { ChordQuality::setDisplay("t"); } else if (opts.getBoolean("inversion")) { ChordQuality::setDisplay("i"); } else { ChordQuality::setDisplay(opts.getString("format")); } Convert::chordType.setNullName(opts.getString("unknown")); Convert::chordInversion.setNullName(opts.getString("unknown")); Convert::kernPitchClass.setNullName(opts.getString("unknown")); strncpy(unknown, opts.getString("unknown"), 64); strcat(unknown, ":"); strncat(unknown, opts.getString("unknown"), 64); strcat(unknown, ":"); strncat(unknown, opts.getString("unknown"), 64); explicitQ = opts.getBoolean("unknown-pcs"); imageQ = opts.getBoolean("image"); if (imageQ) { imagex = 800; imagey = 20; sscanf(opts.getString("image"), "%dx%d", &imagex, &imagey); } ivQ = opts.getBoolean("iv"); attackQ = opts.getBoolean("suspension"); forteQ = opts.getBoolean("forte"); tnQ = opts.getBoolean("Tn"); if (tnQ) { forteQ = 1; } tniQ = opts.getBoolean("Tni"); if (tniQ) { tnQ = 1; forteQ = 1; } notesQ = opts.getBoolean("notes"); suppressQ = opts.getBoolean("suppress"); parenQ = !opts.getBoolean("paren-off"); appendQ = opts.getBoolean("append"); barlinesQ = opts.getBoolean("barlines"); legendQ = opts.getBoolean("legend"); if (opts.getBoolean("separator")) { notesep = opts.getString("separator"); } if (opts.getBoolean("octave")) { octaveVal = opts.getInteger("octave"); } } ////////////////////////////// // // example -- example usage of the sonority program // void example(void) { cout << " \n" "# example usage of the sonority program. \n" "# analyze a Bach chorale for chord qualities: \n" " sonority chor217.krn \n" " \n" "# display the chord analysis with original data: \n" " sonority -a chor217.krn \n" " \n" "# display only the roots of chords: \n" " sonority -r chor217.krn \n" " \n" << endl; } ////////////////////////////// // // processRecords -- looks at humdrum records and determines chord // sonority quality; // void processRecords(HumdrumFile& infile) { Array<ChordQuality> cq; infile.analyzeSonorityQuality(cq); ChordQuality quality; int foundstart = 0; char aString[512] = {0}; for (int i=0; i<infile.getNumLines(); i++) { if (options.getBoolean("debug")) { cout << "processing line " << (i+1) << " of input ..." << endl; cout << "LINE IS: " << infile[i] << endl; } switch (infile[i].getType()) { case E_humrec_none: case E_humrec_empty: case E_humrec_bibliography: case E_humrec_global_comment: cout << infile[i] << endl; break; case E_humrec_data_comment: if (appendQ) { cout << infile[i] << "\t"; } if (infile[i].equalFieldsQ("**kern")) { cout << infile[i][0]; } else { cout << "!"; } cout << endl; break; case E_humrec_data_interpretation: if (appendQ) { cout << infile[i] << "\t"; } if (!foundstart && infile[i].hasExclusiveQ()) { foundstart = 1; if (tniQ) { cout << "**Tni"; } else if (tnQ) { cout << "**Tn"; } else if (forteQ) { cout << "**forte"; } else { cout << "**qual"; } } else { if (infile[i].equalFieldsQ("**kern") && (!infile[i].isSpineManipulator(0))) { cout << infile[i][0]; } else { cout << "*"; } } cout << endl; break; case E_humrec_data_kern_measure: if (appendQ) { cout << infile[i] << "\t"; } cout << infile[i][0]; cout << endl; break; case E_humrec_data: if (appendQ) { cout << infile[i] << "\t"; } // handle null fields if (infile[i].equalFieldsQ("**kern", ".")) { cout << "." << endl; break; } if (ivQ) { Array<int> iv; infile.getIntervalVector(iv, i); cout << "<"; for (int ii=0; ii<iv.getSize(); ii++) { if (iv[ii] < 9) { cout << iv[ii]; continue; } if (iv[ii] < 36) { cout << char(iv[ii]-10+'A'); continue; } if (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<infile[i].getFieldCount(); j++) { if (!infile[i].isExInterp(j, "**kern")) { continue; } if (strcmp(infile[i][j], ".") == 0) { ii = infile[i].getDotLine(j); jj = infile[i].getDotSpine(j); dotQ = 1; } else { ii = i; jj = j; dotQ = 0; } if (strchr(infile[ii][jj], 'r') != NULL) { continue; } else if (dotQ) { cout << "x"; return; } if (strchr(infile[ii][jj], '_') != NULL) { cout << "x"; return; } if (strchr(infile[ii][jj], ']') != NULL) { cout << "x"; return; } } } ////////////////////////////// // // transitionalSonority -- // int transitionalSonority(ChordQuality& quality, HumdrumFile& infile, int line) { SigCollection<int> notes; quality.getNotesInChord(notes); Array<int> octave; octave.setSize(notes.getSize()); octave.allowGrowth(0); octave.setAll(0); Array<int> sounding; sounding.setSize(notes.getSize()); sounding.allowGrowth(0); sounding.setAll(0); // int bassindex = identifyBassNote(notes, infile, line, sounding); int i; for (i=0; i<sounding.getSize(); i++) { if (sounding[i] == 0) { return 1; } } return 0; } ////////////////////////////// // // fillStringWithNotes -- // void fillStringWithNotes(char* string, ChordQuality& quality, HumdrumFile& infile, int line) { string[0] = '\0'; SigCollection<int> notes; quality.getNotesInChord(notes); Array<int> octave; octave.setSize(notes.getSize()); octave.allowGrowth(0); octave.setAll(4); Array<int> 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<sounding.getSize(); i++) { if (sounding[i] == 0) { strcpy(string, "."); return; } } } string[0] = '\0'; char buffer[32] = {0}; for (i=0; i<notes.getSize(); i++) { //if (octaveVal >= 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<int>& notes, HumdrumFile& infile, int line, Array<int>& sounding) { int j, k; int output = -1; int minval = 1000000; int value; int tcount; char buffer[128] = {0}; Array<int> 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<infile[line].getFieldCount(); j++) { if (!infile[line].isExInterp(j, "**kern")) { continue; } dotQ = 0; if (strcmp(infile[line][j], ".") == 0) { pline = infile[line].getDotLine(j); pspine = infile[line].getDotSpine(j); dotQ = 1; } else { pline = line; pspine = j; } tcount = infile[pline].getTokenCount(pspine); for (k=0; k<tcount; k++) { infile[pline].getToken(buffer, pspine, k); if (strchr(buffer, 'r') != NULL) { continue; } if (strcmp(buffer, ".") == 0) { // shouldn't get here... continue; } value = Convert::kernToMidiNoteNumber(buffer); if (value < 0) { continue; } if (value < minval) { minval = value; } if (dotQ) { continue; } if (strchr(buffer, '_') != NULL) { continue; } if (strchr(buffer, ']') != NULL) { continue; } value = Convert::kernToBase40(buffer); if (value < 0) { continue; } soundQ[value % 40] = 1; } } if (minval > 100000) { return -1; } minval = minval % 12; int i; int tval; for (i=0; i<notes.getSize(); i++) { if (notes[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: 45968f7aea2c30cf0f9608748e2b3ed8 sonority.cpp [20130420]