This attraction demonstrates the use of a computer program to solve problems in musical voice-leading. When I say that this program is “intelligent” I simply mean that it applies techniques drawn from Artificial Intelligence — for example, in the early chess-playing and theorem-proving programs by Simon and Newell. I consider the level of expertise to be superior to that of first-year students of musical theory realizing figured-bass examples. Such students might indeed benefit from understanding how this program goes about attacking the problem, since the approach is modeled on human behavior.
I should acknowledge that the more difficult problem of harmonizing a melody was previously addressed in CHORAL, a program by Kemal Ebcioğlu who had been my colleague at the Statue University of New York at Buffalo during the late 70's and early 80's. I am not familiar with the inner workings of CHORAL, but I do know that Kemal's program succeeded in duplicating J.S. Bach's own harmonization on at least one instance.
I first developed this approach presented here as a proof of concept during the early 1980's. It was submitted to the Computer Music Journal and rejected for reasons having to do with the “hierarchy of voices”. (I still have no idea what that means.) I later put the approach to work for the Cybernetic Composer, generating background chords for the ragtime style.
The Intelligent Part Writer implements the structure shown in Figure 1. There are three top-level component types: Chords, Parts, and Voicings. Chords contain Tones (up to seven), while Voicings contain Notes (one per Part). The collection of Voicings comprises a sequence, where the duration of one Voicing determines the starting time of its successor. Chords, Tones, Parts, and Voicings are all configurable using the graphic editor. Notes are not configurable, since the whole point is for the computer to select pitches for Notes.
Expressed in the jargon of my production framework,
A Chord is a collection of Tones. Each tone is described by six attributes:
How tones behave depends entirely on how chords are configured in the input file.
Partwriter-Example.xml file defines seven Chords:
“A Minor 7th”,
“A Dominant 7th”,
“G Dominant 7th”,
“E Minor 7th”,
“F Major”, and
“D Minor 7th”.
All of the chords in this example designate chord-roots as bass tones. This is however, not required. As an alternative, one could define a second-inversion chord named “C Major/G”, with the same degrees as in Table 1-1, but with G designated as the bass tone and C specified with DOWNWARD tendency and OBLIGATORY urgency.
Partwriter-Example.xml file defines four Parts. The Parts and their attributes are
detailed in Table 2.
|ID||Name||Clef||Low Pitch||High Pitch||Bass Part||MIDI Program||MIDI Velocity|
Partwriter-Example.xml file defines a progression of nine Voicings. The Voicings and their attributes are
detailed in Table 3.
|2||A Minor 7th|
|4||G Dominant 7th|
|5||E Minor 7th|
|6||A Dominant 7th|
|7||D Minor 7th|
|8||G Dominant 7th|
|9||C Major 7th|
Figure 2 charts the flow of the Heuristic Search decision engine. Although the flow chart looks daunting, but it is actually familiar to any music student who has ever tackled a part-writing exercise.
As stated previously, a decision services a Note, while the options are pitches. I want to draw your attention to four particular elements of this flowchart:
I have appropriated the word production to indicate a procedure which nominates pitches to be considered for a
production comes from Noam Chomsky's generative grammars. I hope to justify this
appropriation in a future attraction blending searches with grammars.)
If the note's Part is other than the bass line, the productions take all the chromatic
steps in the Part's range and filter these down to chord tones. For the bass line, the productions take
only the chromatic steps that correspond to the bass Tone. All this happens at initialization time,
before any decisions are evaluated.
The filtering process just described is different from what happens with constraints
If a pitch fails a constraint, the search can go back to the source of conflict and make a change.
Filtered-out pitches are wrong no matter what the search does.
The constraints imposed by the part-writing engine adapt the “Music Theory Rules” first identified by Renaissance theorists such as Gioseffo Zarlino; these rules also governed the realization of a figured bass during the Baroque period. As the Part-Writer considers pitches for notes, it identifies constraint issues in a Violations list near the bottom of the screen. Clicking on the constraint name shows you which notes are involved.
Four of the constraints enforce Tone behaviors already described. These constraints may be selectively disengaged by substituting more permissive Tone attributes.
The remaining constraints enforce behaviors that are independent of Tone. These constraints may be engaged or disengaged using check boxes in the document attributes panel.
If you have experienced part-writing, you are familiar with coming to an impasse with no recourse but to go back and change earlier decisions. The flow-chart shown in Figure 2 accommodates impasses in the same way. When a particular decision has exhausted all available options, the engine is capable of retreating to an earlier decision and taking up the next option in this earlier decision's schedule. The ability to revise earlier decisions is called backtracking. Backtracking is an essential technique from artificial intelligence. It transforms a simple process of selection into a search that continues until one of two outcomes have been reached:
The second, negative outcome is possible because once the search has rejected a certain sequence of choices, it never reattempts that sequence.
The discussion of backtracking now becomes technically complicated without providing further musical insight. You may wish to skip forward to the next topic, heuristics.
There are two kinds of backtracking, simple and dependency-directed. When I first became involved with AI search methods during the early 1980's, my programs used simple backtracking. In those days having your own microprocessor was a rare thing, but I had one. I needed it because sometimes my programs ran on for days. Every once in a while, I would check the display (something like the Part-Writer animation, but using characters) to verify that the run was making progress. And I could see the search failing to select a pitch for some current note due to a conflict with some previous note. Each time it failed it would back up one step, make a change, and try again. It was agony. It might take 15 minutes to work its way back to the source of conflict, which might itself be limited in the pitches it could consider. So it might go back further, work forward to the original source of conflict, and revert to the pitch that caused the problem in the first place.
Clearly some way needed to be found to backtrack directly to the source of conflict. I worked something out, then ran into my friend Kemal, and described what I was doing:
Oh yes. I do that. Its called dependency-directed backtracking. There's a famous article by Stallman and Sussman describing it.
Anyway, here's what the Intelligent Part Writer does to achieve dependency-directed backtracking:
While a graduate student at SUNY/Buffalo, I attended composition seminars with Morton Feldman. I remember Feldman priding himself upon working in ink. Certainly for Feldman the old rules don't apply, yet he was known for coming up with the right chord for the moment. Since he composed at the piano, it is likely Feldman tried out a few wrong chords before getting to the right one, yet once that chord was chosen he never changed his mind.
Backtracking is the AI equivalent of a theory student applying a pencil eraser. The very need to backtrack exposes the inefficiency of a selection process guided exclusively by rules. Pile on that the frustration of the part-writing student whose solution is graded down for being “unmusical” even though all the rules have been observed.
As the student gains experience, he or she will come to recognize in advance that some actions will lead to success and while impasse. In particular, the order in which decisions are addressed matters greatly. For example, experience quickly reveals that if one part offers a dissonance for resolution, that's the part you want to handle first. Otherwise you waste time making choices which will conflict with the resolution pitch. Taking this further, if a second part wants to satisfy a leading tone, its best chance happens when you address this second part next after the dissonance.
Procedures which influence the order by which decisions are taken, or the order by which options are considered, are called heuristics. The purpose of heuristics is to encourage good things to happen. In contrast to algorithms, which always produce correct answers (or the conclusion that no correct answer exists) heuristics enforce no rules. Rather, heuristics promote tendencies.
Implementing heuristics is simple, at least in principle: Assign a preference value to each item, then sort the items by preference. However it gets more complicated when the preference values are multidimensional. My 1992 article “Quantifying Musical Merit” delves further into ways of calculating preference values.
Heuristics apply at two levels in Figure 2:
Random.nextDouble()method; that is, to a random number which is uniformly distributed between zero and unity. ξ(n) at this point will have random digits to the right of the decimal point and zero to the left of the decimal point.
|© Charles Ames||Page created: 2013-10-16||Last updated: 2017-03-12|