One of the great things about Max programming is that you almost never have to start from scratch. For my latest project, I essentially frankensteined two of my favorite patches together to make an unholy new device, the APC Mono Sequencer. It’s built on top of Live 9 Mono Sequencer device, made by Cycling 74 to show off the Max for Live platform, and Mark Egloff’s APC Step Sequencer, an awesome device for turning the APC40/20 into a grid-based step sequencer perfect for programming drum patterns. Check out this video I made to see how the device works when it’s hooked up to my APC40 and a nice 303-esque Analog patch:
Unlike Mark’s device, the Mono Sequencer much better suited for programming basslines and melodies. But as released, it has no hardware control, and we all know how much fun it is to program melodies with the mouse. So, I started by making a copy of the Mono Sequencer .amxd file and renaming to my liking. Then I started looking under the hood of Mark’s APC device (which does a lot more than it looks like in presentation mode) and started disconnecting things to see what they did. The hardware control flow of the patch does something like this:
– Get the name/ID of the selected control surface
– Activate a bunch of live.observer objects to receive button presses as input
– Activate a bunch of live.object objects to send light/status info as output
– Deactivate the “session control” functionality so that button presses don’t trigger clips.
Because the APC40 and APC20 have different control number assignments, this ends up being quite a task. Above, you can see all the append and route objects that are needed to send a simple message like
4 1 (meaning “activate button 4”) into a simple “turn on” message sent routed to one of 8 live.objects, each with one of 2 possible control numbers. Fortunately, the 40-button matrix controls are handled by a single live.object, which lets you address buttons by row and column (whew).
Mark’s patch actually stores its patterns in MIDI clips on the current track, which we won’t need to worry about. So, there’s a whole bunch of Live API pieces that won’t be necessary for our purposes, and I was able to delete about half of the patch based on that alone. The only objects we need are control of the button matrix (1 object), the scene launch buttons (5 objects), and the clip stop buttons (8/9 objects). As a bonus, we’ll also check whether the current track is selected so we can revert to regular controls when the sequencer isn’t active. This leaves us with a much simpler initialization patcher. So, we now have the necessary bits in order to send messages to and from the APC 40. Thanks, Mark! Next, we need to figure out how to send this data to the sequencer itself, which is also already built but needs more input and output.
The core of the mono sequencer is a set of five of these live.step devices, each of which controls a single parameter (pitch, velocity, octave, duration, and repeats). A single live.step device will do all of these things on its own, so why 5 separate devices? So that the sequences can be looped independently, with varying lengths to create generative, non-repeating (or long-playing anyway) sequences rather than repeating one bar ad infinitum. Each of the objects are set to display the
extra1 parameter rather than the corresponding pitch/velocity sequence they represent. This allows the display and range of the parameters to be fully customized, and ensures a nice uniform bar chart appearance to each panel, rather than a different style for different modes.
Our first task for the controller is to figure out how to get data into and out of the live.step objects. If we send it a message formatted
fetch extra1 $step-number, it will send a message to its fourth outlet formatted
extra1 $step-number $value, with the appropriate integers substituted. So all we have to do is take the current step as a number, prepend some keywords, and fan it to the various sequencers. Then we can collect the values by listening for
extra1... messages from the outputs. We can collect these output messages use send and receive objects to display these values on live.dial objects that we’ll control from the APC.
It may look a little complicated, but remember that it’s just the same thing repeated 5 times. To control the dial objects, we use the Max Inspector to set their Parameter Visibility to “Automated and Stored”, and their Automapping Index to the numbers 1-5, so each parameter gets one of the device control knobs on the APC. To send values back to the sequencer, we just take the output of the knob, and send a message to the corresponding live.step object in the format
extra1 $step-number $value (just like the message we get out of the same object when we use the “fetch” message). While we’re at it, we can also use the output of the knob to send a static message (again, 1-5) to the live.tab object that controls which panel of the sequencer is visible. That way we can always see what parameter we’re adjusting. With this done we can pick the note we want to edit, see its values, and adjust them in real time.
Now for the tricky part, controlling which steps are active and showing them on the APC. We’ll do this by listening to data from the sixth live.step object, which stores values of 0/1 in its extra1 sequence, and is always visible below the others. To update the lights, all we really need to do is send messages of the format
$row $column $status to the button matrix live.object we looked at earlier. $status takes the following integers as options:
0 = off 1 = green 2 = flashing green 3 = red 4 = flashing red 5 = orange 6 = flashing orange
The first thing we’ll do is use the uzi object to count up from zero and send a
fetch extra1 $step-number message to the sequencer, and listen for the outputs. We’ll get back a series of messages like
0 1, 1 1, 2 0, 3 0, 4 1, and so on. The zeroes and ones will turn the green step lights on and off, so we just have to turn the step number into something the APC knows about in terms of rows and columns. Since the steps are numbered starting at 1 rather than 0, we first subtract 1. Then, we want to divide by the number of columns in each row (8) and round down to get the row number, and take the remainder (or modulus) to get the column number. This is easily accomplished using the / and % objects with integer (rather than float) arguments.
When that’s done, we implement “running lights” by listening to the step sequencer’s current note display and set the corresponding button red (using
$row $column 3) in real-time. Easy enough. But when we advance, we have to reset the previous step to its actual value. We could just subtract 1 from the current step, but then we’d have trouble when we got to the end of the sequence and started from zero again (since there is no step -1). Instead, we’ll store the current step in a number object with the set command, and then retrieve it with a
bang message every time the step advances. Then we can just send another
fetch extra1 $step-number message to the sequencer, and it will automatically get sent to the grid by the piece we just built for initializing it.
Listening to button presses is easy. We receive them as
$column $row 1 from the button matrix, so we can just multiply the row number by 8, add it to the column number, and get the step number. When the third value is 0, it means we’ve released the button, so we can ignore those events. First, we send the “selected step” number out to the other other pitch, velocity, etc. sequencers to retreive those values for the macro controls. We also store the step number in an == object, so the next time we get a button press, we know if it was the same button, and if it is, we can toggle it on/off using a
bang and a toggle object that stores the value of the current note. And of course, when a note is selected, we also light it up orange or flashing orange, depending whether it’s on or off. And last, we must also remember to de-select the previously selected note when a new one is pressed, and _not_ to reset the previously played note when it _is_ selected (whew).
And that’s it! Well, there are a couple other bits I won’t cover, mostly adding gate and route objects in places so that the sequencer control doesn’t interfere with the Randomize and Copy/Paste functions of the Mono Sequencer (discovered through trial and error, of course…). So if you got this far, congratulations! You’re now qualified to hack other peoples’ patches apart and combine them for your own amusement. Happy sequencing!