SoftStep Tutorial #10: Markov Chains

Compatibility note: This tutorial is for SoftStep Pro. If you have SoftStep Basic or SoftStep LE, then you can not create all the modules, but you can load the pre built tutorial file, and follow along with that.

With this tutorial we will attempt to demystify the highly useful Probability module, and show how it can be used to generate very flexible Markov chains. You can use Markov chains in many different ways - here we will explore how to make an "intelligent" scale that generates new notes according to the note just played.

In practical terms, a Markov chain is a set of landing points, usually called nodes, that point to some number of other nodes, with each having an assigned probability of being taken. Think of a scale in which every step generates a new note within the scale according to a set of probabilities that are "owned" by the current step.

To illustrate, think of a C-major scale as the nodes to an 8-step Markov chain. Here are the notes with note value offsets:

C=0, D=2, E=4, F=5, G=7, A=9, B=11, C=12

Now, consider F. Say, somehow, F has been selected. In a Markov chain, F has no way of knowing how it was selected, but once up to bat, it is in control of which note gets played next. Sort of, because we are dealing with probabilities here. With F, if you wanted it to next play a 3rd up most of the time, you would give F the likelihood of selecting an A to be played next a higher probability than the other scale steps. - say, 60%. Perhaps you want it to play a minor 3rd down some of the time - give the D perhaps 20%. Finally you want it to repeat every now and again, and you don't want it hitting any of the other notes at all, ever. You would give F itself perhaps 10%, and leave the other steps at 0 probability.

The good news is that every note in the chain can have its own set of probabilities as to which note is to be played next; the bad news is that you have to set up a separate table of probabilities for each note. With the SoftStep Probability module, you can use the Fill utility to set up the probability tables, so the task isn't as daunting as it might be otherwise.

Probability Demystified

The trick to understanding the Probability module is to realize that while it uses the same Page Table as the Table sequencer, its output is not the table values, but rather the table positions. That is, a Table sequencer will output the value of whatever table step (stage) it is pointing to, while the Probability module instead uses the stage values not as outputs, but to determine the likelihood of selecting that stage, and it outputs the step number itself, not the value in the step.

To illustrate this, create a MIDI Voice, a Clock, and a Probability module.


tutorial-10a.ssp

Connect both the Probability and Voice clock inputs to the Clock module output. Set the Probability lower connection input ("Select Table Number") to use page (table number) 64, which should be unused. If you are using that particular table page, then just pick another. Connect the Note input of the Voice module to the Probability output. It is likely to start the low thump sound of MIDI note 0, but don't worry if it is something else.

Now click on the Fill button on the Probability module. You should see all the sliders set to 0. If not, click on the Erase button. Now, for sure, the Voice will be running its low 0-note-value thump. Click on any one of the little sliders somewhere in the middle of the Fill graphic window. The piano should jump to a middle range tone. If it does not, then recheck your connections before going on.

Carefully, without moving any of the other sliders, adjust the slider you picked up and down. Notice that although the readout under the graphic in the Fill changes - it even gives you a note value - the pitch of the note that is playing does not change at all. This is because the output of the Probability is not the value of the note, but rather its position.

Leave the slider you are adjusting set about middle range, and pick another slider a few steps up or down from it. Now you should be hearing two notes playing: the note represented by the position of the one you were adjusting, and the note representing the position you are now adjusting.

Adjust the value up and down and notice that once again, the pitch does not change - but how often one note is played relative to the other does change. If you position the slider of the 2nd note at a higher value than the first, it will play more often; make it lower than the first and it plays less often. Make it 0, and it stops playing entirely, leaving only the first slider position playing.

Try setting a few other sliders. Each slider that is not zero will generate a note; with the value of the slider relative to the other sliders determining how often the note will be played.

The Probability module is self-normalizing, which means the actual values of the sliders is not important - only their value in relationship to other sliders. You are free to set up precise value settings for each of the probability values, but it works just as well - perhaps better in a musical context - to just "eyeball" them relative to each other, and adjust them on the fly as you are listening.

A Markov Scale

It turns out there is not a lot more to do to make a Markov chain, than you already have done. All you need to add to your current patch is two Step08 sequencers. Create them now.

One of the sequencers will hold the scale interval values. Use the Fill utility to create a C-major scale. Click on the Fill buttons on one of the Step08 modules, then select Make. Job done, Exit. The Step08 will now have the intervals of the C-major scale:

C=0, D=2, E=4, F=5, G=7, A=9, B=11, C=12

For the other Step08, we need to set it to 8 different Table pages. It does not matter which pages you use, nor do they need to be in any order. But to keep things simple, we will use the 8 pages already set up for Warren Burt's example programs, "markovexample.ssp," and "markovexample2.ssp." These are the 8 table pages starting with page 24. So we want to set the 2nd Step08 to the table page numbers 24, 25, 26, ....

Use the Fill utility for this also. Click on the Fill button, then set the first slider to 24 (the readout is the 2nd text box after the knobs), and click on the Count button. Click on Exit. You should see the values 24-31 in the Step text boxes.

Connect the Voice Note input to the Step08 with the scale intervals, replacing the connection to the Probability. Set the Voice Transp input to 48 or so. This is the part you will hear. Now connect the other Step08 - the one with the table page numbers 24, 25, etc. - to the Probability lower connection input ("Select Table Number"), which had been set to 64.

Finally, connect both Step08 stage inputs to the Probability output. You should hear a melody line playing now that is quite different from just a random sequence.

What is happening, is on each clock tick, the Probability module selects a new output based on the values in the table currently connected to it. This value steps the Step08, which picks a note and also sets the next table to feed back into the Probability module, making it ready for the next cycle. Since the Step08 is ahead of the Probability in the processing order, the interval sent to the Voice and the table number the Probability uses to calculate its next step are properly synchronized, or in this case properly unsynchronized.

To adjust the interval selection probabilities to those of your own choosing. click on the priority button in the upper left of the module, and select Disable. The popup will close and the button turns red. Click on the text box of the stage you want to adjust, but don't change the number. Now, click on the Fill button of the Probability module, not the Fill button of the Step08. You should see 3-4 sliders that are not zero, and you should be hearing them play via the Step08 that has the interval settings. Now adjust the values just as you did in the first part of this tutorial. Only the positions 0-7 should be set, which correspond to the Step08 stages.

When you have the one stage set, exit the Fill, click on the next stage of the Step08, and click on the Fill button of the Probability module again. Then adjust the steps as you did before.

Remember, this is a Markov chain - while you do not need to set each of the stages (nodes) to jump to all of the other nodes, you do need to insure that the each node is called at least once, and that the sequence is such that eventually every node can be called.

How it looks:


tutorial-10.ssp

SoftStep is Copyright © 1999-2004 by John Dunn and Algorithmic Arts. All Rights Reserved.