Transports and Synchronization
Understanding Storage: let, const, @state, @param
Using the Audio Plugin/Desktop Application Template
Programming a Custom UI with JUCE
RNBO Raspberry Pi OSCQuery Runner
RNBO MIDI Sequencer
Let's build a sequencer in RNBO that can use four channels of MIDI to drive any synthesizer we'd like.
Making some MIDI
To kick things off, let's create our rnbo~ object with the title “midiseq." In the RNBO subpatcher that opens, let's make some MIDI notes. We can use
[makenote 60 200] and give it a number box, which will make some note-on and note-off events for us with a sort of safe velocity "60" for now.
Let's pack together the midi note and velocity from makenote, format that as a MIDI message with midiformat, and send the message to midiout.
Now, over in Max, we'll get that MIDI message out the MIDI outlet of the rnbo~ object. Let’s use midiout and pick the MIDI port "from Max 1" so that we can drive an instrument which is listening to that same port. You can pick any software instrument or DAW you like. Note that if you are on Windows, you might need to create this MIDI port yourself—you can use an application like loopMIDI.
Now, if we send makenote a "60" from the number box, we should hear a nice, beautiful middle C coming from our synthesizer.
This is all still pretty manual for us, so let's get RNBO to do more of the work.
Transport and Metronome
Let’s create a metro that outputs steady 16th notes, locked to an internal transport. If we toggle on this transport, we can see the metro starts, and it can drive our makenote object. This is a big improvement.
But what if we want to start and stop the transport from outside our RNBO device, like back in Max, or in our DAW or website? For that, we need a way to communicate from our host or target platform into RNBO.
Parameters and Controlling RNBO
Let's do this using the param object—create a
[param transportOn @min 0 @max 1 @value 0 @steps 2] object. That's initialized with a minimum of 0 and a max 1, and a default value of 0, so our transport is off until we want it to be on. We also give it two steps, so that it's clear that we only want two possible values: off, and on.
Over in Max, we can send a 1 or 0 via the message
[transportOn $1] to get the transport to start or stop. Let's give ourselves a tempo parameter as well—perhaps with a default value. This param object can then use the set object to set the value of the transport object's
Okay, we're making progress—next let's give our sequencer more than one note to play.
In RNBO, we only have numerical messages, so when we want to send around a lot of data or information, we want to think in terms of lists and operations on lists. Let's say we want our sequencer to play several octaves of a minor pentatonic scale, using the MIDI notes 60, 62, 63, 65, 67, etc. Well, we can hold all of those MIDI notes in a list.reg object, which will store and output a scale when it receives a bang, like this:
[list.reg 60 62 63 65 67 70 72 74 75 77 79 82 84 86 87 89 91 94 96]
Okay. Now, to move through the notes of that scale, we can read through the list according to the position of each item in the list, or "index," using the list.lookup object. Let's get our metro to drive a counter that moves up from 0 to 15 each sixteenth note.
This sounds great, but we don’t want to only ever hear an ascending scale. We can scramble our list to get a new pattern using list.scramble, which will scramble a list it's received every time it receives a bang.
But what if we want to get back to the list's original order? Let's build some logic here that will allow us to send a message into RNBO whenever we want to scramble our pattern or reset it to the ascending scale.
To send this message, let’s use an inport tagged "scrambleOne." We're calling this "scramble one" so that we can eventually support several voices with this device. We'll plan on "scrambleOne" receiving a message payload consisting of either ones or zeroes, with ones triggering a scramble and zeroes triggering a reset. A
[select 0 1] (or "sel" for short) will give us a bang depending on which of these it receives. Let's patch the 0 bang to list.reg and the 1 bang to list.scramble, with both patched into list.lookup. We probably want a
[loadmess 0] here as well, to make sure that the list.reg outputs at least once when the device first loads.
Now in Max, we can send a message
[message scrambleOne $1] to rnbo~. The word "message" lets RNBO know to expect a message rather than a parameter value. We can make a couple of textbutton objects here to trigger the 0 and 1, and hear our sequencer scramble and reset.
Spice it up
Let’s add a couple more parameters that can make this sequence more interesting. First, let's make a
[param chanOneOffset @value 0 @min -48 @max 48] with a range of -48 to 48 and a default value of 0, and add its value to the MIDI note we're making. Now we can change octaves or keys.
Could we implement some element of chance? What if we don't want to hear every step of the 16-step sequence? Let's create a
[param chanOneProb @value 100 @min 0 @max 100] with a range of 0 to 100 and scale it such that 100 is 0 and 0 is 100.
Now, with every step of our sequence, we can generate a random number from 0 to 100, and if that value is greater than or equal to our scaled probability for channel 1, we'll let the MIDI note pass a gate.
Over in Max, create a slider with a range from 0 to 100 and use it to set the "chanOneProb."
This is sounding great. Let's add three more voices using MIDI channels 1 through 4.
To start, let’s set up our Max patch for more voices by sending all of the channel 1 parameter values and messages to a
[send toRNBO] object.
We can do the same with our RNBO patch by sending our counter to
[s steps], and specifying on our midiformat object that we want everything we've done so far to go to MIDI channel 1.
Then we can copy and paste this whole bit, changing the references to "One" to the new channel number. And we can do the same in Max. Of course, there are other ways to handle the management of multiple voices in RNBO using RNBO's polyphony tools, but that's a subject for another article.
Once we're done, let's hit our "reset" buttons for each voice to get them rolling. Over in whichever DAW you are using, set each track to listen to a seperate channel.
Export a VST
This is sounding great. But the real power of RNBO is that now we can take our creation out of the patching environment and send it off into the world. Let's say we want to build a plug-in that hosts our sequencer that we can use in any DAW. Let’s use Reaper to test this plug-in, as it is easy in Reaper to handle multiple channels of MIDI from a single virtual instrument.
To help our sequencer work well as a VST in particular, we'll make a couple of small changes.
First, let's add two channels of pass-through audio so that we can classify this as an "Effect" VST and so that we can place it anywhere in our signal chain.
Second, while the inport/outport method of getting message events to and from RNBO is very convenient for many target platforms, a VST can only handle MIDI events and updates to parameter values. So let's replace our
[inport scrambleOne] (and Two, Three, Four) with a
[param scrambleOne @value 0 @min 0 @max 2 @steps 3]. To get the same sort of scramble/reset behavior we had before, we'll give the parameter three steps and a range of 0 to 2. Any value this param receives that isn't zero can trigger a bang. Instead of the
[loadmess 0], we can just set the default value of our new param to 0. Over in Max, we can send our "scramble" textbutton to a toggle and a plus one so that every time we hit the button, we get a non-zero value.
With these changes made, we're ready to export our plugin! Let's select "Audio Plugin Export," pick "Effect," and make sure we're pointing at the output directory we'd expect.
We haven't set any presets, included any samples, and the patcher is not polyphonic, so we can leave all of these options unchecked. Press "Export," enjoy a few moments of quiet reflection while your plugin builds on the cloud.
Once the plugin has built, you can place it in either your computer's built-in folder for plugins, or your custom folder if you've set one up for Reaper. Over in Reaper, scan for new plug-ins, and load it in, and route the MIDI tracks appropriately—it should work just like in Max.
Congratulations, you've built and exported a MIDI sequencer in RNBO, and now it's your own to use anywhere. Of course, this is RNBO, we've only scratched the surface - you can imagine modifying this device to switch between any number of scales, add more manipulation of the patterns, retune each voice according to your just intonation of choice, and then you can export the whole patch as WASM and load the sequencer on your webpage… you get the idea.
If you’re unsure what to mod first, why not try adding a new param that can control the velocity of MIDI notes this sequencer creates? You could add controls to raise and lower the velocity, or randomize it in some quirky way.
Have fun, and happy patching!