Skip to content

Instantly share code, notes, and snippets.

@Janiczek
Last active April 3, 2024 15:05
Show Gist options
  • Save Janiczek/04a87c2534b9d1435a1d8159c742d260 to your computer and use it in GitHub Desktop.
Save Janiczek/04a87c2534b9d1435a1d8159c742d260 to your computer and use it in GitHub Desktop.
Arturia Minilab 3 Sysex codes

Arturia Minilab 3 SysEx messages

I was mainly interested in finding out how to change pad colours.

There was this Github repo detailing some SysEx messages for Minilab 2, but that didn't work for Minilab 3.

In the end I downloaded the DAW integration scripts from the Resources page and decompiled the Bitwig Java classes (you need to unzip the .bwextension file). That gave me the coveted secret SysEx commands :)

Initialization

Seems to only be needed for showing text on the display. Seems to do something about the Arturia vs DAW vs User 1 modes, but I didn't figure that out and am using it blindly.

F0                # sysex header
00 20 6B 7F 42    # Arturia header
02 02 40 6A 21    # ?
F7                # sysex footer

Setting button/pad colors

Below the ID needs to be replaced by the button you want to set colors for.

Button ID Note
Shift 0
Oct - 1
Hold 2
Oct + 3
Pad 1..8 4..11 Don't forget to convert to hex: pad 7 is 0x0A and pad 8 is 0x0B

The RR, GG, BB need to be in range 0x00..0x7F. Examples:

RR GG BB Color
00 00 00 black / off
7F 7F 7F white
7F 00 00 red
00 7F 00 green
00 00 7F blue
7F 7F 00 yellow

etc.

F0                     # sysex header
00 20 6B 7F 42         # Arturia header
02 02 16 ID RR GG BB   # set color of button ID to 0xRRGGBB
F7                     # sysex footer

Drawing stuff on the display

In all of the messages below, S1 and S2 need to be the ASCII bytes of your strings.

Eg. string "Hello" would be the bytes 48 65 6C 6C 6F.

No pictograms, first line smaller font and left-aligned

F0               # sysex header
00 20 6B 7F 42   # Arturia header
04 02 60         # set text
01 S1 00         # line 1 of the text
02 S2            # line 2 of the text
F7               # sysex footer

Centered lines with pictograms

Below, P1 and P2 need to be one of the following:

Pictogram Value
00 None
01 Heart
02 Play
03 Record
04 Armed
05 Shift
F0                      # sysex header
00 20 6B 7F 42          # Arturia header
04 02 60                # set text
1F 07 01 P1 P2 01 00    # set pictograms
01 S1 00                # line 1 of the text
02 S2 00                # line 2 of the text
F7                      # sysex footer

TODO: This probably follows the same scheme as the "Info" messages below, meaning the "01" byte in "1F 07 01" is probably an "autohide" parameter, and 02 could set it to "True". Haven't checked.

Info display

Below, CC should be one of the following:

CC Pictogram
03 Knob
04 Fader
05 Pad

AH should be 00 if the text should not autohide and 02 if it should autohide after a few seconds.

VV should be the value of the control, between 0x00 and 0x7F (100%).

Eg. CC=04 and VV=5F would show a fader that is around 75% to the top. CC=03 and VV=7F would show a knob that's all the way to the right.

F0                   # sysex header
00 20 6B 7F 42       # Arturia header
04 02 60             # set text
1F CC AH VV 00 00    # set control
01 S1 00             # line 1 of the text
02 S2                # line 2 of the text
F7                   # sysex footer

Scrolling display

CC and AH mean the same thing as above.

PO and LE are position and length of your imaginary list.

Thus PO should be >= 0 and < LE, and LE should be >= 1.

F0                        # sysex header
00 20 6B 7F 42            # Arturia header
04 02 60                  # set text
1F CC AH PO 00 LE 00 00   # set scrolling information
01 S1 00                  # line 1 of the text
02 S2 00                  # line 2 of the text
F7                        # sysex footer

01_colors.jpg

f0 00 20 6b 7f 42 02 02 16 00 00 00 00 f7
f0 00 20 6b 7f 42 02 02 16 01 7f 00 00 f7
f0 00 20 6b 7f 42 02 02 16 02 30 00 00 f7
f0 00 20 6b 7f 42 02 02 16 03 7f 7f 7f f7
f0 00 20 6b 7f 42 02 02 16 04 30 30 30 f7
f0 00 20 6b 7f 42 02 02 16 05 00 7f 00 f7
f0 00 20 6b 7f 42 02 02 16 06 00 30 00 f7
f0 00 20 6b 7f 42 02 02 16 07 00 00 7f f7
f0 00 20 6b 7f 42 02 02 16 08 00 00 30 f7
f0 00 20 6b 7f 42 02 02 16 09 7f 7f 00 f7
f0 00 20 6b 7f 42 02 02 16 0a 00 7f 7f f7
f0 00 20 6b 7f 42 02 02 16 0b 7f 00 7f f7

                           ^^ ID
                              ^^ ^^ ^^ RR GG BB

02_text_left.jpg

Note this needs the init message as well.

f0 00 20 6b 7f 42 04 02 60 01 48 65 6c 6c 6f 00 02 57 6f 72 6c 64 21 f7
                              ^^^^^^^^^^^^^^ "Hello"
                                                   ^^^^^^^^^^^^^^^^^ "World!"

03_text_pictograms.jpg

Note this needs the init message as well.

f0 00 20 6b 7f 42 04 02 60 1f 07 01 01 02 01 00 01 48 65 61 72 74 00 02 50 6c 61 79 00 f7
                                    ^^ ^^ heart, play
                                                   ^^^^^^^^^^^^^^ "Heart"
                                                                        ^^^^^^^^^^^ "Play"

f0 00 20 6b 7f 42 04 02 60 1f 07 01 03 04 01 00 01 52 65 63 00 02 41 72 6d 65 64 00 f7
                                    ^^ ^^ rec, armed
                                                   ^^^^^^^^ "Rec"
                                                                  ^^^^^^^^^^^^^^ "Armed"

f0 00 20 6b 7f 42 04 02 60 1f 07 01 05 00 01 00 01 53 68 69 66 74 00 02 4e 6f 6e 65 00 f7
                                    ^^ ^^ shift, none
                                                   ^^^^^^^^^^^^^^ "Shift"
                                                                        ^^^^^^^^^^^ "None"

04_controls.jpg


                              vv vv control, autohide
f0 00 20 6b 7f 42 04 02 60 1f 05 00 00 00 00 01 50 61 64 00 02 30 20 3d 20 65 6d 70 74 79 f7
f0 00 20 6b 7f 42 04 02 60 1f 05 00 40 00 00 01 50 61 64 00 02 36 34 20 3d 20 68 61 6c 66 f7
f0 00 20 6b 7f 42 04 02 60 1f 05 00 7f 00 00 01 50 61 64 00 02 31 32 37 20 3d 20 66 75 6c 6c f7
                                    ^^ value    ^^^^^^^^ "Pad"

05_scroll.jpg

f0 00 20 6b 7f 42 04 02 60 1f 06 00 01 00 7f 00 00 01 49 74 65 6d 20 6e 61 6d 65 00 02 31 20 2f 20 31 32 37 00 f7
f0 00 20 6b 7f 42 04 02 60 1f 06 00 1e 00 5a 00 00 01 49 74 65 6d 20 6e 61 6d 65 00 02 33 30 20 2f 20 39 30 00 f7
f0 00 20 6b 7f 42 04 02 60 1f 06 00 4d 00 4e 00 00 01 49 74 65 6d 20 6e 61 6d 65 00 02 37 38 20 2f 20 37 38 00 f7
                                    ^^ position
                                          ^^ length
#!/usr/bin/env python
import mido
#print(mido.get_output_names())
port = mido.open_output('Minilab3 MIDI')
def sysex(*bytes):
# This automatically adds the 0xF0 prefix and 0xF7 suffix.
# There is also an Arturia-specific prefix (00 20 6B 7F 42) but we keep that explicit in the messages below.
return mido.Message(
'sysex',
data=list(bytes)
)
def init():
# Initialization: needed for display changes. Not needed for pad color changes
# TODO: what exactly does this do?
port.send(sysex(
0x00,0x20,0x6B,0x7F,0x42,
0x02,0x02,0x40,0x6A,0x21, # sometimes suggested to be 0x20. Is this Arturia vs DAW?
))
#port.send(sysex(0x00,0x20,0x6B,0x7F,0x42, 0x01,0x00,0x40,0x03))
#port.send(sysex(0x00,0x20,0x6B,0x7F,0x42, 0x01,0x00,0x40,0x01))
#port.send(sysex(0x00,0x20,0x6b,0x7f,0x42, 0x04,0x01,0x60,0x0a,0x0a,0x5f,0x51,0x00))
def set_button_color(button, r=0x00, g=0x00, b=0x00):
assert button >= 0 and button <= 11, "pad must be 0..11"
assert r >= 0 and r <= 0x7F, "red must be 0x00..0x7F"
assert g >= 0 and g <= 0x7F, "green must be 0x00..0x7F"
assert b >= 0 and b <= 0x7F, "blue must be 0x00..0x7F"
port.send(sysex(
0x00, 0x20, 0x6B, 0x7F, 0x42,
0x02, 0x02, 0x16, button, r, g, b
))
pictures = {
'none': 0x00,
'heart': 0x01,
'play': 0x02,
'rec': 0x03,
'armed': 0x04,
'shift': 0x05,
}
def show_text(line1, line2, picture1='none', picture2='none'):
assert picture1 in pictures, "unknown picture1"
assert picture1 in pictures, "unknown picture2"
pict1 = pictures[picture1]
pict2 = pictures[picture2]
str1 = list(bytearray(line1, 'ascii'))
str2 = list(bytearray(line2, 'ascii'))
port.send(sysex(
0x00, 0x20, 0x6B, 0x7F, 0x42,
0x04, 0x02, 0x60,
0x1F, 0x07, 0x01, pict1, pict2, 0x01, 0x00,
# ^
# The Bitwig script also allows putting 0x02 here but I haven't seen a difference ¯\_(ツ)_/¯
0x01, *str1, 0x00,
0x02, *str2, 0x00,
))
def clear_text():
show_text('','')
def show_text_left(line1, line2):
str1 = list(bytearray(line1, 'ascii'))
str2 = list(bytearray(line2, 'ascii'))
port.send(sysex(
0x00, 0x20, 0x6B, 0x7F, 0x42,
0x04, 0x02, 0x60,
0x01, *str1, 0x00,
0x02, *str2,
))
controls = {
'knob': 0x03,
'fader': 0x04,
'pad': 0x05,
}
def show_info(line1, line2, value, control, autohide=True):
assert value >= 0 and value <= 127, "value must be 0..127"
assert type(autohide) == bool, "autohide must be bool"
assert control in controls
str1 = list(bytearray(line1, 'ascii'))
str2 = list(bytearray(line2, 'ascii'))
autohide_byte = 0x02 if autohide else 0x00
control_byte = controls[control]
port.send(sysex(
0x00, 0x20, 0x6B, 0x7F, 0x42,
0x04, 0x02, 0x60,
0x1F, control_byte, autohide_byte, value, 0x00, 0x00,
0x01, *str1, 0x00,
0x02, *str2,
))
def show_scroll_text(line1, line2, pos, length, autohide=True):
# Note that after autohide, the text from this invocation stays there
assert pos < length, "pos must < length"
assert pos >= 0, "pos must be positive"
assert length >= 0, "length must be positive"
assert type(autohide) == bool, "autohide must be bool"
control_byte = 0x06
autohide_byte = 0x02 if autohide else 0x00
str1 = list(bytearray(line1, 'ascii'))
str2 = list(bytearray(line2, 'ascii'))
port.send(sysex(
0x00, 0x20, 0x6B, 0x7F, 0x42,
0x04, 0x02, 0x60,
0x1F, control_byte, autohide_byte, pos, 0x00, length, 0x00, 0x00,
0x01, *str1, 0x00,
0x02, *str2, 0x00,
))
#init()
set_button_color( 0,0x00,0x00,0x00)
set_button_color( 1,0x7F,0x00,0x00)
set_button_color( 2,0x30,0x00,0x00)
set_button_color( 3,0x7F,0x7F,0x7F)
set_button_color( 4,0x30,0x30,0x30)
set_button_color( 5,0x00,0x7F,0x00)
set_button_color( 6,0x00,0x30,0x00)
set_button_color( 7,0x00,0x00,0x7F)
set_button_color( 8,0x00,0x00,0x30)
set_button_color( 9,0x7F,0x7F,0x00)
set_button_color(10,0x00,0x7F,0x7F)
set_button_color(11,0x7F,0x00,0x7F)
#clear_text()
#show_text('Hello', 'World!', 'heart', 'play')
#show_text('Hello', 'World!', picture1='heart', picture2='heart')
#show_text_left('Hello', 'World')
#show_info('Pad', 'Info', 0, control='pad')
#show_info('Pad', 'Info', 50, control='knob')
#show_info('Pad', 'Info', 127, control='fader')
#show_scroll_text('What', 'Whattt', 1, 5)
mido
python-rtmidi
mido[ports-rtmidi]
@cdiaz
Copy link

cdiaz commented Apr 3, 2024

Hello, I appreciate your work, it's great, it works for me, but only in DAW mode, do you know how to make sysex messages also act on Arturia mode?

@Janiczek
Copy link
Author

Janiczek commented Apr 3, 2024

Hey @cdiaz, you might want to experiment with the commented out lines in the init() function above, but I wasn't able to make things work. You might need to download and reverse-engineer the various integration scripts that Arturia provides to find out some magical SysEx message that does this :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment