CreateDigitalMusic.com recently posted this video. Though the focus is on Live Coding, what jumped out was this comment on the syntax of Lisp:
“Rule number 1. Everything is a list. Rule number 2. Some lists are functions in which the first item of the list is a function name and the remaining items are parameters. You have now learned the entire syntax of Lisp.”
This is a bit of a revelation to me. Too be honest, I’ve sort of avoided lisp for the most superficial of reasons; There are just to many parenthesis.
And now that my mind is open again, I’m going to take a serious look into Lisp and especially Impromptu. I’m not saying that I’m shifting from a Python-based environment to a Lisp-based system, only that I will continue to remain open to other possibilities.
Now that I have the basic Markov engine happening, it’s play time. Instead of a simple three node chain, today’s example has eight. And each node does not lead to every other node, which adds a layer of melodic phrasing.
Nothing more to say really, other than it’s time for me to start working on my orchestrations to make these things sound more musical than these tech demos.
What is a Markov chain? According to wikipedia, “A Markov chain is a discrete random process with the property that the next state depends only on the current state.”
This Markov melody starts with state_0, playing an E-flat for an 8th note duration. A new state is then chosen for the next course of action. There is an equal chance (1 in 3) that state_0, state_1 or state_2 will be chosen. Assuming state_2 is selected, G below middle C is played for a 16th note duration. From state_2, there is a 1 in 10 chance state_0 will be chosen at random, 2 in 10 chance for state_1, and a 7 in 10 chance for state_2. I’m guessing you can figure out state_1. This chain plays until time runs out.
Though there are various ways of creating Markov chains in Csound, I landed on this design, which utilizes Csound instruments as Markov nodes. My first draft used a lot of gotos and jumps, which has its place, but I really wanted to encapsulate each state in it’s own block of code. Instruments do the trick, though I believe user-defined opcodes would work as well. Node connections, along with their weighted probabilities, are defined as f-tables in a centralized block of code in the global space of the orchestra; This allows a user to quickly change the probabilities, and to quickly create/modify new Markov networks.
In order to allow multiple instances of the Markov melody to play simultaneously, I’ve equipped each running Markov thread with a string identifier. You can hear two chains playing in the last 4 bars, with the second chain offset by a 32nd note.
In a piece like this, finding the correct balance of randomly generated parameters can be a bit tricky. At least for me. If the music has a tendency to remain too similar for long periods of time, everything becomes blah. On the other hand, subtlety and nuance are decimated from too much too fast. I personally enjoy a blend of semi-frequent sonically interesting interruptions that jump from a monotonous trance-inducing track.
Did I accomplish this with this track. Somewhat. I’m also training to force myself to work faster in Csound. For practice, I’m rushing things out. I can always revisit the piece later.