Melody harmonization


Now that Whole-Play is harmony aware, it's time to give it some useful skills, starting with how to harmonize a melody. For now I'm focusing on adding a single voice. I can add more than one voice but each process is independent, so the results might be a bit unpredictable.

The issue of harmonization gets interesting if you try to devise generic approaches. In particular, I might or not have a harmonic context. And the original melody might or not fit into that harmonic context. So far I've come up with various approaches to create different types of harmonizations, I think the best way to discuss this will be with an example.

The original melody

Here's a little melody to test the various harmonization styles:

The original melody169.12 KB


#1: Parallel strict

This was the easy one to implement: a parallel melody separated by a fixed interval. What a basic pitch shifter would do. For example, a major third above:

Parallel strict173.92 KB

A major third above.



Of course this ignores any harmonic context. But hey, I love this kind of harmony, as simple as it is, so I'm sure I'll be using it often.

#2: Parallel within harmony

The natural next step was to implement parallel harmonizations within a specific harmonic context. For example, here's a third above within C Dorian (which the original melody fits in).

Parallel third in matching harmony176.42 KB

3rd above in C Dorian. All notes of the original melody are within this harmony.


harmonizer.parallelWithHarmony(C_Dorian, 2)

This gets interestingly complex to implement. For example, what if the original melody does not fit the harmonic context? My first approach has been to skip any notes that don't belong to the harmony, which is a bit of a clumsy effort (and I will certainly improve on this later on). For example, this is a parallel third but in G Major. Any notes in the original melody that don't belong to G Major are ignored.

Parallel third in non-matching harmony176.68 KB

A 3rd above in G Major: now some of the notes in the original melody are not in the harmony, and are simply bypassed (for now).


harmonizer.parallelWithHarmony(G_Ionian, 2)

But it gets even more complex if one considers an arbitrary harmonic context. For example, what if I want to harmonize with a pentatonic scale? Here's the same technique but with G Pentatonic Minor. Here a "third" doesn't really mean a third, it means "jump two notes up the scale". Again, any notes in the original that are not found in the scale are ignored.

Parallel 'third' in arbitrary harmony176.62 KB

Now the harmony (G Pentatonic minor) is not a diatonic scale, so "third" means "jump two notes up in the scale".


harmonizer.parallelWithHarmony(G_PentatonicMinor, 2)

This approach would work on any harmonic context, no matter how dissonant and irregular it is. Of course that doesn't mean the results will be good, it just means, well, that there will be results. :) Still have to play around with this to explore how it works in less standard scenarios.

#3: Mapped harmonizations

I wanted to find other ways to create harmonizations, in particular avoiding parallel movement. One of my ideas has been mapped harmonizations. What this means is that I create a map between each pitch-class and a matching pitch-class. For example:

C->G, C#->G, D->G, D#->C, E->C, F->A, F#->C, G->C, G#->C, A->G, A#->C, B->G

A harmonization using this map will generate a melody sticking to these pairings (with some melodic coherence, although that'a bit crude right now, another area with lots of room for improvement). Something like:

Mapped172.75 KB



#4: Weighed harmonizations

My last approach for now is what I've called weighed harmonizations. This technique defines a set of preferred intervals, a set of alternative intervals, and a set of backup intervals. The harmonizer will then use the preferred intervals (in a harmonic sense) most of the time, occasionally the alternative intervals, and only use the backup intervals if it can't use any of the previous ones (which might happen due to the melodic profile).

Additionally I can set the maximum jump allowed in the harmonized melody, and if I want it to use a specific harmonic context. When a harmonic context is provided, the harmonizer will try to use the given intervals but sticking to notes in that harmonic context.

That was a bit of a (confusing) mouthful, here's a few examples:

Weighed consonant173.41 KB

Here the chosen intervals (notated as number of semitones) are:

  • Preferred: 3, 4, 7 (minor and major third, perfect fifth)
  • Alternative: 8 (minor sixth)
  • Backup: 5 (perfect forth)


But no harmony is specified, so the harmonization will be free (and probably not particularly tonal).

harmonizer.weighed([3,4,7], [8], [5])

Weighed consonant within harmony171.94 KB

Same as above, but sticking to C Dorian. Now the result is controlled in terms of harmonic context. Well, at least the harmonized melody, the original might or not be in that harmony.


harmonizer.weighed([3,4,7], [8], [5], C_Dorian)

Weighed dissonant174.44 KB

Here I've chosen dissonant intervals, specifically:

  • Preferred: 2, 6, 10, 11 (major 2nd, augmented 4th, minor/major 7th)
  • Alternative: 1 (minor 2nd)
  • Backup: none


Results get interesting. :)

harmonizer.weighed([2,6,10,11], [1], null)

Weighed dissonant within harmony173.72 KB

Same as the previous dissonant example, but sticking to notes in G Major.


harmonizer.weighed([2,6,10,11], [1], null, G_Ionian)

Some combinations

As I pointed out at the beginning, I can add multiple harmonizations to a melody, but each one will be independent from the others. I'm sure at some point I will tackle multi-part harmonizations, but for now I'm happy with two, and in fact if chosen wisely, combinations can be interesting. Here's a couple of samples:

Combination #1176.38 KB

Here's a combination of:

  • A 3rd above in C Dorian
  • A mapped harmonization below (see mapped example a bit before)


The two added melodies are not related. They are both created in relation to the original melody but independently of each other. Still the result can be more or less controlled, depending on the styles of harmonization used.

Syntax might be a bit abstract unless you've used Chuck before:

harmonizer.parallelWithHarmony(C_Dorian, 2) @=> WPMotif m1;
harmonizer.mapped() @=> WPMotif m2;
harmonizer.setPosition(WPHarmonizer.POSITION_BELOW); // for mapped
spork ~ lead.playMotif("original");
spork ~ lead.playMotif(m1);
spork ~ lead.playMotif(m2);

Combination #2189.74 KB

Of course we all know Tonal Is Boring ;), so here we go:

  • A parallel major 3rd above
  • A parallel major 7th above
  • A weighed harmonization below (using dissonant intervals, like in the previous examples)


Now we're talking! :D

And the funky Chuck + WP code:

harmonizer.parallel(4) @=> WPMotif m1;
harmonizer.parallel(11) @=> WPMotif m2;
harmonizer.weighed([2,6,10,11], [1], null) @=> WPMotif m3;
harmonizer.setPosition(WPHarmonizer.POSITION_BELOW); // for mapped
spork ~ lead.playMotif("original");
spork ~ lead.playMotif(m1);
spork ~ lead.playMotif(m2);
spork ~ lead.playMotif(m3);

I don't know about you, but I find this really exciting. :)

1 comment

Add a comment

[ change image ]

PS: no links allowed in comment.

All comments


Wow! Amazing stuff Gonzalo! You are making progress in leaps and bound with the project. Love how it's sounding.

End of page. Back to page navigation.