Behringer X-Touch Mini

This notebook can be downloaded here.

Because Chrome is the only browser that implements the Web MIDI API, this package only works in Chrome. Firefox has recent discussion on how to move forward with implementing this standard.

Each midi controller needs a custom implementation exposing the interface for that specific midi controller as buttons, knobs, faders, etc. Currently we support the Behringer X-Touch Mini controller, which is currently available for around $60.

In [ ]:
from ipymidicontrols import XTouchMini, xtouchmini_ui
x = XTouchMini()

We can work directly with the controls to assign values, listen for value changes, etc., just like a normal widget. Run the cell below, then turn the first knob or press the upper left button. You should see the values below update. Note that the button value toggles when held down, and the light on the physical button reflects this state, where true means light on, false means light off.

In [ ]:
left_knob = x.rotary_encoders[0]
upper_left_button = x.buttons[0]
display(left_knob)
display(upper_left_button)

You can also adjust the values from Python and the changes are reflected in the kernel.

In [ ]:
left_knob.value = 50

Rotary encoders (knobs)

Rotary encoders (i.e., knobs) have a min and max that can be set.

In [ ]:
left_knob.min=0
left_knob.max=10

Knobs have a variety of ways to display the value in the lights around the knob. If your value represents a deviation from some reference, you might use the 'trim' light mode. If your value represents the width of a symmetric range around some reference, you might use the 'spread' light mode.

In [ ]:
# light_mode can be 'single', 'wrap', 'trim', 'spread'
left_knob.light_mode = 'spread'

We’ll set the min/max back to the default (0, 100) range for the rest of the example for consistency with other knobs.

In [ ]:
left_knob.min = 0
left_knob.max = 100

Buttons

Since the button has a True/False state, and holding down the button momentarily toggles the state, if we set the button to True when it is not held down, we reverse the toggling (i.e., it is now True by default, and pressing it toggles it to False).

In [ ]:
upper_left_button.value = True
# Now press the button to see it toggle to false.

We can change this toggling behavior in the button by setting the button mode. It defaults to 'momentary', which means the button state toggles only when the button is held down. Setting mode to 'toggle' makes the button toggle its value each time it is pressed. Run the following cell and press the button several times. Notice how the toggle behavior is different.

In [ ]:
upper_left_button.mode = 'toggle'

Each rotary encoder can also be pressed as a button and the toggle mode can be set as well. Run the cell below and press the left knob.

In [ ]:
left_knob_button = x.rotary_buttons[0]
left_knob_button.mode = 'toggle'
display(left_knob_button)

Faders

The fader can send its value to Python and has min, max, and value properties.

In [ ]:
fader = x.faders[0]
display(fader)

Because the X-Touch Mini does not have motorized faders, the fader cannot be moved to represent a value set from Python. Any value set from Python is overridden by the next fader movement.

Listening to changes

As with any widget, we can observe changes from any control to run a function.

In [ ]:
from ipywidgets import Output

out = Output()

@out.capture()
def f(change):
    print('upper left button is %s'%(change.new))

upper_left_button.observe(f, 'value')
display(out)

Linking to other widgets

You can synchronize these widgets up to other widgets using link() to give a nicer GUI. Run the cell below and then try turning the left knob or pressing the upper left button. Also try adjusting the slider and checkbox below to see that the values are synchronized both ways.

In [ ]:
from ipywidgets import link, IntSlider, Checkbox, VBox
slider = IntSlider(description="Left knob", min=left_knob.min, max=left_knob.max)
checkbox = Checkbox(description="Upper left button")

link((left_knob, 'value'), (slider, 'value'))
link((upper_left_button, 'value'), (checkbox, 'value'))

display(VBox([slider, checkbox]))

This package includes a convenience function, xtouchmini_ux(), to link each control up to a slider or checkbox widget in a GUI that roughly approximates the physical layout.

In [ ]:
xtouchmini_ui(x)

Experimenting with options

Let’s set various controls to explore the available button and knob light modes, as well as some random values to see what they look like on the controller.

In [ ]:
for b in x.buttons:
    b.mode='toggle'
for b in x.rotary_buttons[:4]:
    b.mode='toggle'
for b in x.rotary_buttons[4:]:
    b.mode='momentary'
for b in x.side_buttons:
    b.mode='momentary'
for b, mode in zip(x.rotary_encoders, ['single', 'single', 'trim', 'trim', 'wrap', 'wrap', 'spread', 'spread']):
    b.light_mode = mode
In [ ]:
# Set some random values
import secrets
for b in x.buttons:
    b.value=secrets.choice([False, True])
for b in x.rotary_encoders:
    b.value = secrets.randbelow(101)

Clearing values

Finally, let’s clear all of the values.

In [ ]:
# Clear all values
for b in x.buttons:
    b.value = False
for b in x.rotary_buttons:
    b.value = False
for b in x.rotary_encoders:
    b.value = 0
In [ ]: