Changing Instruments
This post is part of a series of notes and exercises for a summer camp on making musical instruments with Arduino and Pure Data.
Earlier we created this ticker
abstraction to walk steadily through a range of numbers:
In this exercise we explore changing MIDI instruments and using two of these ticker
s together.
Changing Instruments
In MIDI terms, each instrument is a program. To change which instrument or program plays a note, we feed a number in [1, 128] to the pgmout
command. The MIDI standard defines the mapping between these numbers and instruments.
We can test this changing of instruments with a quick patch:
When you drag on the number box, we first feed the instrument number to pgmout
, and then we fire off a middle C. You hear a slurry of various instruments. Let’s use ticker
to slow down this slurry and showcase the whole cast of instruments.
Ticker Ticker
Suppose we wanted a ticker
to fire off another ticker
. One loop would be triggering another loop. We write nested loops like this often to traverse 2D space or mix and match one collection with another. For instance, maybe we want to loop through a set of instruments, and for each of those instruments, we’ll have it play a little tune. In a text-based language, we’d write something like this:
for each instrument number set instrument for each note number in tune play note
Each for
loop represents a ticker
. To keep things simple, let’s just print the numbers coming from the two ticker
s:
for each instrument number print instrument for each note number in tune print note
Suppose we want instruments 1, 2, and 3 to play notes 60, 61, and 62. We’d expect this output when we run our code:
instrument: 1 note: 60 note: 61 note: 62 instrument: 2 note: 60 note: 61 note: 62 instrument: 3 note: 60 note: 61 note: 62
Let’s create a patch with two ticker
s that implements this pseudocode. It might look something like this patch:
We use a trigger
to make the sequencing clear and to convert the numeric output of the first ticker
into a bang that the second ticker is expecting. Here’s the actual output that we see:
note: 1 instrument: 1 note: 2 instrument: 2 note: 3 instrument: 3
That’s definitely not what we expected. What went wrong? The issue is that the two instances of ticker
are interfering with each other. The names that we send
to and receive
from are shared by both ticker
s. When the first ticker
issues send tick
, both of them will receive it and print the same number. That’s what we’re seeing in the output. Likewise, when the first issues send stop
, both of them will receive
it and stop.
Instance Variables
To keep two or more instances of the same abstraction from interfering with each other, we can assign the send
and receive
targets unique names. How do we generate unique names? We could pass in an extra creation argument: ticker 4000 1 3 instrument-loop
and ticker 1000 60 62 note-loop
. And then we could send stop-$4
and receive stop-$4
. The $4
would get expanded to the identifier that we passed in to the ticker
. Each instance of ticker
, then, will have its own channels for send
and receive
. As long as the identifiers are unique, this will solve our problem.
However, we don’t need $4
. Pure Data already provides an identifier unique to each instance of an abstraction. It’s named $0
. We tweak our ticker
implementation by appending -$0
to each of the names we send
and receive
from:
Be sure not to miss any! With these changes applied, we now see the expected output.
Showcase
Our last step is to walk through all 128 MIDI instruments and have each play a short sequence of notes. Our first ticker
will iterate through [1, 128], set the MIDI program, and fire off another ticker
that marches through 1, 2, and 3. These numbers will tick through an arpeggio of the C major I chord—which is made up of MIDI notes 60, 64, and 67. Our patch might look something like this:
This patch should give you a good sampling of the instruments. It does get long, however, so don’t forget that you can send a stop
message.