Interesting Music in Four Lines of Code

One of the strengths of the Euterpea library is the ability to generate complex musical values extremely concisely. Here I’m going to walk through an example of that, the results of which I then took and turned into a more serious composition.

Here’s the motif I started with:

x1 = c 4 en :+: g 4 en :+: c 5 en :+: g 5 en

Just four notes – fifths going up an octive. Not too interesting yet. How about some transposition to add new pitch classes into the mix?

x2 = x1 :+: transpose 3 x1

An interesting thing about patterns based on fifths is that they often behave well when inverted vs. turning into an atonal mess as is the case for more complex melodies. So, why not throw in a bit of that and a retrograde as well to get some variety?

x3 = x2 :+: x2 :+: invert x2 :+: retro x2

If we play this repeated, such as play $ forever x3, it still sounds boring pretty fast. A common trick to add complexity in algorithmic work is to layer a sequence with itself at a slightly different tempo. When the tempo differences are very small, such as a <1% difference in tempo, it’s called a phase composition and the two patterns slide in and out of synchrony (phase) slowly over time. When the differences are greater, the effect is different and you get interesting textures that can be hard to identify as the same motif. Let’s layer this pattern with itself at 2/3rds its original speed to make it 1.5 times as long. This will add a lot of variation by ensuring that there are no repeats for quite a while.

x4 = forever x3 :=: forever (tempo (2/3) x3)

And there it is! Something interesting in four lines of code. In fact, it’s actually hard to tell by ear when the first repeat happens, which is after 12 measures. This is what each of these Music values looks like as a score:

This version is also an interesting variation of it, staggering the two lines just a bit rather than starting in synchrony:

x4' = forever x3 :=: (rest hn :+: forever (tempo (2/3) x3))

I used these two versions as part of a larger composition. Of course, once I got into that, things got a bit more complicated (although not much) and I needed a little more code to make the particular synth I wanted behave properly. Although the occasional overlapping and simultaneous notes of the same pitch can produce interesting accent effects with many synthesizers, it can create problems for some monosynths, like the one I was trying to use, so I needed a way to clean up those overlaps. Here’s the whole program in one place along with a playback function that merges simultaneous/overlapping identical pitches for finicky monosynths:

import Euterpea
import Control.DeepSeq -- for special playback function

x1 = c 4 en :+: g 4 en :+: c 5 en :+: g 5 en
x2 = x1 :+: transpose 3 x1
x3 = x2 :+: x2 :+: invert x2 :+: retro x2
x4 = forever x3 :=: forever (tempo (2/3) x3)
x4' = forever x3 :=: (rest hn :+: forever (tempo (2/3) x3))

playX :: (NFData a, ToMusic1 a) => Music a -> IO ()
playX = playC defParams{perfAlg = eventMerge . perform} where
    eventMerge :: Performance -> Performance
    eventMerge (e1:e2:es) =
        let e1' = e1{eDur = eTime e2 + eDur e2 - eTime e1}
        in  if ePitch e1 == ePitch e2 then eventMerge (e1':es)
            else e1 : eventMerge (e2:es)
    eventMerge e = e

Finally, add more hours, some Euterpea-inspired jamming on a keyboard, and a lot of coffee…

Leave a Reply

Your email address will not be published. Required fields are marked *