teaching machines

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 tickers 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 tickers:

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 tickers 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 tickers. 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.

Comments

Leave a Reply

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