// // Programmer: Craig Stuart Sapp // Creation Date: Mon Nov 20 17:32:36 PST 2000 // Last Modified: Mon Nov 20 17:32:39 PST 2000 // Filename: ...sig/doc/examples/all/dissic/dissic.cpp // Web Address: http://sig/doc/examples/all/dissic/dissic.cpp // Syntax: C++ // // Description: determination of dissonance in context using rules given // by John Maxwell in: // // "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 // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void example (void); void generateAnalysis (HumdrumFile& infile, Array& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic); 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); void printAnalysis (HumdrumFile& infile, Array& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic); 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; // 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) { soncondis.setSize(infile.getNumLines()); tertian.setSize(infile.getNumLines()); terdis.setSize(infile.getNumLines()); accent.setSize(infile.getNumLines()); dissic.setSize(infile.getNumLines()); infile.analyzeRhythm(); int i, j; for (i=0; i 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; } ////////////////////////////// // // printAnalysis -- // void printAnalysis(HumdrumFile& infile, Array& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic) { int i; if (appendQ) { for (i=0; i& notes) { if (notes.getSize() < 2) { return; } int note = notes[0]; int i; for (i=0; i