// // Programmer: Craig Stuart Sapp // Creation Date: Tue Nov 21 14:12:11 PST 2000 // Last Modified: Tue Nov 21 14:12:13 PST 2000 // Filename: ...sig/doc/examples/all/dissnote/dissnote.cpp // Web Address: http://sig/doc/examples/all/dissnote/dissnote.cpp // Syntax: C++ // // Description: Determine if a note in a sonority is dissonant according // to rules given by John Maxwell. // // "An Expert System for Harmonizing Analysis of Tonal // Music." pp 335-353 in: "Understanding Music with AI: // Perspectives on Music Cognition." Ed. by Mira Balaban, // Kemal Ebcioglu, and Otto Laske. MIT Press; 1992. // [ISBN 0-262-52170-9] // #include "humdrum.h" #include #include #include typedef Array notearray; // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void example (void); void displayNoteDiss (Array& notediss); void generateAnalysis (HumdrumFile& infile, Array& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& notediss); int measureAccentuation (HumdrumFile& infile, int line); int measureTertian (HumdrumFile& infile, int line); int measureTertianDissonance (HumdrumFile& infile, int line); int measureVerticalConsonance(HumdrumFile& infile, int line); int measureDissic (int line, Array& soncondis, Array& tertian, Array& terdis, Array& accent); int measureNoteDissonance (int line, HumdrumFile& score, int note, Array& soncondis, Array& accent, Array& dissic); void printAnalysis (HumdrumFile& infile, Array& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& notediss); void rotateNotes (Array& notes); void usage (const char* command); // global variables Options options; // database for command-line arguments int debugQ = 0; // used with the --debug option int appendQ = 0; // used with the -a option int compoundQ = 1; // used with the -c option // variables for keeping track of the change in meter during the score: int metercount = 4; int meterbase = 4; /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile; Array soncondis; Array tertian; Array terdis; Array accent; Array dissic; Array notediss; // 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& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& notediss) { soncondis.setSize(infile.getNumLines()); tertian.setSize(infile.getNumLines()); terdis.setSize(infile.getNumLines()); accent.setSize(infile.getNumLines()); dissic.setSize(infile.getNumLines()); notediss.setSize(infile.getNumLines()); int i, j; for (i=0; i currentnotes; infile.getNoteList(currentnotes, i, NL_NOFILL | NL_NOSORT | NL_NOUNIQ | NL_NORESTS); int m; for (m=0; m notes; if (infile[line].getType() != E_humrec_data) { return UNDEFINED_VERTICAL; } infile.getNoteList(notes, line, NL_FILL | NL_SORT | NL_UNIQ | NL_NORESTS); // IF a sonority consists of only one note, THEN it is a consonant vertical. if (notes.getSize() <= 1) { return CONSONANT_VERTICAL; } // IF a sonority consists of two notes that form a consonant interval // other than a perfect fourth, THEN it is a consonant vertical. if (notes.getSize() == 2) { int interval = notes[1] - notes[0]; if (interval < 0) { cout << "Error on line " << line+1 << " of file: " << "problem determing interval" << endl; exit(1); } interval = interval % 40; if (interval == E_base40_per4) { return DISSONANT_VERTICAL; } else if (interval == E_base40_per1 || interval == E_base40_maj3 || interval == E_base40_min3 || interval == E_base40_min6 || interval == E_base40_maj6 || interval == E_base40_per5) { return CONSONANT_VERTICAL; } else { return DISSONANT_VERTICAL; } } // IF a sonority consists of three or more notes forming only // consonant intervals, THEN it is a consonant vertical. int i, j; int interval; for (i=0; i notes; if (infile[line].getType() != E_humrec_data) { return TERTIAN_UNKNOWN; } infile.getNoteList(notes, line, NL_PC | NL_FILL | NL_SORT | NL_UNIQ | NL_NORESTS); // if there is one or fewer notes, then cannot be tertian if (notes.getSize() <= 1) { return TERTIAN_NO; } int i, j; int foundTertianQ = 0; int interval; for (i=0; i notes; if (infile[line].getType() != E_humrec_data) { return TERTIAN_UNKNOWN; } infile.getNoteList(notes, line, NL_PC | NL_FILL | NL_SORT | NL_UNIQ | NL_NORESTS); if (notes.getSize() == 0) { return TERTIAN_0; } if (notes.getSize() == 1) { return TERTIAN_0; } int i, j; int foundTertianQ = 0; int interval; for (i=0; i 0.999) { fraction = 0; beat++; } if (fraction == 0) { return ACCENT_YES; } else { return ACCENT_NO; } } ////////////////////////////// // // measureDissic -- determine dissonance in context value using // definition by John Maxwell. // // Rule 7: IF [a sonority is not tertian] OR [it is accented AND dissonant AND // the next sonority is tertian AND the next sonority has a lower // tertian-dissonance level] OR [it is unaccented AND dissonant AND the last // sonority is tertian AND the last sonority has a lower tertian-dissonance // level], THEN the sonority is dissonant in context. // #define DISSIC_UNDEFINED -1 #define DISSIC_YES 0 #define DISSIC_NO 1 int measureDissic(int line, Array& soncondis, Array& tertian, Array& terdis, Array& accent) { int i; // case 1: IF a sonority is not tertian, THEN the sonority is dissonant // in context. if (tertian[line] == TERTIAN_NO) { return DISSIC_YES; } // case 2: IF a sonority is accented AND dissonant AND the next // sonority is tertian AND the next sonority has a lower tertian-dissonance // level, THEN the sonority is dissonant in context. int nextdislevel = -1; int nexttertian = -1; for (i=line+1; i0; i--) { if (tertian[i] != TERTIAN_UNKNOWN) { lastterdis = terdis[i]; lasttertian = tertian[i]; break; } } if ((accent[line] == ACCENT_NO) && (soncondis[line] == DISSONANT_VERTICAL) && (lasttertian == TERTIAN_YES) && (lastterdis < terdis[line])) { return DISSIC_YES; } return DISSIC_NO; } ////////////////////////////// // // measureNoteDissonance -- determine if note is dissonant using // rules by John Maxwell. // // Rule 8: IF a note is in a vertical that is both "dissonant" and // "dissonant in context," AND the note formas a dissonant interval with // another note in the vertical, AND the vertical is accented, AND the // note is note continued or repeated in the next vertical, THEN the note // is a dissonant note. // // Rule 9: IF a note is in a vertical that is both "dissonant" and // "dissonant in context", AND the note forms a dissonant interval // with another note in the vertical, AND the vertical is unaccented, AND // the note is not continued or repeated from the previous vertical, THEN // the note is a dissonant note. // #define NOTEDISSONANT_UNKNOWN -1 #define NOTEDISSONANT_YES 0 #define NOTEDISSONANT_NO 1 int measureNoteDissonance(int line, HumdrumFile& score, int note, Array& soncondis, Array& accent, Array& dissic) { if (score[line].getType() != E_humrec_data) { return NOTEDISSONANT_UNKNOWN; } if (note == E_base40_rest) { return NOTEDISSONANT_UNKNOWN; } // remove octave information from note: note = note % 40; int dissintervalQ = 0; int interval; Array notes; score.getNoteList(notes, line, NL_PC | NL_FILL | NL_SORT | NL_UNIQ | NL_NORESTS); int i, j; for (i=0; i nextnotes; nextnotes.setSize(0); int nextline = line+1; while ((nextline < score.getNumLines()) && (score[nextline].getType() != E_humrec_data)) { nextline++; } int noteinnextQ = 0; if (nextline < score.getNumLines()) { score.getNoteList(nextnotes, nextline, NL_PC | NL_FILL | NL_SORT | NL_UNIQ | NL_NORESTS); noteinnextQ = 0; for (i=0; i lastnotes; lastnotes.setSize(0); int lastline = line-1; while ((lastline > 0) && (score[lastline].getType() != E_humrec_data)) { lastline--; } if (lastline > 0) { score.getNoteList(lastnotes, lastline, NL_PC | NL_FILL | NL_SORT | NL_UNIQ | NL_NORESTS); noteinlastQ = 0; for (i=0; i& notediss) { int i; for (i=0; i& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& notediss) { int i; if (appendQ) { for (i=0; i& notes) { if (notes.getSize() < 2) { return; } int note = notes[0]; int i; for (i=0; i