Skip to content

Instantly share code, notes, and snippets.

@helgoboss
Last active June 6, 2023 10:00
Show Gist options
  • Save helgoboss/902d78137248da1683791e19d435be06 to your computer and use it in GitHub Desktop.
Save helgoboss/902d78137248da1683791e19d435be06 to your computer and use it in GitHub Desktop.
ReaLearn Lua MIDI script templates for programming the Novation SL MkIII via InControl API
-- ReaLearn Lua MIDI script template for programming the screens and LEDs of the Novation SL MkIII keyboard via InControl API
--
-- The section "Function" contains reusable helper functions for creating MIDI messages that change something on the
-- screen. The section "Code" makes use of the helper functions, so this is the section that you probably want to
-- adjust to your needs.
--
-- Hardware setup: Put the SL MkIII into InControl mode by pressing the corresponding button on the keyboard!
-- ReaLearn setup: Use the MIDI output "SL MkIII InControl" and add a mapping with a Lua "MIDI script" source!
--
-- See https://fael-downloads-prod.focusrite.com/customer/prod/s3fs-public/downloads/SLMkIII_Programmer%27s_Guide.pdf
-- for more info.
-- ## Functions ##
function to_ascii(text)
local bytes = {}
if text ~= nil then
for i = 1, string.len(text) do
local byte = string.byte(text, i)
if byte < 128 then
table.insert(bytes, byte)
end
end
end
-- Null terminator
table.insert(bytes, 0)
return bytes
end
function concat_table(t1, t2)
for i = 1, #t2 do
t1[#t1 + 1] = t2[i]
end
end
function create_msg(content)
-- SysEx Header
local msg = {
0xf0, 0x00, 0x20, 0x29, 0x02, 0x0a, 0x01,
}
-- Content
concat_table(msg, content)
-- End of SysEx
table.insert(msg, 0xf7)
return msg
end
--- Creates a message for changing the layout.
---
--- @param layout_index number layout index (0 = empty, 1 = knob, 2 = box)
function create_screen_layout_msg(layout_index)
return create_msg({ 0x01, layout_index })
end
--- Creates a message for displaying a notification on the center screen.
---
--- @param line1 string first line of text
--- @param line2 string second line of text
function create_notification_text_msg(line1, line2)
local content = { 0x04 }
concat_table(content, to_ascii(line1))
concat_table(content, to_ascii(line2))
return create_msg(content)
end
--- Creates a message for changing multiple screen properties.
---
--- @param changes table list of property changes
function create_screen_props_msg(changes)
local content = { 0x02 }
for i = 1, #changes do
if changes[i] ~= nil then
concat_table(content, changes[i])
end
end
return create_msg(content)
end
--- Creates a text property change.
---
--- @param column_index number in which column to display the text
--- @param object_index number in which location to display the text
--- @param text string the actual text
function create_text_prop_change(column_index, object_index, text)
local change = {
-- Column Index
column_index,
-- Property Type "Text"
0x01,
-- Object Index
object_index,
}
concat_table(change, to_ascii(text))
return change
end
--- Creates a value property change.
---
--- If it's about setting the knob value, it's usually more intuitive to not
--- do this via script but by enabling feedback on the corresponding encoder
--- mappings, then you need just one mapping for both control and feedback.
---
--- @param column_index number in which column to change the value
--- @param object_index number the kind of value to change (see programmer's guide)
--- @param value number the value
function create_value_prop_change(column_index, object_index, value)
return {
-- Column Index
column_index,
-- Property Type "Value"
0x03,
-- Object Index
object_index,
-- Color bytes
value
}
end
--- Creates an RGB color property change.
---
--- If the given color is `nil`, this function returns `nil`.
---
--- @param column_index number in which column to change the color
--- @param object_index number in which location to change the color
--- @param color table the RGB color (table with properties r, g and b)
function create_rgb_color_prop_change(column_index, object_index, color)
if color == null then
return nil
end
return {
-- Column Index
column_index,
-- Property Type "RGB color"
0x04,
-- Object Index
object_index,
-- Color bytes
math.floor(color.r / 2),
math.floor(color.g / 2),
math.floor(color.b / 2),
}
end
--- Creates a message for changing the state of an LED.
---
--- Passing a `nil` color will make the LED go off.
---
--- @param led_index number which LED to talk to
--- @param led_behavior number LED behavior (1 = solid, 2 = flashing with previously set solid color, 3 = pulsating)
--- @param color table the RGB color (table with properties r, g and b)
function create_led_msg(led_index, led_behavior, color)
if color == nil then
color = { r = 0, g = 0, b = 0 }
end
return create_msg({
0x03,
led_index,
led_behavior,
math.floor(color.r / 2),
math.floor(color.g / 2),
math.floor(color.b / 2),
})
end
-- ## Code ##
-- In this example, we send a bunch of different changes at once in order to demonstrate the possibilities. In a real-world
-- scenario you would probably send less changes within one mapping.
local column = 0
local white = { r = 255, g = 255, b = 255 }
return {
-- In real-world scenarios, you probably want to set the address to a number that uniquely and
-- globally identifies the screen element that you are changing. Otherwise, ReaLearn has no way
-- to prevent unnecessary duplicate feedback and might exhibit strange behavior when switching
-- between multiple mappings that change the same screen element.
address = nil,
messages = {
-- Display a short notification on the center screen
create_notification_text_msg("Hello", "World"),
-- Use the knob layout for all normal screens
create_screen_layout_msg(1),
-- Send some properties for the configured column
create_screen_props_msg({
-- Set the top bar color to the color configured in the "Glue" section
create_rgb_color_prop_change(column, 0, context.feedback_event.color),
-- Make the knob visible (by making it white)
create_rgb_color_prop_change(column, 1, white),
-- Make the bottom bar color appear white (when lower text selected)
create_rgb_color_prop_change(column, 2, white),
-- Make the upper text label show the parameter value
create_text_prop_change(column, 0, y),
-- Make the lower text label show some other text
create_text_prop_change(column, 3, "Volume"),
-- Make the lower text label appear selected
create_value_prop_change(column, 1, 1),
}),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment