Push Programming Oct13 02

Introduction

The last tutorial was a great (and fairly easy) introduction to working with the Push, but it does suffer from one problem - long load times. In order for the abstractions to provide easy access to all of the Push parameters, Mark's code created a connection to all of the possible parameters. This process can take a long time to load - which can be an irritation in a live performance situation.

In this tutorial, we'll make a new device, and make it in a new way. We will be using Javascript to create a lean-and-mean connection to just the part of the Push that we want (in this case, we will again attack the button matrix), then build a structure around that code.

Note that this code contains both an .amxd device file and a .js file (called PushStepperControl.js), which is the heart of the new device. The PushStepper won't work without access to the Javascript file; you can either put it in the same folder as the .amxd file, or you can place it in a common area - such as the Max /patches/ folder.

The Patching Basics

This device is basically a simple wrapper around a Javascript object (the js object at the bottom left). We interface with the transport to get our transport status and clock feed, and collect some user controls for the device, but most of the good stuff is found in the PushStepperControl.js code file. About the only think that is really interesting is the "midiStoreAndForward" subpatcher, which holds incoming notes and outputs them whenever it receives a bang from the Javascript. You can peek inside to see it in action.

The Javascript Program

I decided to use Javascript, because it manages some of the complexity in a way that typical (textual) code does best.

There are two sections of the Javascript code that are interesting: the two objects, labeled "Matrix" and "Surface". Let's look at the Surface first.

The Surface object is the high-level object that finds and interfaces with the Push controller. We use a probe into the control_surfaces LiveAPI path in order to identify the control surface labeled "Push" (which is what any Push device will call itself); once this is done, we register access to the button matrix and create some mediation methods to manage interface with the user interface.

Whenever we grab or release the button matrix, we do it through the grabButtonMatrix and releaseButtonMatrix functions. In addition to performing the grab/release, we also set properties that let us know the current status, and also determine that property that we will be "observing" (in this case, the value). This was actually a difficult piece of logic to get correct, and only with help from Jeremy Burnstein was I able to negotiate the connection correctly.

Finally, when we grab the button matrix, we have to have a way to receive the information. This is done with the Surface.prototype.bmxCallback function, which is called any time that the button matrix values change. I put in an extensive note about the use of 'this' in the callback, and that it refers to the button matrix (not the Surface itself), because of the way that we've instantiated the button matrix interface. Confusing? Sure, but it works, and gives us a chance to do some interesting stuff in the Matrix object.