When I first heard about Bitwig Studio years ago, there was one feature that really caught my eye. In promotions for the software they always mentioned that they would have an ‘Open Controller Scripting API’. Coming from an environment like Ableton Live, which has an undocumented and ‘closed’ API, this was hugely exciting. In this series of articles we will walk through the creation of a basic controller script for Bitwig Studio.
Live is great, and I still use it for a most of my sound making and performing, but coding scripts without documentation, or a convenient way of debugging, makes it a laborious, and sometimes frustrating experience. Bitwig Studio on the other hand, has a completely documented scripting API, and a debugging console built into the application. This makes writing control scripts a much faster and easier process, which is very good, because in order to do anything with a controller in Bitwig, you’ll need a script. Thankfully, there are some generic scripts that are included with Bitwig that allow for note input and cc mappings, as well as quite a few scripts for popular controllers.
Let’s get to it! First, let’s make two folders in our Controller Scripts folder in our Bitwig User directory.
Mac: Documents/Bitwig Studio/Controller Scripts
Windows: %USERPROFILE%\Documents\Bitwig Studio\Controller Scripts\
There are a few lines of code that every script needs to have at the top to initialize the script and make the connections. First we need to initialize the API, define our script, and define the inputs and outputs.
In the host.defineController function, we let Bitwig know what company makes the controller, what the actual device is, the version number, and a UUID. You can generate those easily HERE. It’s some sort of hardware identifier, that I’m still not totally clear on (just generate one and put it as the fourth argument of this function, ok?). After that we define the number of input and output ports. In this case I want one input and one output. If you save this file you should be able to open Bitwig, navigate to the controller preferences, and select your new script from the ‘Add controller manually’ menu. You can then assign a controller to the MIDI input and MIDI output of the script. It won’t do anything yet, but we can quickly change that with a few more lines of code.
We’ll add a few functions to our script inside of the init() function. This function is called whenever we load the script and sets things up for us. In this case we want to create our note input and a MIDI callback.
The Note input (as you may have guessed) allows us to get MIDI notes to Bitwig’s synths or third party VSTs. The MIDI callback isn’t needed now, but it’s a useful thing to setup. Basically, we create a MIDI callback that takes a function as an argument (onMidiPort1 in this case). This will call the onMidiPort1 function (which we haven’t defined yet) whenever an event happens on the specified MIDI port (which is defined by the host.getMidiInPort(0) bit). This is your gateway to creating interesting interactions using functions, conditionals, and other fun stuff, which we will talk about later.
In order for this script to not throw errors, let’s go ahead and define our onMidiPort1 function like this:
We can leave this empty for now, as we aren’t doing anything with MIDI data except passing on the notes. When we get a MIDI message this function passes the status byte, and the two data bytes of the MIDI message it received and then executes the code contained in this function.
One more thing to add is just a notification when you disconnect the device that connected to this script. This isn’t necessary, but it’s good to have if you need to do some cleanup on disconnection.
Now you can go ahead and save the file, connect it to Bitwig, arm an instrument track, and play notes with your MIDI controller. We have coded up about half of the Generic MIDI Keyboard script that ships with Bitwig, and in the next installment we will add support for mapping CC data.