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

In the last installment we successfully implemented some transport control in our script to play, stop and record from our controller, as well as input notes. This article will focus on creating and using observers to get information from Bitwig sent to our controllers. This is useful if your controller has any type of LED feedback. You can create all kinds of useful communication including parameter values, volume levels, transport state, clip launching, etc. We will be focusing on adding some observers to our transport so we can see what state our session is in right from our controller!

It will be useful to have access to your controllers LED implementation. It’s common for some controllers to respond to the same message that they send out to control the LEDs (or other feedback options), but some of them don’t. If the manufacturer has good documentation on how to interact with their hardware, you should dig that up before proceeding, as it will make tasks like this much more manageable. You can grab the updated scripts on github, I will be posting the script that we’ve been developing after each article, complete with some features that we don’t cover directly in the article.

I’ll be using the QuNeo as the controller I implement the feedback on. I chose this device because it has a lot of different options for displaying information, so whatever type of data we encounter, we’ll have some options as to how we display it.

The first thing we’ll want to do is create an observer. If you navigate to the transport object in the Bitwig API, about 8 items down you’ll see the ‘addIsPlayingObserver’ function. You can see that this function returns nothing and takes a type ’Callable callback’ as an argument. A callback is a function that will be called whenever the value of this statement changes. It will also pass that value into the function. An observer with a callback will look like this:



Whenever the playing state of the transport changes it will call our function (no need to give it a name in this case) with the value as an argument. It will then print to the console the value using the ‘println’ function. If you add this code and save your script, you should be able to see ‘True’ or ‘False’ pop up in your console as you play or stop your session.

With this information we can easily setup a check and then send values according to the state of our transport. In order to send MIDI out from the script we will make use of the ‘sendMidi’ function of our MidiOut object we created way back in part 1. You can call this function wherever you want in your script and it will send the status byte and 2 data bytes that you pass in as arguments.

The QuNeo has three transport buttons that we’ll use to display our transport state. According to the documentation, the play button can be controlled by MIDI note B0 (note number 35). So data 1 will be 35 and data 2 will change based on the transport state; 0 for stopped, 127 for on. But what about the status byte? The status byte contains the channel and type of message. The page over at has a handy table that gives the decimal (and binary if you’re interested) values of all the status bytes one might encounter. As you can see a status of 144 is a note on, on channel 1. So with all of that information we can setup a conditional inside of our callback function:



This function checks to see if the value is true. If it is, the MIDI message to turn the LED on is sent, else, the MIDI message to turn the light off is sent.

Depending on your controller, your MIDI messages will be different and you should consult the proper documentation. If your controller is one that employs ‘mirroring’ (the same message that is sent, also controls the feedback) you can easily find the status and data bytes that your controller sends using the ‘println’ function we saw earlier:



This will now report exactly what the script is hearing from your controller. You can use this to quickly setup checks for certain midi messages, or to gather data about what message your controller might be looking for.

Now that we have added some LED feedback for the playing status, you can easily add some observers for stop and record. In the next installment we will look at creating functions and variables in an external file and importing them to keep our main script tidy, readable, and most importantly maintainable and expandable! Direct any questions comments and concerns to