// // Programmer: Craig Stuart Sapp // Creation Date: Wed Nov 22 18:42:05 PST 2000 // Last Modified: Wed Nov 22 18:42:09 PST 2000 // Filename: ...sig/doc/examples/all/arto/arto.cpp // Web Address: http://sig/doc/examples/all/arto/arto.cpp // Syntax: C++ // // Description: reduces chordal textures to their unembellished forms. // #include "humdrum.h" #include #include #include #define NOTEDISSONANT_UNKNOWN -1 #define NOTEDISSONANT_YES 0 #define NOTEDISSONANT_NO 1 typedef Array notearray; // function declarations int displayChord(HumdrumFile& infile, Array& chord, int line); void generateReduction(HumdrumFile& infile, Array& chord); double getChordDuration(HumdrumFile& infile, Array& chord, int line); void printNewDuration(const char* kern, double duration); 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, Array& chord, Array& cq); 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 measureChordQuality (int line, HumdrumFile&score, Array& notediss, Array& cq); int measureChordFunction1 (int line, HumdrumFile& score, Array& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& cq); int measureChordFunction2 (int line, Array& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& cq); void printAnalysis (HumdrumFile& infile, Array& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& notediss, Array& chord, Array& cq); 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; double beatduration = 1.0; /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { HumdrumFile infile; Array soncondis; Array tertian; Array terdis; Array accent; Array dissic; Array notediss; Array chord; Array cq; // 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& chord) { int i; for (i=0; i& chord, int line) { double duration = 0.0; int i; if (chord[line] == 'c') { duration = getChordDuration(infile, chord, line); for (i=0; i& chord, int line) { double output = 0; output += infile[line].getDuration(); int i; for (i=line+1; i= 0; i--) { if (chord[i] == 'c') { break; } if (chord[i] == 'n') { output += infile[i].getDuration(); } if (chord[i] == 'g') { break; } if (chord[i] == 'p') { break; } } return output; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // checkOptions -- validate and process command-line options. // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("a|append=b", "append analysis to data in output"); opts.define("C|compound=b", "don't try to use compound meters"); opts.define("debug=b", "trace input parsing"); opts.define("author=b", "author of the program"); opts.define("version=b", "compilation information"); opts.define("example=b", "example usage"); 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, Nov 2000" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: Nov 2000" << endl; cout << "compiled: " << __DATE__ << endl; cout << HUMDRUM_VERSION << endl; exit(0); } else if (opts.getBoolean("help")) { usage(opts.getCommand()); exit(0); } else if (opts.getBoolean("example")) { example(); exit(0); } debugQ = opts.getBoolean("debug"); appendQ = opts.getBoolean("append"); if (opts.getBoolean("compound")) { compoundQ = 0; } else { compoundQ = 0; } } ////////////////////////////// // // example -- example usage of the maxent program // void example(void) { cout << " \n" << endl; } ////////////////////////////// // // generateAnalysis -- // void generateAnalysis(HumdrumFile& infile, Array& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& notediss, Array& chord, Array& cq) { soncondis.setSize(infile.getNumLines()); tertian.setSize(infile.getNumLines()); terdis.setSize(infile.getNumLines()); accent.setSize(infile.getNumLines()); dissic.setSize(infile.getNumLines()); notediss.setSize(infile.getNumLines()); cq.setSize(infile.getNumLines()); chord.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& notediss, Array& cq) { Array notes; score.getNoteList(notes, line, NL_NOPC | NL_FILL | NL_NOSORT | NL_NOUNIQ | NL_NORESTS); cq[line] = Convert::noteSetToChordQuality(notes); if (cq[line].getType() != E_unknown) { return; } // try getting rid of dissonant notes to see if a chord can be found: Array testnotes; testnotes.setSize(0); score.getNoteList(testnotes, line, NL_NOPC | NL_NOFILL | NL_NOSORT | NL_NOUNIQ | NL_RESTS); if (testnotes.getSize() == 0) { return; } int restcount = 0; 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; } ////////////////////////////// // // 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. // 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& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic, 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() >= beatduration)) { return 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; } // 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; } // 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] == TERTIAN_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; } return CHORD_UNKNOWN; } ////////////////////////////// // // measureChordFunction2 -- apply rules 28 through 36 to identify // chord and non-chord sonorities. // int measureChordFunction2(int line, Array& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& cq) { // 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. // 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; } ////////////////////////////// // // displayNoteDiss -- display the note dissonance determinations // void displayNoteDiss(Array& notediss) { int i; for (i=0; i& soncondis, Array& tertian, Array& terdis, Array& accent, Array& dissic, Array& notediss, Array& chord, Array& cq) { int i; if (appendQ) { for (i=0; i& notes) { if (notes.getSize() < 2) { return; } int note = notes[0]; int i; for (i=0; i