Posted by & filed under Bitwig Studio, Blog, Tutorials.

In the last article we succeeded in creating a user input section that allows us to MIDI map CCs from our controller to any parameter in Bitwig, just as we are used to doing in other DAWs. In this article we will dive a bit deeper into the API to get control of, and get feedback from the Transport Controls.

Up until now we’ve been walking through just the basics. Registering your script, getting notes from your controls and testing for CC data. We haven’t had to write our own functions, or use the API, except at the highest level. We will have to create a few API objects, find the proper methods in the API and define some functions to interact with these API objects. The first thing to do is open up Bitwig’s Control Surface API documentation from the ‘Help’ Menu in Bitwig. If you want to become savvy with scripting in Bitwig, you’ll need to become very familiar with navigating and understanding the documentation. Another great resource for beginning scripters is the Control Surface Scripting Guide, also available from the help menu. It will go over some things that we have already looked at, but it also has some more in depth discussions on views and functions, among other things. I encourage you to consult that for a deeper explanation of some of the features we will implement moving forward.

Something that is important in any musical environment is the ability to manipulate the transport. Playing, stopping and recording are essential functions, so let’s focus on getting control of those. In order to access those functions we need to instantiate an interface with the transport using the following code:



We now have an object called ‘transport’ that has access to all of the methods and functions provided by the API. This includes stopping, playing, recording, and also observing the state of the transport for LED feedback (if your controller supports that).

In order to take advantage of these we need to know what the functions are and how to call them. We should consult the API! If you navigate to the class list in the documentation (click on ‘Classes’ then ‘Class List’) you will find the ‘Transport’ class near the bottom. Click on that to bring up the documentation for that class. You will see a list of all the functions that we can call on our transport. Near the top of the list we will see a few of the functions that we are interested in. Let’s start with telling our transport to ‘Play’.

If you’re not familiar with reading documentation like this it can be a little overwhelming with all of the jargon (what the heck does void mean? What is a Callable callback?), but it’s not too bad. Let’s talk about each column. The first column tells you what value the function will return. Void just means that this function doesn’t return any values. If you scroll further down you can see that some functions do return a value, and instead of ‘Void’ you will see the type of value returned by that function. The second column tells you the name of the function, followed by the arguments in parentheses, separated by commas. If the function takes no arguments, these will be blank. Some functions here do take arguments, and in that case it will give you the type of the value (boolean, number, etc.) and the name of the value.

So now that we know a little about functions let’s set up a MIDI note to play our session in Bitwig. Most controllers will have access to a C3 (MIDI note 60),  so let’s go with that. We handle all of our MIDI data in the onMidiPort1 function that we set up previously, and we have already set up a check to see if the MIDI data is a CC, so any data that isn’t a CC will be a note (generally speaking, there are some other data types like pitch bend and aftertouch that we don’t need to worry about quite yet). Add the following lines of code directly after the closure of your if statement in the onMidiPort1 function.



This creates an if/else statement and it checks to see if the data is a CC. If it is, it runs the previous code that we implemented last time, ELSE it runs this code. We check to see if the note number (data1) is equal to 60, and that the velocity (data2) is greater than 0, so we only trigger this function on a note on. If we meet these conditions, we call play() on our transport object that we created. You should be able to save your code, and hit that key to see the transport light up and your session start rolling!

Or maybe not.

This actually won’t do anything yet. When we get MIDI notes into Bitwig they are filtered by channel and data type that we give as arguments to our createNoteInput() function, and then get sent directly to the application, bypassing the script. If we don’t define the filters bitwig will use generic filters which grab notes on channel 1. Using this you can set up one channel to play notes, and another to interact with the API (that’s for a later episode). In the meantime we simply need to add this line right below our noteIn instantiation in our init function:



This tells Bitwig not to consume the filtered notes and pass them onto the script. After adding this, we should be able to play our session (for real this time).

This is great! We can easily add a few more functions in our onMidiPort1 function to stop, record, rewind, fast forward etc., but I’ll leave those to you for the time being, and in the next installment we will examine getting some LED feedback going using observers. All questions, comments and concerns can be directed to