In the previous tutorial on melody we created a simple melody.
Now we will learn to combine it with harmonies.
For this we will learn how to use harmony, chord and inversion attributes of the entities.
Table of Contents
• • • •
Each entity has the chord attribute which controls how many notes are actually played.
So instead of playing the default single note, you may play the whole triad.
function Main()
{
@chord = Chord.Triad;
}D♭ offers a finer control of the notes played. Similarly as in the previous examples,
they are indexed relative to the base pitch of this entity. So you can write the triad as
[0, 2, 4]. Integer arrays can be implicitly cast to chords and interact with them.
A single integer n behaves like an array [n]. Collection expressions (new in C# 12)
make the notation short and simple.
function Main()
{
@chord = [0, 2, 4]; //triad
}The default chord for each entity is [0].
You can freely add and remove one or more chord tones from the chord using + and -.
function Main()
{
@chord += [2, 4]; //still a triad
}function Main()
{
@chord = Chord.Triad + 7; //a triad with an octave added
}function Main()
{
@chord = Chord.Triad + 7 - 2; //a triad with an octave added and the third removed
}Chords can be inverted in both directions. Positive inversions increase the lowest chord tone (bass)
by an octave so that it becomes the highest tone of the chord. For larger chords several octave steps
may be necessary. Positive inversions can be imagined on a keyboard like rotations to the right.
Vice versa, a negative inversion decreases the highest tone of the chord by one or more octave steps
so that it becomes the lowest tone of the chord. Negative inversions imagined on a keyboard
are like rotations to the left. The default value of inversion is 0.
function Main()
{
@span = 4;
@chord = Chord.Triad;
@Split(4).Then(idx => @inversion = idx.Index);
}One of the simplest functional progressions in Western tonal music alternates between tonic and dominant.
We can easily create such a progression with the help of the modulo operator % to distinguish between even and odd entities.
function Main()
{
@span = 16;
@chord = Chord.Triad;
@Split(8).Then(idx => @harmony = idx.Index % 2 == 0 ? 0 : 4);
}We may use a random choice to place the dominant either above or below the tonic.
function Main()
{
@span = 16;
@chord = Chord.Triad;
@Split(8).Then(idx => @harmony = idx.Index % 2 == 0 ? 0 : @Rnd.Choice(4, -3));
}Notice that the two dominant options are in fact three inversions away. We can also include the two inversions in between that are not in the root form.
function Main()
{
@span = 16;
@chord = Chord.Triad;
@Split(8).Then(idx => @harmony = idx.Index % 2 == 0 ? 0 : -3);
if (@harmony != 0)
@inversion = @Rnd.Int(0, 2);
//instead you can also apply inversions to both chords
//@inversion = @Rnd.Int(0, @harmony == 0 ? 1 : 2);
}Note that you could exchange harmony for degree and the result would sound just the same.
This is because in fact degree stands for a degree in a harmonic function.
So in C major @harmony = 0; @degree = 2; stands for E but @harmony = 4; @degree = 2; is interpreted as B.
You see that if one of them is zero, the other one fully takes over.
D♭ put no restrictions on the pair of attributes.
It is up to the composer to deal with them in a semantically correct way.
The following example shows a combination of harmony and degree.
The result is a simple ostinato build on top of the harmony. The relative
degrees of the ostinato always stay the same, but the harmonic progression
shifts them according to the current harmonic function.
var progression = [ 4, 1, 2, 0 ];
var ostinato = [ 7, 4, 2, 0 ];
function Main()
{
@span = progression.Length * 4;
@Split(2);
@Split(progression.Length).Then(idx => @harmony = progression[idx.Index]);
@Split(4);
@Split(ostinato.Length).Then(idx => @degree = ostinato[idx.Index]);
}We may also develop the ostinato idea using chords. It is better to increase the overall duration as playing chords as fast as in the previous example would be very difficult.
var progression = [ 4, 1, 2, 0 ];
var ostinatoChord = [ Chord.Triad + 7, Chord.Triad - 0, Chord.Dyad, Chord.Triad - 0 ];
function Main()
{
@span = progression.Length * 3;
@Split(progression.Length).Then(idx => @harmony = progression[idx.Index]);
@Split(4);
@Split(ostinatoChord.Length).Then(idx => {
@chord = ostinatoChord[idx.Index];
if (!idx.IsFirst) @velocity *= 0.8;
});
}Arpeggio decomposes a chord into single-note entities.
Each chord tone becomes the degree of one output entity. An arpeggio on a triad (0,2,4) results
in three entities (0),(2),(4). In fact they all become (0) with degree attributes
adjusted accordingly.
function Main()
{
@span = 16;
@chord = Chord.Triad;
@Split(8).Then(idx => @harmony = idx.Index % 2 == 0 ? 0 : 4);
@Arpeggio();
}The arpeggio portion can be specified to be shorter so that the chord sounds longer.
function Main()
{
@span = 16;
@chord = Chord.Triad;
@Split(8).Then(idx => @harmony = idx.Index % 2 == 0 ? 0 : 4);
@Arpeggio(0.3);
}A similar effect can be also achieved with a Split but there the notes will no longer overlap.
A parameterless Split divides notes in a chord so that they will be played
as in ostinato one after each other. If the chord contains less than two notes,
no operation is performed.
function Main()
{
@span = 16;
@chord = Chord.Triad;
@Split(8).Then(idx => @harmony = idx.Index % 2 == 0 ? 0 : 4);
@Split();
}Let us now repeat the progression example with the Arpeggio added. Note that it must be
applied as last, as it breaks the chords into single-note entities and inversions would
have no effect on single-note entities.
function Main()
{
@span = 16;
@chord = Chord.Triad;
@Split(8).Then(idx => @harmony = idx.Index % 2 == 0 ? 0 : -3);
if (@harmony != 0)
@inversion = @Rnd.Int(0, 2);
@Arpeggio(0.1);
}We can now create a more complex progression randomly. We will still start on the tonic and end on the dominant.
function Main()
{
@h = new [] {
0,
@Rnd.Int(1,2),
@Rnd.Choice(1,3,5),
4
};
@span = 16;
@chord = Chord.Triad;
@Split(8).Then(idx => @harmony = @h[idx.Index % @h.Length]);
if (@harmony != 0)
@inversion = @Rnd.Int(-2, 2);
@Arpeggio(0.3);
}Random generation of harmonies can easily get out of control when too much of randomness is involved. Maybe some of the examples you just heard sounded awkward every now and then. Chords of a progression usually obey several rules, or better said constraints. D♭ supports generation of melodies, harmonies and rhythms by means of constraint programming. These advanced topics will be discussed in a later chapter.
Harmonies presented here are composed only of diatonic pitches from the current key. In the next tutorial you will learn how to switch between keys and modes to gain access to the full range of chromas.
D♭ Tutorials — Basic
D♭ Tutorials — Intermediate
D♭ Reference
D♭ Examples
Links