The Harmony Program
The harmony program produces an analysis of the piece divided into segments, labeled with roots. It also chooses a spelling for each pitch-event in the input file.
As input, the program requires a "note list", as well as a "beat list"; see the meter program page for explanations of these. (Why the beat list is needed will be explained below.) To create the appropriate input format, we recommend running a notefile through the meter program first, then using that to generate both the note list and the beat list, which can then be piped into the harmonic analyzer. (This too is explained further below.)
In forming its harmonic analysis, the program treats beats at the lowest level of the metrical structure as indivisible units. (Each unit extends from one lowest-level beat to the next lowest-level beat.) Thus its job is to choose a root for each such unit. Also, for the purposes of computing its analysis, it adjusts the notes of the input so that each note begins and ends on a beat. (In general, it does this by shifting each note-onset and each note-offset back to the nearest previous beat. In cases where this would result in shifting both the onset and offset back to the same beat, thus giving the note a duration of zero, it instead shifts the offset forward to the following beat.)
The harmonic analyzer has several criteria for choosing the best harmonic analysis. It prefers an analysis such that the root of each segment is compatible with the pitches in the segment. The program has information about how compatible each pitch-class is with each root. If a pitch is not compatible with the chosen root - it is then an "ornamental dissonance" - it is preferred that it be closely followed by another event a half-step or whole-step away in pitch. The program prefers roots such that nearby roots are close together on the "line of fifths": this is similar to the circle of fifths, except extending infinitely in either direction, so that distinctions are made between different spellings of the same pitch (such as Ab versus G#). (We call these spellings "tonal-pitch-classes".) And it prefers to have changes of harmony on strong beats of the metrical structure (this is why metrical information is needed as input).
In choosing a spelling for each pitch, the program in effect maps each event on to the line of fifths. In so doing, it prefers a spelling so that nearby pitch-events are close together on the line of fifths. The program also takes spelling into account in the harmonic analysis, so that pitch spelling and root choices influence one another. And it considers "voice-leading": it prefers to avoid cases where two notes a half-step apart are spelled as a chromatic semitone, e.g. G#-G (particularly when the first note of the pair is chromatic in context, that is, far from other events in the vicinity on the line of fifths).
The output of the harmonic analyzer for the ending of "Yankee Doodle" looks like this:12005 x x x x x C <E > + 12110 x C < > | 12250 x x C < > | 12390 x C <F#> + 12495 x x x C <E > + 12600 x C < > | 12740 x x C <D > + 12845 x C < > | 12985 x x x x C <E > + 13125 x C < > | 13265 x x C <F#> + 13370 x C < > | 13510 x x x C <G > + 13615 x C < > | 13755 x x C <E > + 13860 x C < > | 14000 x x x x x G <D > + 14105 x G < > | 14245 x x G <G > + 14350 x G < > | 14490 x x x D <F#> + 14595 x D < > | 14735 x x D <A > + 14875 x D < > | 15015 x x x x G <G > + 15120 x G < > | 15260 x x G < > | 15365 x G < > | 15505 x x x G <G > + 15610 x G < > | 15750 x x G < > | 15855 x G < > |
The timepoints and metrical grid at the left-hand side simply represent the information that was outputted by the metrical program, and inputted to the harmonic program. To the right of that is the harmonic analysis itself. For each lowest-level beat, the harmonic analyzer's choice of root for that segment is shown. (Remember the analyzer treats lowest-level beats as implying indivisible segments.) To the right of that, the pitch-events in each segment are shown. Each pitch-event is indicated by its spelling, in the segment in which the pitch-event begins. (If the pitch-event does not begin exactly on a beat, it is marked with a "*".) To the right of that, the pitch-events are shown according to their location on the line of fifths. An "+" indicates that a pitch-event begins at that segment; a "|" indicates the continuation of an event. If more than one pitch-event of the same tonal-pitch-class is present in a segment, the symbols "2", "3", etc. are used, as appropriate.
To run the harmonic program alone, enter the "harmony" directory and typeharmony [input-file]
Remember that the input file must contain a beat list as well as a note list. To use the meter program to generate the appropriate input file, you can use the pipe command as follows. (For this to work, you should be in the parent directory of the meter and harmony directories.)meter/meter [input-file] | harmony/harmony
Parameters. Here are the user-settable parameters for the harmony program.
verbosity=1 The amount of information outputted by the program. With verbosity=0, it outputs just a list of beat statements, chord statements, and TPCNote statements. A beat statement has the form "Beat [time] [level]", just like that outputted by the meter program. A chord statement has the form "Chord [start-time] [end-time] [root]"; a TPCNote statement has the form "TPCNote [start-time] [end-time] [pitch] [TPC]". This is the input required by the key program. Roots and TPC's are indicated by their line of fifths position. For this we use the following convention:With verbosity=1, the program outputs the list of beats, chords, and TPCNotes, as well as the graphic display described above. With verbosity=2, it outputs much other information....-2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 ... ... Ab Eb Bb F C G D A E B F# C# G# D# A#... pruning_cutoff=10.0 The analyzer processes a piece in a left-to-right fashion. At each point, it is in effect generating a large number of possible analyses of the piece up to that point. The pruning_cutoff tells it that it should discontinue any analyses whose score is more than this value below the highest-scoring analysis. Having a higher pruning_cutoff speeds up the program, but may also risk overlooking the overall optimal analysis. compat_values=-5.0 -5.0 0.0 1.0 -3.0 0.0 5.0 3.0 0.0 0.0 2.0 0.0 These "compatibility values" determine the scores contributed by a pitch-event to the current root, depending on the relationship between them. The twelve positions in the statement correspond to pitch-root relationships listed in line-of-fifths order: b5, b2, b6, b3, b7, 4, 1, 5, 2, 6, 3, 7. For example, the value for b5 is -5.0; this means that, given a root of C, the pitch Gb (b5 of C) will contribute a score of -5.0 (per second) to the score. If the value for a relationship is 0.0, that means the relationship is "ornamental"; no compatibility score is contributed, and ornamental dissonance penalties apply (see below). compat_factor=1.0 This factor multiplies the "compatibility scores" explained above. tpc_var_factor=0.3 The weight of tpc variance - the preference for spelling pitch events as close together on the line of fifths - relative to the other harmonic rules. har_var_factor = 0.3 The weight of the harmonic variance rule - the preference to keep roots of nearby segments close together on the line of fifths - relative to the other rules. half_life=2.0 The harmonic variance penalty contributed by a segment depends on how far its root is from the current harmonic "center of gravity" on the line of fifths. The center of gravity is a weighted mean of the roots of all previous segments, under an exponential curve. This value determines the half life of the curve. The same curve is used to calculate pitch variance; here, the center of gravity is a weighted mean position of all previous pitch events. odp_linear_factor = 3.0 An ornamental dissonance is a note which is not a chord tone relative to the current root. Each ornamental dissonance carries a penalty depending on its stepwise inter-onset interval (SIOI): the time interval between its onset and the onset of the next event a half-step or whole-step away in pitch. The penalty has the form: (odp_quadratic_factor * SIOI^2) + (odp_linear_factor * SIOI) + odp_constant. odp_quadratic_factor=1.0 See odp_linear_factor above. odp_constant=2.0 See odp_linear_factor above. sbp_weight=2.0 If the root of a chord-segment in an analysis differs from that of the previous segment, it contributes a penalty depending on the "beat interval" of the beat it starts on: the time interval between that beat and the previous beat at that level. The penalty takes the form (sbp_weight * beat interval) - sbp_constant. sbp_constant=1.5 See sbp_weight above. voice_leading_penalty=3.0 Each pitch-event which is more than four steps below the current pitch center of gravity on the line of fifths, and which is closely followed in time by another event which is a half-step above in pitch, contributes a penalty of this value. Similarly, events which are more than four steps above the current pitch center of gravity, closely followed in time by another event a half-step below in pitch, contribute this penalty. voice_leading_time=1.0 This value determines how close an event's onset must be to another event's onset in order to be considered "closely following" in the voice-leading rule (see "voice_leading_penalty" above). print_beats=1.0, print_chords=1.0, print_tpc_notes=1.0 These control whether beat, chord and TPCNote statements are printed out. When each parameter is set to one, the corresponding statement type will be printed. prechord_mode=0 This is used in the special "two-pass" way of running the analyzer (see Section 4 below). In prechord mode, the analyzer outputs only the list of the notes that was inputted, along with a list of "prechords" indicating points of harmonic change. round_to_beat=0 For the purposes of computing the harmonic analysis, the analyzer adjusts the notes to be perfectly aligned with beats; this parameter determines how this is done. When round_to_beat = 0, each note onset and offset is adjusted back to the previous beat (unless this would mean adjusting both the onset and offset to the same beat; then, the offset is moved to the following beat). If round_to_beat = 1, then each timepoint is adjusted to the nearest beat.