// // Copyright 1998-2000 by Craig Stuart Sapp, All Rights Reserved. // Programmer: Craig Stuart Sapp // Creation Date: Wed Jan 1 19:54:45 PST 2003 (extracted from HumdrumFile.cpp) // Last Modified: Wed Jan 1 19:54:59 PST 2003 // Filename: ...sig/src/sigInfo/Maxwell.cpp // Web Address: http://sig.sapp.org/src/sigInfo/Maxwell.cpp // Syntax: C++ // // Description: Harmony analysis functions based on John Maxwell's // dissertation. // #include "Maxwell.h" #ifndef OLDCPP using namespace std; #endif #define MAXWELL_ROUNDERR 0.005 ////////////////////////////// // // Maxwell::Maxwell -- // Maxwell::Maxwell(void) { // do nothing } ////////////////////////////// // // Maxwell::~Maxwell // Maxwell::~Maxwell() { // do nothing } ////////////////////////////// // // Maxwell::analyzeVerticalDissonance -- apply the rules 1 & 2 // from page 337: // // Rule 1 & Rule 2. IF a sonority consists of only one note, OR it // consists of two notes that form a consonant interval other than a // perfect fourth, OR it consists of three of more notes forming only // consonant intervals, THEN it is a consonant vertical, OTHERWISE, // it is a dissonant vertical. // void Maxwell::analyzeVerticalDissonance(HumdrumFile& score, Array& vertdis) { Array notes; vertdis.setSize(score.getNumLines()); vertdis.setSize(0); vertdis.allowGrowth(1); int analysis = 0; int line; for (line=0; line& tertian) { Array notes; int analysis; tertian.setSize(score.getNumLines()); tertian.setSize(0); tertian.allowGrowth(1); int line; for (line=0; line& notes) { if (notes.getSize() < 2) { return; } int note = notes[0]; int i; for (i=0; i& accent, int flag) { int compoundQ = flag & (0x01< (1-MAXWELL_ROUNDERR)) { fraction = 0; beat++; } if (fraction == 0) { analysis = ACCENT_YES; accent.append(analysis); } else { analysis = ACCENT_NO; accent.append(analysis); } } accent.allowGrowth(0); } ////////////////////////////// // // Maxwell::analyzeTertianDissonanceLevel -- based on the table // on page 338. Modified value for Major-minor seventh chords // // TERTIAN_UNKNOWN = -1 // TERTIAN_0 = 0 single notes // TERTIAN_1 = 1 consonant intervals, maj/min triads // TERTIAN_1_5 = 1.5 Mm seventh chords // TERTIAN_2 = 2 tritone, dim triad, mm // TERTIAN_2_5 = 2.5 incomplete mm sevenths // TERTIAN_3 = 3 aug fifth, aug triad // TERTIAN_4 = 4 1/2 dim 7, dim 7, aug 6 // TERTIAN_5 = 5 MM, M7, every thing else // void Maxwell::analyzeTertianDissonanceLevel(HumdrumFile& score, Array& terdis) { terdis.setSize(score.getNumLines()); terdis.setSize(0); terdis.allowGrowth(1); Array notes; double analysis; int line; for (line=0; line& dissic, int flag) { Array vertdis(0); Array tertian(0); Array terdis(0); Array accent(0); analyzeDissonantInContext(score, dissic, vertdis, tertian, terdis, accent, flag); } void Maxwell::analyzeDissonantInContext(HumdrumFile& score, Array& dissic, Array& vertdis, Array& tertian, Array& terdis, Array& accent, int flag) { int analysis; dissic.setSize(score.getNumLines()); dissic.setSize(0); dissic.allowGrowth(1); if (score.rhythmQ() == 0) { score.analyzeRhythm(); } // make sure dependent analyses have been done if (vertdis.getSize() != score.getNumLines()) { analyzeVerticalDissonance(score, vertdis); } if (tertian.getSize() != score.getNumLines()) { analyzeTertian(score, tertian); } if (terdis.getSize() != score.getNumLines()) { analyzeTertianDissonanceLevel(score, terdis); } if (accent.getSize() != score.getNumLines()) { analyzeAccent(score, accent, flag); } int i; int line; for (line=0; line0; i--) { if (tertian[line] != TERTIAN_UNKNOWN) { lastterdis = terdis[i]; lasttertian = tertian[i]; break; } } if ((accent[line] == ACCENT_NO) && (vertdis[line] == DISSONANT_VERTICAL) && (lasttertian == TERTIAN_YES) && (lastterdis < terdis[line])) { analysis = DISSIC_YES; dissic.append(analysis); continue; } analysis = DISSIC_NO; dissic.append(analysis); } dissic.allowGrowth(0); } ////////////////////////////// // // Maxwell::analyzeDissonantNotes -- determine if notes are // 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. // void Maxwell::analyzeDissonantNotes(HumdrumFile& score, Array& notediss) { Array vertdis(0); Array tertian(0); Array terdis(0); Array accent(0); Array dissic(0); analyzeDissonantNotes(score, notediss, vertdis, tertian, terdis, accent, dissic); } void Maxwell::analyzeDissonantNotes(HumdrumFile& score, Array& notediss, Array& vertdis, Array& tertian, Array& terdis, Array& accent, Array& dissic) { int i; Array currentnotes; if (score.rhythmQ() == 0) { score.analyzeRhythm(); } notediss.setSize(score.getNumLines()); for (i=0; i& vertdis, 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&sonrel, int flag) { Array vertdis; Array tertian; Array terdis; Array accent; Array dissic; Array beatdur; Array cq; analyzeSonorityRelations(score, sonrel, vertdis, tertian, terdis, accent, dissic, beatdur, cq, flag); } void Maxwell::analyzeSonorityRelations(HumdrumFile& score, Array&sonrel, Array& vertdis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& beatdur, Array& cq, int flag) { int debugQ = flag & (1<& vertdis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& beatdur, Array& cq) { // // preliminaries // int lastline = line - 1; while (lastline > 0 && score[lastline].getType() != E_humrec_data) { lastline--; } int nextline = line + 1; while (nextline < score.getNumLines() && score[nextline].getType() != E_humrec_data) { nextline++; } if (nextline >= score.getNumLines()) { nextline = -1; } //////////////////// // Rule 20: IF a vertical is tertian AND its duration is at least as long // as the primary beat of the meter, THEN it is a chord. if ((tertian[line] == TERTIAN_YES) && (score[line].getDuration() >= beatdur[line])) { return CHORD_CHORD; } // Rule 21: IF a vertical is tertian AND it is accented AND it is not // "dissonant in context," THEN it is a chord. if ((tertian[line] == TERTIAN_YES) && (accent[line] == ACCENT_YES) && (dissic[line] == DISSIC_NO)) { return CHORD_CHORD; } // Rule 22: IF a vertical is unaccented AND it is tertian AND the previous // vertical is tertian AND they both have the same root, THEN the vertical // is subordinate to the previous vertical. if ((accent[line] == ACCENT_NO) && (tertian[line] == TERTIAN_YES) && (lastline > 0) && (tertian[lastline] == TERTIAN_YES) && (cq[line].getRoot() >= 0) && (cq[line].getRoot() == cq[lastline].getRoot())) { return CHORD_PREVSUB; } // Rule 23: IF a vertical is accented AND it is dissonant in context AND // the next vertical is tertian, THEN it is subordinate to the next vertical, // and is not an independent chord. if ((accent[line] == ACCENT_YES) && (dissic[line] == DISSIC_YES) && (nextline > 0) && (tertian[nextline] == TERTIAN_YES)) { return CHORD_NEXTSUB; } // Rule 24: IF a vertical is unaccented AND it is not dissonant in context // AND the last vertical is dissonant in context, THEN the vertical is a // chord. if ((accent[line] == ACCENT_NO) && (dissic[line] == DISSIC_NO) && (lastline > 0) && (dissic[lastline] == DISSIC_YES)) { return CHORD_CHORD; } // Rule 25: IF a vertical is tertian AND the previous vertical is // tertian AND the previous vertical is not dissonant in context AND the // two verticals do not have the same root, THEN the vertical is a chord, // but is marked passing. if ((tertian[line] == TERTIAN_YES) && (lastline > 0) && (tertian[lastline] == TERTIAN_YES) && (dissic[lastline] == DISSIC_NO) && (cq[line].getRoot() >= 0) && (cq[lastline].getRoot() >= 0) && (cq[line].getRoot() != cq[lastline].getRoot())) { return CHORD_PASSING; } // Rule 26: IF a vertical is not tertian AND it is accented, THEN // it is subordinate to whatever chord follows. if ((tertian[line] == TERTIAN_NO) && (accent[line] == ACCENT_YES)) { return CHORD_NEXTSUB; } // Rule 27: IF a vertical is not tertian AND it is unaccented, THEN // it is subordinate to whatever chord precedes it. if ((tertian[line] == TERTIAN_NO) && (accent[line] == ACCENT_NO)) { return CHORD_PREVSUB; } // Rule 28: IF a vertical contains a suspension AND the resolution // note of the suspension can be substituted for the suspension note to // form an implied tertian vertical AND the implied tertian vertical is // more consonant than the original vertical, THEN the implied vertical // should be substituted for the suspension vertical, and is made a // chord. // Rule 29: IF a vertical is unaccented AND it is not dissonant in // context AND it is a two-voice sonority AND the previous vertical is a // two-voice sonority AND the notes of the vertical can be combined with // the notes of the previous vertical producing an implied tertian // sonority with the same root as the previous vertical, THEN the // unaccented vertical should be subordinate to the previous vertical, // and its notes can be included with those of the previous vertical. // Rule 30: IF a vertical consists of a single note from a single // voice, THEN the vertical is subordinate to the previous chord. return CHORD_UNKNOWN; } ////////////////////////////// // // Maxwell::measureChordFunction2 -- apply rules 31 through 36 to identify // chord and non-chord sonorities. These rules must be applied after // the key has been determined. // int Maxwell::measureChordFunction2(HumdrumFile& score, int line, Array& vertdis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& cq) { // Rule 31: IF a chord is in the same key as the previous chord AND // the chord has the same harmonic function as the previous chord AND // they have the same inversion, THEN the chord can be subordinated to // the previous chord. // Rule 32: IF a chord is accented AND it is followed by a chord // with a weaker harmonic strength, which is followed by a chord with the // same function as the first chord, THEN the second two chrods can be // subordinated to the first chord. // Rule 33: IF a chord is accented AND it is followed by a chord // that is unaccented AND the second chord has a weaker harmonic function // than the first, THEN the second chord is subordinate to the first. // Rule 34: IF a chord contains a suspension AND the resolution of // the suspension note can be substituted for the suspension note to // produce a chord with a greater function strength that the original // chord, THEN the new function should be substituted for the old // function. (This rule does note combine chords, but can cause other // rules to do so.). // Rule 35: IF a chord is accented AND it is on a strong beat AND // it is a six-four chord AND the next chord has the same bass note AND // the next chord is in root position, THEN the first chord is // subordinate to the second. // Rule 36: IF a chord is a two-voice chrod AND the previous chord // is accented AND the two chords are in the same measure AND the notes // of the chord can be combined with those of the previous chord without // changing the root of the previous chord, THEN the chord is subordinate // to the previous chord. return CHORD_UNKNOWN; } // md5sum: 88665f25708fe42976fcc0653f777991 Maxwell.cpp [20050403]