Vendor helgoboss/helgobox (ReaLearn) as basis for custom UI fork
Stripped upstream git history; starting point for replacing the native SWELL/Win32 mapping UI with something more suited to bulk editing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
../../api/luau/.stylua.toml
|
||||
@@ -0,0 +1 @@
|
||||
../../api/luau/.vscode
|
||||
@@ -0,0 +1 @@
|
||||
../../api/luau/README.md
|
||||
+1617
File diff suppressed because it is too large
Load Diff
+1650
File diff suppressed because it is too large
Load Diff
+254
@@ -0,0 +1,254 @@
|
||||
--- name: APC mini mk2
|
||||
--- realearn_version: 2.16.0-pre.8
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: Akai
|
||||
--- device_name: APC mini mk2
|
||||
--- description: |
|
||||
--- This controller preset exposes all control elements of the APC mini mk2 in a neutral way. It supports
|
||||
--- ReaLearn color feedback as well as Playtime slot status feedback.
|
||||
--- midi_identity_pattern: F0 7E ? 06 02 47 4F 00 19 * F7
|
||||
--- # This device exposes 2 USB MIDI ports, one for "Notes" and one for "Control". We are
|
||||
--- # interested in "Control". Both MIDI ports reply with the same device identity. If we
|
||||
--- # don't provide a MIDI output device pattern, it's possible that ReaLearn's automatic
|
||||
--- # controller detection feature takes the "Notes" port ... and things wouldn't work!
|
||||
--- # On Windows, the naming is different, that's why there's also "MIDIOUT2".
|
||||
--- midi_output_port_patterns: ["macos:*Control*", "windows:APC mini mk2"]
|
||||
--- provided_schemes: [akai/apc-mini-mk2, grid]
|
||||
|
||||
--!strict
|
||||
|
||||
-- Configuration
|
||||
|
||||
local resolve_shift = false
|
||||
|
||||
-- Requires
|
||||
|
||||
local preset_runtime = require("preset_runtime")
|
||||
local realearn = require("realearn")
|
||||
|
||||
-- Define MIDI scripts
|
||||
|
||||
local common_lua = preset_runtime.include_str("akai/apc-mk2-lib/compartment-common.luau")
|
||||
|
||||
local function build_pad_script(pad_index: number): string
|
||||
return `return require("compartment").pad_script({pad_index}, y, context)`
|
||||
end
|
||||
|
||||
-- Parameters
|
||||
|
||||
local shift_param = realearn.Parameter {
|
||||
index = 0,
|
||||
name = "Shift",
|
||||
}
|
||||
local parameters: { realearn.Parameter }? = if resolve_shift then { shift_param } else nil
|
||||
|
||||
-- Single buttons
|
||||
|
||||
local function simple_button(id: string, name: string, key_number: number): realearn.Mapping
|
||||
return realearn.Mapping {
|
||||
id = id,
|
||||
name = name,
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = key_number,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local mappings: { realearn.Mapping } = {
|
||||
-- Main fader
|
||||
{
|
||||
id = "fm",
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = 56,
|
||||
character = "Range",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "main/fader",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
-- Shift
|
||||
local no_shift_activation_condition: realearn.ActivationCondition?
|
||||
if resolve_shift then
|
||||
-- The activation condition reflecting the state that shift is not pressed.
|
||||
no_shift_activation_condition = realearn.ActivationCondition.Modifier {
|
||||
modifiers = {
|
||||
{
|
||||
parameter = 0,
|
||||
on = false,
|
||||
},
|
||||
},
|
||||
}
|
||||
-- Mapping to make shift button switch to other set of virtual control elements
|
||||
local shift_mapping = realearn.Mapping {
|
||||
name = "Shift",
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 122,
|
||||
},
|
||||
target = realearn.Target.CompartmentParameterValue {
|
||||
parameter = realearn.CompartmentParameterDescriptor.ById {
|
||||
index = 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
table.insert(mappings, shift_mapping)
|
||||
-- Alternative set of virtual control elements
|
||||
local alt_elements = {
|
||||
{ key = 104, id = "cursor-up" },
|
||||
{ key = 105, id = "cursor-down" },
|
||||
{ key = 106, id = "cursor-left" },
|
||||
{ key = 107, id = "cursor-right" },
|
||||
{ key = 100, id = "volume" },
|
||||
{ key = 101, id = "pan" },
|
||||
{ key = 102, id = "sends" },
|
||||
{ key = 103, id = "device" },
|
||||
{ key = 112, id = "stop-clip" },
|
||||
{ key = 113, id = "solo" },
|
||||
{ key = 114, id = "mute" },
|
||||
{ key = 115, id = "record-arm" },
|
||||
{ key = 116, id = "track-select" },
|
||||
{ key = 117, id = "drum" },
|
||||
{ key = 118, id = "note" },
|
||||
{ key = 119, id = "stop-all-clips" },
|
||||
}
|
||||
for _, element in ipairs(alt_elements) do
|
||||
local mapping = realearn.Mapping {
|
||||
activation_condition = realearn.ActivationCondition.Modifier {
|
||||
modifiers = {
|
||||
{
|
||||
parameter = 0,
|
||||
on = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = element.key,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = element.id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
else
|
||||
no_shift_activation_condition = nil
|
||||
local mapping = simple_button("shift", "Shift", 122)
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
-- Channel faders
|
||||
for i = 0, 7 do
|
||||
local human_i = i + 1
|
||||
local mapping = realearn.Mapping {
|
||||
id = `f{human_i}`,
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = 48 + i,
|
||||
character = "Range",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = i,
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
-- Clip launch buttons
|
||||
for col = 0, 7 do
|
||||
local human_col = col + 1
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local key_number_offset = (7 - row) * 8
|
||||
local id = `col{human_col}/row{human_row}/pad`
|
||||
local control_mapping = realearn.Mapping {
|
||||
id = id,
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = key_number_offset + col,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Multi",
|
||||
},
|
||||
}
|
||||
local feedback_mapping = realearn.Mapping {
|
||||
id = `{id}-feedback`,
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiScript {
|
||||
script_kind = "Lua",
|
||||
script = build_pad_script(key_number_offset + col),
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Multi",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, control_mapping)
|
||||
table.insert(mappings, feedback_mapping)
|
||||
end
|
||||
end
|
||||
|
||||
-- Clip stop buttons
|
||||
for col = 0, 7 do
|
||||
local human_col = col + 1
|
||||
local id = `col{human_col}/stop`
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
activation_condition = no_shift_activation_condition,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 100 + col,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
-- Scene launch buttons
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local id = `row{human_row}/play`
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
activation_condition = no_shift_activation_condition,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 112 + row,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
return realearn.Compartment {
|
||||
parameters = parameters,
|
||||
mappings = mappings,
|
||||
common_lua = common_lua,
|
||||
custom_data = {
|
||||
grid = {
|
||||
column_count = 8,
|
||||
row_count = 8,
|
||||
},
|
||||
},
|
||||
}
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
--- name: APC mini
|
||||
--- realearn_version: 2.16.0-pre.8
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: Akai
|
||||
--- device_name: APC mini
|
||||
--- description: |
|
||||
--- This controller preset exposes all control elements of the APC mini mk2 in a neutral way. It supports
|
||||
--- Playtime slot status feedback.
|
||||
--- midi_identity_pattern: F0 7E ? 06 02 47 28 00 19 * F7
|
||||
--- provided_schemes: [akai/apc-mini, grid]
|
||||
|
||||
--!strict
|
||||
|
||||
-- Configuration
|
||||
|
||||
local resolve_shift = false
|
||||
|
||||
-- Requires
|
||||
|
||||
local realearn = require("realearn")
|
||||
|
||||
-- Parameters
|
||||
|
||||
local shift_param = realearn.Parameter {
|
||||
index = 0,
|
||||
name = "Shift",
|
||||
}
|
||||
local parameters: { realearn.Parameter }? = if resolve_shift then { shift_param } else nil
|
||||
|
||||
-- Single buttons
|
||||
|
||||
local function simple_button(id: string, name: string, key_number: number): realearn.Mapping
|
||||
return realearn.Mapping {
|
||||
id = id,
|
||||
name = name,
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = key_number,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local mappings: { realearn.Mapping } = {
|
||||
-- Main fader
|
||||
{
|
||||
id = "fm",
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = 56,
|
||||
character = "Range",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "main/fader",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
-- Shift
|
||||
local no_shift_activation_condition: realearn.ActivationCondition?
|
||||
if resolve_shift then
|
||||
-- The activation condition reflecting the state that shift is not pressed.
|
||||
no_shift_activation_condition = realearn.ActivationCondition.Modifier {
|
||||
modifiers = {
|
||||
{
|
||||
parameter = 0,
|
||||
on = false,
|
||||
},
|
||||
},
|
||||
}
|
||||
-- Mapping to make shift button switch to other set of virtual control elements
|
||||
local shift_mapping = realearn.Mapping {
|
||||
name = "Shift",
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 98,
|
||||
},
|
||||
target = realearn.Target.CompartmentParameterValue {
|
||||
parameter = realearn.CompartmentParameterDescriptor.ById {
|
||||
index = 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
table.insert(mappings, shift_mapping)
|
||||
-- Alternative set of virtual control elements
|
||||
local alt_elements = {
|
||||
{ key = 64, id = "cursor-up" },
|
||||
{ key = 65, id = "cursor-down" },
|
||||
{ key = 66, id = "cursor-left" },
|
||||
{ key = 67, id = "cursor-right" },
|
||||
{ key = 68, id = "volume" },
|
||||
{ key = 69, id = "pan" },
|
||||
{ key = 70, id = "sends" },
|
||||
{ key = 71, id = "device" },
|
||||
{ key = 82, id = "stop-clip" },
|
||||
{ key = 83, id = "solo" },
|
||||
{ key = 84, id = "record-arm" },
|
||||
{ key = 85, id = "mute" },
|
||||
{ key = 86, id = "track-select" },
|
||||
{ key = 89, id = "stop-all-clips" },
|
||||
}
|
||||
for _, element in ipairs(alt_elements) do
|
||||
local mapping = realearn.Mapping {
|
||||
activation_condition = realearn.ActivationCondition.Modifier {
|
||||
modifiers = {
|
||||
{
|
||||
parameter = 0,
|
||||
on = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = element.key,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = element.id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
else
|
||||
no_shift_activation_condition = nil
|
||||
local mapping = simple_button("shift", "Shift", 98)
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
-- Channel faders
|
||||
for i = 0, 7 do
|
||||
local human_i = i + 1
|
||||
local mapping = realearn.Mapping {
|
||||
id = `f{human_i}`,
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = 48 + i,
|
||||
character = "Range",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = i,
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
-- Clip launch buttons
|
||||
local feedback_value_table = realearn.FeedbackValueTable.FromTextToDiscrete {
|
||||
value = {
|
||||
-- Off
|
||||
["playtime.slot_state.empty"] = 0,
|
||||
-- Red
|
||||
["playtime.slot_state.armed"] = 0,
|
||||
-- Yellow
|
||||
["playtime.slot_state.stopped"] = 5,
|
||||
-- Green blinking
|
||||
["playtime.slot_state.scheduled_for_play_start"] = 2,
|
||||
-- Green
|
||||
["playtime.slot_state.playing"] = 1,
|
||||
-- Yellow
|
||||
["playtime.slot_state.paused"] = 5,
|
||||
-- Yellow blinking
|
||||
["playtime.slot_state.scheduled_for_play_stop"] = 6,
|
||||
-- Yellow blinking
|
||||
["playtime.slot_state.scheduled_for_play_restart"] = 6,
|
||||
-- Red blinking
|
||||
["playtime.slot_state.scheduled_for_record_start"] = 4,
|
||||
-- Red
|
||||
["playtime.slot_state.recording"] = 3,
|
||||
-- Yellow blinking
|
||||
["playtime.slot_state.scheduled_for_record_stop"] = 6,
|
||||
},
|
||||
}
|
||||
for col = 0, 7 do
|
||||
local human_col = col + 1
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local key_number_offset = (7 - row) * 8
|
||||
local id = `col{human_col}/row{human_row}/pad`
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = key_number_offset + col,
|
||||
},
|
||||
glue = {
|
||||
feedback_value_table = feedback_value_table,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Multi",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
end
|
||||
|
||||
-- Clip stop buttons
|
||||
for col = 0, 7 do
|
||||
local human_col = col + 1
|
||||
local id = `col{human_col}/stop`
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
activation_condition = no_shift_activation_condition,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 64 + col,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
-- Scene launch buttons
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local id = `row{human_row}/play`
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
activation_condition = no_shift_activation_condition,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 82 + row,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
return realearn.Compartment {
|
||||
parameters = parameters,
|
||||
mappings = mappings,
|
||||
custom_data = {
|
||||
grid = {
|
||||
column_count = 8,
|
||||
row_count = 8,
|
||||
},
|
||||
},
|
||||
}
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
--!strict
|
||||
|
||||
local midi_script = require("midi_script_source_runtime")
|
||||
|
||||
local module = {}
|
||||
|
||||
type FeedbackEntry = {
|
||||
behavior: number,
|
||||
color: number?,
|
||||
}
|
||||
local dark = 0x91
|
||||
local medium = 0x93
|
||||
local bright = 0x96
|
||||
local pulsing = 0x9A
|
||||
local blinking = 0x9B
|
||||
local red_color = 6
|
||||
local default_color = 3
|
||||
local feedback_table: { [string]: FeedbackEntry? } = {
|
||||
["playtime.slot_state.empty"] = {
|
||||
behavior = dark,
|
||||
color = 0,
|
||||
},
|
||||
["playtime.slot_state.armed"] = {
|
||||
behavior = dark,
|
||||
color = red_color,
|
||||
},
|
||||
["playtime.slot_state.stopped"] = {
|
||||
behavior = dark,
|
||||
},
|
||||
["playtime.slot_state.ignited"] = {
|
||||
behavior = dark,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_play_start"] = {
|
||||
behavior = medium,
|
||||
},
|
||||
["playtime.slot_state.playing"] = {
|
||||
behavior = pulsing,
|
||||
},
|
||||
["playtime.slot_state.paused"] = {
|
||||
behavior = medium,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_play_stop"] = {
|
||||
behavior = blinking,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_play_restart"] = {
|
||||
behavior = blinking,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_record_start"] = {
|
||||
behavior = medium,
|
||||
color = red_color,
|
||||
},
|
||||
["playtime.slot_state.recording"] = {
|
||||
behavior = pulsing,
|
||||
color = red_color,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_record_stop"] = {
|
||||
behavior = blinking,
|
||||
color = red_color,
|
||||
},
|
||||
}
|
||||
|
||||
--- Although I got the true RGB colors to work, it was impossible to combine them with blinking
|
||||
--- or pulsing behavior. So back to good old color palette.
|
||||
local color_palette: { midi_script.RgbColor } = {
|
||||
{r = 0x00, g= 0x00, b = 0x00},
|
||||
{r = 0x1E, g= 0x1E, b = 0x1E},
|
||||
{r = 0x7F, g= 0x7F, b = 0x7F},
|
||||
{r = 0xFF, g= 0xFF, b = 0xFF},
|
||||
{r = 0xFF, g= 0x4C, b = 0x4C},
|
||||
{r = 0xFF, g= 0x00, b = 0x00},
|
||||
{r = 0x59, g= 0x00, b = 0x00},
|
||||
{r = 0x19, g= 0x00, b = 0x00},
|
||||
{r = 0xFF, g= 0xBD, b = 0x6C},
|
||||
{r = 0xFF, g= 0x54, b = 0x00},
|
||||
{r = 0x59, g= 0x1D, b = 0x00},
|
||||
{r = 0x27, g= 0x1B, b = 0x00},
|
||||
{r = 0xFF, g= 0xFF, b = 0x4C},
|
||||
{r = 0xFF, g= 0xFF, b = 0x00},
|
||||
{r = 0x59, g= 0x59, b = 0x00},
|
||||
{r = 0x19, g= 0x19, b = 0x00},
|
||||
{r = 0x88, g= 0xFF, b = 0x4C},
|
||||
{r = 0x54, g= 0xFF, b = 0x00},
|
||||
{r = 0x1D, g= 0x59, b = 0x00},
|
||||
{r = 0x14, g= 0x2B, b = 0x00},
|
||||
{r = 0x4C, g= 0xFF, b = 0x4C},
|
||||
{r = 0x00, g= 0xFF, b = 0x00},
|
||||
{r = 0x00, g= 0x59, b = 0x00},
|
||||
{r = 0x00, g= 0x19, b = 0x00},
|
||||
{r = 0x4C, g= 0xFF, b = 0x5E},
|
||||
{r = 0x00, g= 0xFF, b = 0x19},
|
||||
{r = 0x00, g= 0x59, b = 0x0D},
|
||||
{r = 0x00, g= 0x19, b = 0x02},
|
||||
{r = 0x4C, g= 0xFF, b = 0x88},
|
||||
{r = 0x00, g= 0xFF, b = 0x55},
|
||||
{r = 0x00, g= 0x59, b = 0x1D},
|
||||
{r = 0x00, g= 0x1F, b = 0x12},
|
||||
{r = 0x4C, g= 0xFF, b = 0xB7},
|
||||
{r = 0x00, g= 0xFF, b = 0x99},
|
||||
{r = 0x00, g= 0x59, b = 0x35},
|
||||
{r = 0x00, g= 0x19, b = 0x12},
|
||||
{r = 0x4C, g= 0xC3, b = 0xFF},
|
||||
{r = 0x00, g= 0xA9, b = 0xFF},
|
||||
{r = 0x00, g= 0x41, b = 0x52},
|
||||
{r = 0x00, g= 0x10, b = 0x19},
|
||||
{r = 0x4C, g= 0x88, b = 0xFF},
|
||||
{r = 0x00, g= 0x55, b = 0xFF},
|
||||
{r = 0x00, g= 0x1D, b = 0x59},
|
||||
{r = 0x00, g= 0x08, b = 0x19},
|
||||
{r = 0x4C, g= 0x4C, b = 0xFF},
|
||||
{r = 0x00, g= 0x00, b = 0xFF},
|
||||
{r = 0x00, g= 0x00, b = 0x59},
|
||||
{r = 0x00, g= 0x00, b = 0x19},
|
||||
{r = 0x87, g= 0x4C, b = 0xFF},
|
||||
{r = 0x54, g= 0x00, b = 0xFF},
|
||||
{r = 0x19, g= 0x00, b = 0x64},
|
||||
{r = 0x0F, g= 0x00, b = 0x30},
|
||||
{r = 0xFF, g= 0x4C, b = 0xFF},
|
||||
{r = 0xFF, g= 0x00, b = 0xFF},
|
||||
{r = 0x59, g= 0x00, b = 0x59},
|
||||
{r = 0x19, g= 0x00, b = 0x19},
|
||||
{r = 0xFF, g= 0x4C, b = 0x87},
|
||||
{r = 0xFF, g= 0x00, b = 0x54},
|
||||
{r = 0x59, g= 0x00, b = 0x1D},
|
||||
{r = 0x22, g= 0x00, b = 0x13},
|
||||
{r = 0xFF, g= 0x15, b = 0x00},
|
||||
{r = 0x99, g= 0x35, b = 0x00},
|
||||
{r = 0x79, g= 0x51, b = 0x00},
|
||||
{r = 0x43, g= 0x64, b = 0x00},
|
||||
{r = 0x03, g= 0x39, b = 0x00},
|
||||
{r = 0x00, g= 0x57, b = 0x35},
|
||||
{r = 0x00, g= 0x54, b = 0x7F},
|
||||
{r = 0x00, g= 0x00, b = 0xFF},
|
||||
{r = 0x00, g= 0x45, b = 0x4F},
|
||||
{r = 0x25, g= 0x00, b = 0xCC},
|
||||
{r = 0x7F, g= 0x7F, b = 0x7F},
|
||||
{r = 0x20, g= 0x20, b = 0x20},
|
||||
{r = 0xFF, g= 0x00, b = 0x00},
|
||||
{r = 0xBD, g= 0xFF, b = 0x2D},
|
||||
{r = 0xAF, g= 0xED, b = 0x06},
|
||||
{r = 0x64, g= 0xFF, b = 0x09},
|
||||
{r = 0x10, g= 0x8B, b = 0x00},
|
||||
{r = 0x00, g= 0xFF, b = 0x87},
|
||||
{r = 0x00, g= 0xA9, b = 0xFF},
|
||||
{r = 0x00, g= 0x2A, b = 0xFF},
|
||||
{r = 0x3F, g= 0x00, b = 0xFF},
|
||||
{r = 0x7A, g= 0x00, b = 0xFF},
|
||||
{r = 0xB2, g= 0x1A, b = 0x7D},
|
||||
{r = 0x40, g= 0x21, b = 0x00},
|
||||
{r = 0xFF, g= 0x4A, b = 0x00},
|
||||
{r = 0x88, g= 0xE1, b = 0x06},
|
||||
{r = 0x72, g= 0xFF, b = 0x15},
|
||||
{r = 0x00, g= 0xFF, b = 0x00},
|
||||
{r = 0x3B, g= 0xFF, b = 0x26},
|
||||
{r = 0x59, g= 0xFF, b = 0x71},
|
||||
{r = 0x38, g= 0xFF, b = 0xCC},
|
||||
{r = 0x5B, g= 0x8A, b = 0xFF},
|
||||
{r = 0x31, g= 0x51, b = 0xC6},
|
||||
{r = 0x87, g= 0x7F, b = 0xE9},
|
||||
{r = 0xD3, g= 0x1D, b = 0xFF},
|
||||
{r = 0xFF, g= 0x00, b = 0x5D},
|
||||
{r = 0xFF, g= 0x7F, b = 0x00},
|
||||
{r = 0xB9, g= 0xB0, b = 0x00},
|
||||
{r = 0x90, g= 0xFF, b = 0x00},
|
||||
{r = 0x83, g= 0x5D, b = 0x07},
|
||||
{r = 0x39, g= 0x2b, b = 0x00},
|
||||
{r = 0x14, g= 0x4C, b = 0x10},
|
||||
{r = 0x0D, g= 0x50, b = 0x38},
|
||||
{r = 0x15, g= 0x15, b = 0x2A},
|
||||
{r = 0x16, g= 0x20, b = 0x5A},
|
||||
{r = 0x69, g= 0x3C, b = 0x1C},
|
||||
{r = 0xA8, g= 0x00, b = 0x0A},
|
||||
{r = 0xDE, g= 0x51, b = 0x3D},
|
||||
{r = 0xD8, g= 0x6A, b = 0x1C},
|
||||
{r = 0xFF, g= 0xE1, b = 0x26},
|
||||
{r = 0x9E, g= 0xE1, b = 0x2F},
|
||||
{r = 0x67, g= 0xB5, b = 0x0F},
|
||||
{r = 0x1E, g= 0x1E, b = 0x30},
|
||||
{r = 0xDC, g= 0xFF, b = 0x6B},
|
||||
{r = 0x80, g= 0xFF, b = 0xBD},
|
||||
{r = 0x9A, g= 0x99, b = 0xFF},
|
||||
{r = 0x8E, g= 0x66, b = 0xFF},
|
||||
{r = 0x40, g= 0x40, b = 0x40},
|
||||
{r = 0x75, g= 0x75, b = 0x75},
|
||||
{r = 0xE0, g= 0xFF, b = 0xFF},
|
||||
{r = 0xA0, g= 0x00, b = 0x00},
|
||||
{r = 0x35, g= 0x00, b = 0x00},
|
||||
{r = 0x1A, g= 0xD0, b = 0x00},
|
||||
{r = 0x07, g= 0x42, b = 0x00},
|
||||
{r = 0xB9, g= 0xB0, b = 0x00},
|
||||
{r = 0x3F, g= 0x31, b = 0x00},
|
||||
{r = 0xB3, g= 0x5F, b = 0x00},
|
||||
{r = 0x4B, g= 0x15, b = 0x02},
|
||||
{r = 0x40, g= 0x40, b = 0x40},
|
||||
{r = 0x75, g= 0x75, b = 0x75},
|
||||
{r = 0xE0, g= 0xFF, b = 0xFF},
|
||||
{r = 0xA0, g= 0x00, b = 0x00},
|
||||
{r = 0x35, g= 0x00, b = 0x00},
|
||||
{r = 0x1A, g= 0xD0, b = 0x00},
|
||||
{r = 0x07, g= 0x42, b = 0x00},
|
||||
{r = 0xB9, g= 0xB0, b = 0x00},
|
||||
{r = 0x3F, g= 0x31, b = 0x00},
|
||||
{r = 0xB3, g= 0x5F, b = 0x00},
|
||||
{r = 0x4B, g= 0x15, b = 0x02},
|
||||
}
|
||||
|
||||
--- Returns the 0-based index within the given palette array.
|
||||
local function find_closest_color_in_palette(color: midi_script.RgbColor, palette: {midi_script.RgbColor}): number
|
||||
local ifurthest = 0
|
||||
local furthest = 3 * math.pow(255, 2) + 1
|
||||
for i,c in palette do
|
||||
if color.r == c.r and color.g == c.g and color.b == c.b then
|
||||
return i - 1
|
||||
end
|
||||
local distance = math.pow((color.r - c.r), 2) + math.pow((color.g - c.g), 2) + math.pow((color.b - c.b), 2)
|
||||
if distance < furthest then
|
||||
furthest = distance
|
||||
ifurthest = i - 1
|
||||
end
|
||||
end
|
||||
return ifurthest
|
||||
end
|
||||
|
||||
function module.pad_script(pad_index: number, y: midi_script.InputValue, context: midi_script.Context): midi_script.Output
|
||||
local address = pad_index
|
||||
local off_color = 0x00
|
||||
local off_output = {
|
||||
address = address,
|
||||
messages = {
|
||||
{ bright, pad_index, off_color },
|
||||
},
|
||||
}
|
||||
-- Handle "off" feedback
|
||||
if y == nil then
|
||||
return off_output
|
||||
end
|
||||
-- Handle numeric feedback
|
||||
if type(y) == "number" then
|
||||
-- Translate number to solid feedback color, just as with APC Key 25 mk1
|
||||
local color = math.floor(y * 127)
|
||||
return {
|
||||
address = address,
|
||||
messages = {
|
||||
{ bright, pad_index, color },
|
||||
},
|
||||
}
|
||||
end
|
||||
-- Handle text feedback
|
||||
if type(y) == "string" then
|
||||
-- This is a grid controller, typically used for controlling a Playtime matrix, so we should be able to
|
||||
-- handle text feedback that conforms to Playtime's clip state convention.
|
||||
local entry = feedback_table[y]
|
||||
if entry == nil then
|
||||
-- Unknown texts switch the LED off
|
||||
return off_output
|
||||
end
|
||||
local explicit_color = entry.color
|
||||
if explicit_color ~= nil then
|
||||
-- Switch LED to explicit color
|
||||
return {
|
||||
address = address,
|
||||
messages = {
|
||||
{ entry.behavior, pad_index, explicit_color },
|
||||
},
|
||||
}
|
||||
end
|
||||
-- No explicit color means we should use the event color (which is set in the "Glue" section)
|
||||
local event_color = context.feedback_event.color
|
||||
if event_color == nil then
|
||||
-- Event has default color / no specific color
|
||||
return {
|
||||
address = address,
|
||||
messages = {
|
||||
{ entry.behavior, pad_index, default_color },
|
||||
},
|
||||
}
|
||||
end
|
||||
-- Find color available on the controller that's closest to the desired RGB color
|
||||
local closest_color = find_closest_color_in_palette(event_color, color_palette)
|
||||
return {
|
||||
address = address,
|
||||
messages = {
|
||||
{ entry.behavior, pad_index, closest_color },
|
||||
},
|
||||
}
|
||||
end
|
||||
-- Complex feedback is highly individual. It doesn't make sense to handle this in a general-purpose controller preset.
|
||||
return {
|
||||
address = address,
|
||||
messages = {},
|
||||
}
|
||||
end
|
||||
|
||||
return module
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
--- name: X-Touch One
|
||||
--- realearn_version: 2.16.0
|
||||
--- author: helgoboss
|
||||
--- description: |
|
||||
--- This controller preset implements support for the Behringer X-Touch One controller in MCU mode.
|
||||
---
|
||||
--- The MC modes cover all buttons and work great with the "Mackie Control" preset. A potential
|
||||
--- downside is that the device itself controls the "Master" button, so you can’t use that button in
|
||||
--- ReaLearn to customize its logic.
|
||||
--- setup_instructions: |
|
||||
--- Select the correct mode by holding the stop button and pressing the encoder:
|
||||
---
|
||||
--- - If you have firmware < 1.10 (the firmware is displayed at startup), use mode "MC Std"
|
||||
--- - If you have at least firmware 1.10, use mode "MC user"
|
||||
--- device_manufacturer: Behringer
|
||||
--- device_name: X-Touch One
|
||||
--- provided_schemes: [daw]
|
||||
|
||||
--!strict
|
||||
|
||||
local commons = require("mackie/control-universal-lib/preset-common")
|
||||
|
||||
return commons.create_compartment {
|
||||
companion_data = nil,
|
||||
support_x_touch_colors = true,
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
--- name: Midi Fighter Twister - Grid
|
||||
--- realearn_version: 2.16.0-pre.8
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: DJ TechTools
|
||||
--- device_name: Midi Fighter Twister
|
||||
--- description: |
|
||||
--- This controller preset exposes the push encoders of the Midi Fighter Twister with the "grid" scheme, which means
|
||||
--- it uses virtual element IDs such as "col1/row1/pad". This makes it compatible with main presets that are
|
||||
--- built for generic grid controllers.
|
||||
--- setup_instructions: |
|
||||
--- The Midi Fighter Twister is a very customizable controller. Please follow the instructions at
|
||||
--- https://github.com/helgoboss/helgobox/blob/master/doc/controllers.adoc#dj-techtools-midi-fighter-twister
|
||||
--- to make it ready for ReaLearn.
|
||||
--- midi_identity_pattern: F0 7E ? 06 02 00 01 79 05 00 01 00 * F7
|
||||
--- provided_schemes: [djtechtools/midi-fighter-twister/grid, grid]
|
||||
|
||||
--!strict
|
||||
|
||||
local realearn = require("realearn")
|
||||
local commons = require("djtechtools/midi-fighter-twister-lib/preset-common")
|
||||
|
||||
return commons.create_compartment {
|
||||
create_push_target = function (col, row)
|
||||
return realearn.Target.Virtual {
|
||||
id = `col{col +1 }/row{row + 1}/pad`,
|
||||
character = "Multi",
|
||||
}
|
||||
end,
|
||||
create_turn_target = function (col, row)
|
||||
return realearn.Target.Virtual {
|
||||
id = `col{col +1 }/row{row + 1}/knob`,
|
||||
character = "Multi",
|
||||
}
|
||||
end,
|
||||
}
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
--!strict
|
||||
|
||||
local midi_script = require("midi_script_source_runtime")
|
||||
|
||||
local module = {}
|
||||
|
||||
local color_palette: { midi_script.RgbColor } = {
|
||||
{ r = 0, g = 0, b = 0 },
|
||||
{ r = 0, g = 0, b = 255 },
|
||||
{ r = 0, g = 21, b = 255 },
|
||||
{ r = 0, g = 34, b = 255 },
|
||||
{ r = 0, g = 46, b = 255 },
|
||||
{ r = 0, g = 59, b = 255 },
|
||||
{ r = 0, g = 68, b = 255 },
|
||||
{ r = 0, g = 80, b = 255 },
|
||||
{ r = 0, g = 93, b = 255 },
|
||||
{ r = 0, g = 106, b = 255 },
|
||||
{ r = 0, g = 119, b = 255 },
|
||||
{ r = 0, g = 127, b = 255 },
|
||||
{ r = 0, g = 140, b = 255 },
|
||||
{ r = 0, g = 153, b = 255 },
|
||||
{ r = 0, g = 165, b = 255 },
|
||||
{ r = 0, g = 178, b = 255 },
|
||||
{ r = 0, g = 191, b = 255 },
|
||||
{ r = 0, g = 199, b = 255 },
|
||||
{ r = 0, g = 212, b = 255 },
|
||||
{ r = 0, g = 225, b = 255 },
|
||||
{ r = 0, g = 238, b = 255 },
|
||||
{ r = 0, g = 250, b = 255 },
|
||||
{ r = 0, g = 255, b = 250 },
|
||||
{ r = 0, g = 255, b = 237 },
|
||||
{ r = 0, g = 255, b = 225 },
|
||||
{ r = 0, g = 255, b = 212 },
|
||||
{ r = 0, g = 255, b = 199 },
|
||||
{ r = 0, g = 255, b = 191 },
|
||||
{ r = 0, g = 255, b = 178 },
|
||||
{ r = 0, g = 255, b = 165 },
|
||||
{ r = 0, g = 255, b = 153 },
|
||||
{ r = 0, g = 255, b = 140 },
|
||||
{ r = 0, g = 255, b = 127 },
|
||||
{ r = 0, g = 255, b = 119 },
|
||||
{ r = 0, g = 255, b = 106 },
|
||||
{ r = 0, g = 255, b = 93 },
|
||||
{ r = 0, g = 255, b = 80 },
|
||||
{ r = 0, g = 255, b = 67 },
|
||||
{ r = 0, g = 255, b = 59 },
|
||||
{ r = 0, g = 255, b = 46 },
|
||||
{ r = 0, g = 255, b = 33 },
|
||||
{ r = 0, g = 255, b = 21 },
|
||||
{ r = 0, g = 255, b = 8 },
|
||||
{ r = 0, g = 255, b = 0 },
|
||||
{ r = 12, g = 255, b = 0 },
|
||||
{ r = 25, g = 255, b = 0 },
|
||||
{ r = 38, g = 255, b = 0 },
|
||||
{ r = 51, g = 255, b = 0 },
|
||||
{ r = 63, g = 255, b = 0 },
|
||||
{ r = 72, g = 255, b = 0 },
|
||||
{ r = 84, g = 255, b = 0 },
|
||||
{ r = 97, g = 255, b = 0 },
|
||||
{ r = 110, g = 255, b = 0 },
|
||||
{ r = 123, g = 255, b = 0 },
|
||||
{ r = 131, g = 255, b = 0 },
|
||||
{ r = 144, g = 255, b = 0 },
|
||||
{ r = 157, g = 255, b = 0 },
|
||||
{ r = 170, g = 255, b = 0 },
|
||||
{ r = 182, g = 255, b = 0 },
|
||||
{ r = 191, g = 255, b = 0 },
|
||||
{ r = 203, g = 255, b = 0 },
|
||||
{ r = 216, g = 255, b = 0 },
|
||||
{ r = 229, g = 255, b = 0 },
|
||||
{ r = 242, g = 255, b = 0 },
|
||||
{ r = 255, g = 255, b = 0 },
|
||||
{ r = 255, g = 246, b = 0 },
|
||||
{ r = 255, g = 233, b = 0 },
|
||||
{ r = 255, g = 220, b = 0 },
|
||||
{ r = 255, g = 208, b = 0 },
|
||||
{ r = 255, g = 195, b = 0 },
|
||||
{ r = 255, g = 187, b = 0 },
|
||||
{ r = 255, g = 174, b = 0 },
|
||||
{ r = 255, g = 161, b = 0 },
|
||||
{ r = 255, g = 148, b = 0 },
|
||||
{ r = 255, g = 135, b = 0 },
|
||||
{ r = 255, g = 127, b = 0 },
|
||||
{ r = 255, g = 114, b = 0 },
|
||||
{ r = 255, g = 102, b = 0 },
|
||||
{ r = 255, g = 89, b = 0 },
|
||||
{ r = 255, g = 76, b = 0 },
|
||||
{ r = 255, g = 63, b = 0 },
|
||||
{ r = 255, g = 55, b = 0 },
|
||||
{ r = 255, g = 42, b = 0 },
|
||||
{ r = 255, g = 29, b = 0 },
|
||||
{ r = 255, g = 16, b = 0 },
|
||||
{ r = 255, g = 4, b = 0 },
|
||||
{ r = 255, g = 0, b = 4 },
|
||||
{ r = 255, g = 0, b = 16 },
|
||||
{ r = 255, g = 0, b = 29 },
|
||||
{ r = 255, g = 0, b = 42 },
|
||||
{ r = 255, g = 0, b = 55 },
|
||||
{ r = 255, g = 0, b = 63 },
|
||||
{ r = 255, g = 0, b = 76 },
|
||||
{ r = 255, g = 0, b = 89 },
|
||||
{ r = 255, g = 0, b = 102 },
|
||||
{ r = 255, g = 0, b = 114 },
|
||||
{ r = 255, g = 0, b = 127 },
|
||||
{ r = 255, g = 0, b = 135 },
|
||||
{ r = 255, g = 0, b = 148 },
|
||||
{ r = 255, g = 0, b = 161 },
|
||||
{ r = 255, g = 0, b = 174 },
|
||||
{ r = 255, g = 0, b = 186 },
|
||||
{ r = 255, g = 0, b = 195 },
|
||||
{ r = 255, g = 0, b = 208 },
|
||||
{ r = 255, g = 0, b = 221 },
|
||||
{ r = 255, g = 0, b = 233 },
|
||||
{ r = 255, g = 0, b = 246 },
|
||||
{ r = 255, g = 0, b = 255 },
|
||||
{ r = 242, g = 0, b = 255 },
|
||||
{ r = 229, g = 0, b = 255 },
|
||||
{ r = 216, g = 0, b = 255 },
|
||||
{ r = 204, g = 0, b = 255 },
|
||||
{ r = 191, g = 0, b = 255 },
|
||||
{ r = 182, g = 0, b = 255 },
|
||||
{ r = 169, g = 0, b = 255 },
|
||||
{ r = 157, g = 0, b = 255 },
|
||||
{ r = 144, g = 0, b = 255 },
|
||||
{ r = 131, g = 0, b = 255 },
|
||||
{ r = 123, g = 0, b = 255 },
|
||||
{ r = 110, g = 0, b = 255 },
|
||||
{ r = 97, g = 0, b = 255 },
|
||||
{ r = 85, g = 0, b = 255 },
|
||||
{ r = 72, g = 0, b = 255 },
|
||||
{ r = 63, g = 0, b = 255 },
|
||||
{ r = 50, g = 0, b = 255 },
|
||||
{ r = 38, g = 0, b = 255 },
|
||||
{ r = 25, g = 0, b = 255 },
|
||||
{ r = 240, g = 240, b = 225 },
|
||||
}
|
||||
|
||||
type FeedbackEntry = {
|
||||
behavior: number,
|
||||
color: number?,
|
||||
}
|
||||
local dark = 30
|
||||
local medium = 40
|
||||
local bright = 47
|
||||
local pulsing = 12
|
||||
local blinking = 8
|
||||
local red_color = 83
|
||||
local default_color = 21
|
||||
local feedback_table: { [string]: FeedbackEntry? } = {
|
||||
["playtime.slot_state.empty"] = {
|
||||
behavior = bright,
|
||||
color = 0,
|
||||
},
|
||||
["playtime.slot_state.armed"] = {
|
||||
behavior = dark,
|
||||
color = red_color,
|
||||
},
|
||||
["playtime.slot_state.stopped"] = {
|
||||
behavior = dark,
|
||||
},
|
||||
["playtime.slot_state.ignited"] = {
|
||||
behavior = dark,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_play_start"] = {
|
||||
behavior = medium,
|
||||
},
|
||||
["playtime.slot_state.playing"] = {
|
||||
behavior = pulsing,
|
||||
},
|
||||
["playtime.slot_state.paused"] = {
|
||||
behavior = dark,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_play_stop"] = {
|
||||
behavior = blinking,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_play_restart"] = {
|
||||
behavior = blinking,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_record_start"] = {
|
||||
behavior = medium,
|
||||
color = red_color,
|
||||
},
|
||||
["playtime.slot_state.recording"] = {
|
||||
behavior = pulsing,
|
||||
color = red_color,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_record_stop"] = {
|
||||
behavior = blinking,
|
||||
color = red_color,
|
||||
},
|
||||
}
|
||||
|
||||
--- Returns the 0-based index within the given palette array.
|
||||
local function find_closest_color_in_palette(color: midi_script.RgbColor, palette: { midi_script.RgbColor }): number
|
||||
local ifurthest = 0
|
||||
local furthest = 3 * math.pow(255, 2) + 1
|
||||
for i, c in palette do
|
||||
if color.r == c.r and color.g == c.g and color.b == c.b then
|
||||
return i - 1
|
||||
end
|
||||
local distance = math.pow((color.r - c.r), 2) + math.pow((color.g - c.g), 2) + math.pow((color.b - c.b), 2)
|
||||
if distance < furthest then
|
||||
furthest = distance
|
||||
ifurthest = i - 1
|
||||
end
|
||||
end
|
||||
return ifurthest
|
||||
end
|
||||
|
||||
local function create_output(pad_index: number, color_index: number, behavior: number): midi_script.Output
|
||||
return {
|
||||
address = pad_index,
|
||||
messages = {
|
||||
{ 0xB1, pad_index, color_index },
|
||||
{ 0xB2, pad_index, behavior },
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
function module.pad_script(
|
||||
pad_index: number,
|
||||
y: midi_script.InputValue,
|
||||
context: midi_script.Context
|
||||
): midi_script.Output
|
||||
local off_color = 0x00
|
||||
local off_output = create_output(pad_index, off_color, bright)
|
||||
-- Handle "off" feedback
|
||||
if y == nil then
|
||||
return off_output
|
||||
end
|
||||
-- Handle numeric feedback
|
||||
if type(y) == "number" then
|
||||
-- Translate number to solid feedback color.
|
||||
local color = math.floor(y * 127)
|
||||
return create_output(pad_index, color, bright)
|
||||
end
|
||||
-- Handle text feedback
|
||||
if type(y) == "string" then
|
||||
-- This can be used as a grid controller for controlling a Playtime matrix, so we should be able to
|
||||
-- handle text feedback that conforms to Playtime's clip state convention.
|
||||
local entry = feedback_table[y]
|
||||
if entry == nil then
|
||||
-- Unknown texts switch the LED off
|
||||
return off_output
|
||||
end
|
||||
local explicit_color = entry.color
|
||||
if explicit_color ~= nil then
|
||||
-- Switch LED to explicit color
|
||||
return create_output(pad_index, explicit_color, entry.behavior)
|
||||
end
|
||||
-- No explicit color means we should use the event color (which is set in the "Glue" section)
|
||||
local event_color = context.feedback_event.color
|
||||
if event_color == nil then
|
||||
-- Event has default color / no specific color
|
||||
return create_output(pad_index, default_color, entry.behavior)
|
||||
end
|
||||
-- Find color available on the controller that's closest to the desired RGB color
|
||||
local closest_color = find_closest_color_in_palette(event_color, color_palette)
|
||||
return create_output(pad_index, closest_color, entry.behavior)
|
||||
end
|
||||
-- Complex feedback is highly individual. It doesn't make sense to handle this in a general-purpose controller preset.
|
||||
return {
|
||||
address = pad_index,
|
||||
messages = {},
|
||||
}
|
||||
end
|
||||
|
||||
return module
|
||||
+605
@@ -0,0 +1,605 @@
|
||||
--!strict
|
||||
|
||||
local preset_runtime = require("preset_runtime")
|
||||
local realearn = require("realearn")
|
||||
|
||||
local module = {}
|
||||
|
||||
export type MidiFighterTwisterPresetConfig = {
|
||||
create_turn_target: (col: number, row: number) -> realearn.Target,
|
||||
create_push_target: (col: number, row: number) -> realearn.Target,
|
||||
}
|
||||
|
||||
local common_lua = preset_runtime.include_str("djtechtools/midi-fighter-twister-lib/compartment-common.luau")
|
||||
|
||||
local function build_pad_script(pad_index: number): string
|
||||
return `return require("compartment").pad_script({pad_index}, y, context)`
|
||||
end
|
||||
|
||||
function module.create_compartment(config: MidiFighterTwisterPresetConfig): realearn.Compartment
|
||||
-- Preparation
|
||||
local function pad_control(col: number, row: number, cc_number: number): realearn.Mapping
|
||||
return realearn.Mapping {
|
||||
id = `col{col + 1}/row{row + 1}/pad`,
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 1,
|
||||
controller_number = cc_number,
|
||||
character = "Button",
|
||||
},
|
||||
target = config.create_push_target(col, row),
|
||||
}
|
||||
end
|
||||
|
||||
local function pad_feedback(col: number, row: number, cc_number: number): realearn.Mapping
|
||||
return realearn.Mapping {
|
||||
id = `col{col + 1}/row{row + 1}/pad/feedback`,
|
||||
control_enabled = false,
|
||||
visible_in_projection = false,
|
||||
source = realearn.Source.MidiScript {
|
||||
script_kind = "Lua",
|
||||
script = build_pad_script(cc_number),
|
||||
},
|
||||
target = config.create_push_target(col, row)
|
||||
}
|
||||
end
|
||||
|
||||
local function knob(col: number, row: number, cc_number: number): realearn.Mapping
|
||||
return realearn.Mapping {
|
||||
id = `col{col + 1}/row{row + 1}/knob`,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = cc_number,
|
||||
character = "Relative2",
|
||||
},
|
||||
glue = {
|
||||
step_factor_interval = { 1, 100 }
|
||||
},
|
||||
target = config.create_turn_target(col, row),
|
||||
}
|
||||
end
|
||||
|
||||
local function side_button(id: string, cc_number: number): realearn.Mapping
|
||||
return realearn.Mapping {
|
||||
id = id,
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 3,
|
||||
controller_number = cc_number,
|
||||
character = "Button",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local mappings: { realearn.Mapping } = {
|
||||
-- Side buttons
|
||||
side_button("bank-left", 8),
|
||||
side_button("cursor-left", 9),
|
||||
side_button("ch-left", 10),
|
||||
side_button("bank-right", 11),
|
||||
side_button("cursor-right", 12),
|
||||
side_button("ch-right", 13),
|
||||
}
|
||||
|
||||
-- Grid
|
||||
local column_count = 4
|
||||
local row_count = 4
|
||||
for col = 0, column_count - 1 do
|
||||
for row = 0, row_count - 1 do
|
||||
local cc_number = row * row_count + col
|
||||
table.insert(mappings, pad_control(col, row, cc_number))
|
||||
table.insert(mappings, pad_feedback(col, row, cc_number))
|
||||
table.insert(mappings, knob(col, row, cc_number))
|
||||
end
|
||||
end
|
||||
|
||||
-- Companion data
|
||||
|
||||
local companion_data = {
|
||||
controls = {
|
||||
{
|
||||
height = 50,
|
||||
id = "col4/row1/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col4/row1/knob",
|
||||
"col4/row1/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 400,
|
||||
y = 0,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col1/row2/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col1/row2/knob",
|
||||
"col1/row2/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 100,
|
||||
y = 100,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col4/row2/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col4/row2/knob",
|
||||
"col4/row2/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 400,
|
||||
y = 100,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col1/row1/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col1/row1/knob",
|
||||
"col1/row1/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 100,
|
||||
y = 0,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col3/row1/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col3/row1/knob",
|
||||
"col3/row1/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 300,
|
||||
y = 0,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col2/row1/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col2/row1/knob",
|
||||
"col2/row1/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 200,
|
||||
y = 0,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col2/row2/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col2/row2/knob",
|
||||
"col2/row2/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 200,
|
||||
y = 100,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col3/row2/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col3/row2/knob",
|
||||
"col3/row2/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 300,
|
||||
y = 100,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col2/row3/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col2/row3/knob",
|
||||
"col2/row3/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 200,
|
||||
y = 200,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col3/row3/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col3/row3/knob",
|
||||
"col3/row3/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 300,
|
||||
y = 200,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col4/row4/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col4/row4/knob",
|
||||
"col4/row4/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 400,
|
||||
y = 300,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col1/row4/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col1/row4/knob",
|
||||
"col1/row4/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 100,
|
||||
y = 300,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col2/row4/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col2/row4/knob",
|
||||
"col2/row4/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 200,
|
||||
y = 300,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col3/row4/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col3/row4/knob",
|
||||
"col3/row4/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 300,
|
||||
y = 300,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col1/row3/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col1/row3/knob",
|
||||
"col1/row3/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 100,
|
||||
y = 200,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "col4/row3/knob",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "center",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"col4/row3/knob",
|
||||
"col4/row3/pad",
|
||||
},
|
||||
shape = "circle",
|
||||
width = 50,
|
||||
x = 400,
|
||||
y = 200,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "bank-right",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "belowBottom",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"bank-right",
|
||||
},
|
||||
shape = "rectangle",
|
||||
width = 50,
|
||||
x = 500,
|
||||
y = 50,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "bank-left",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "belowBottom",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"bank-left",
|
||||
},
|
||||
shape = "rectangle",
|
||||
width = 50,
|
||||
x = 0,
|
||||
y = 50,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "a78b277e-cfbf-4b2b-9cc6-1a550aeb87fd",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "belowBottom",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"ch-left",
|
||||
},
|
||||
shape = "rectangle",
|
||||
width = 50,
|
||||
x = 0,
|
||||
y = 250,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "e312d2a2-ecf1-4189-95af-4174c43a750c",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "belowBottom",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"ch-right",
|
||||
},
|
||||
shape = "rectangle",
|
||||
width = 50,
|
||||
x = 500,
|
||||
y = 250,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "cursor-left",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "belowBottom",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"cursor-left",
|
||||
},
|
||||
shape = "rectangle",
|
||||
width = 50,
|
||||
x = 0,
|
||||
y = 150,
|
||||
},
|
||||
{
|
||||
height = 50,
|
||||
id = "cursor-right",
|
||||
["labelOne"] = {
|
||||
angle = 0,
|
||||
position = "aboveTop",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
["labelTwo"] = {
|
||||
angle = 0,
|
||||
position = "belowBottom",
|
||||
["sizeConstrained"] = true,
|
||||
},
|
||||
mappings = {
|
||||
"cursor-right",
|
||||
},
|
||||
shape = "rectangle",
|
||||
width = 50,
|
||||
x = 500,
|
||||
y = 150,
|
||||
},
|
||||
},
|
||||
["gridDivisionCount"] = 2,
|
||||
["gridSize"] = 50,
|
||||
}
|
||||
|
||||
-- Result
|
||||
return realearn.Compartment {
|
||||
mappings = mappings,
|
||||
common_lua = common_lua,
|
||||
custom_data = {
|
||||
companion = companion_data,
|
||||
numbered = {
|
||||
multi_count = column_count * row_count,
|
||||
button_count = column_count * row_count,
|
||||
},
|
||||
grid = {
|
||||
column_count = column_count,
|
||||
row_count = row_count,
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
return module
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
--- name: Midi Fighter Twister - Numbered
|
||||
--- realearn_version: 2.16.0-pre.8
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: DJ TechTools
|
||||
--- device_name: Midi Fighter Twister
|
||||
--- description: |
|
||||
--- This controller preset exposes the push encoders of the Midi Fighter Twister with the "numbered" scheme, which means
|
||||
--- it uses virtual element IDs such as button 5 or knob 3. This makes it compatible with main presets that are
|
||||
--- built for generic controllers that have a row of buttons and knobs.
|
||||
--- setup_instructions: |
|
||||
--- The Midi Fighter Twister is a very customizable controller. Please follow the instructions at
|
||||
--- https://github.com/helgoboss/helgobox/blob/master/doc/controllers.adoc#dj-techtools-midi-fighter-twister
|
||||
--- to make it ready for ReaLearn.
|
||||
--- midi_identity_pattern: F0 7E ? 06 02 00 01 79 05 00 01 00 * F7
|
||||
--- provided_schemes: [djtechtools/midi-fighter-twister/numbered, numbered]
|
||||
|
||||
--!strict
|
||||
|
||||
local realearn = require("realearn")
|
||||
local commons = require("djtechtools/midi-fighter-twister-lib/preset-common")
|
||||
|
||||
return commons.create_compartment {
|
||||
create_push_target = function (col, row)
|
||||
return realearn.Target.Virtual {
|
||||
id = row * 4 + col,
|
||||
character = "Button",
|
||||
}
|
||||
end,
|
||||
create_turn_target = function (col, row)
|
||||
return realearn.Target.Virtual {
|
||||
id = row * 4 + col,
|
||||
character = "Multi",
|
||||
}
|
||||
end,
|
||||
}
|
||||
+1397
File diff suppressed because it is too large
Load Diff
+729
@@ -0,0 +1,729 @@
|
||||
--!strict
|
||||
|
||||
local realearn = require("realearn")
|
||||
|
||||
local module = {}
|
||||
|
||||
export type McuPresetConfig = {
|
||||
companion_data: any,
|
||||
support_x_touch_colors: boolean,
|
||||
}
|
||||
|
||||
function module.create_compartment(config: McuPresetConfig): realearn.Compartment
|
||||
local channel_count = 8;
|
||||
|
||||
-- Replace with "XTouchMackieLcd" in order to be able to benefit from colors when using X-Touch.
|
||||
local lcd_kind = "MackieLcd";
|
||||
|
||||
local binary_eight = {
|
||||
[0] = "000",
|
||||
[1] = "001",
|
||||
[2] = "010",
|
||||
[3] = "011",
|
||||
[4] = "100",
|
||||
[5] = "101",
|
||||
[6] = "110",
|
||||
[7] = "111",
|
||||
}
|
||||
|
||||
local groups: { realearn.Group } = {
|
||||
{
|
||||
id = "fader",
|
||||
name = "Fader",
|
||||
},
|
||||
{
|
||||
id = "v-pot",
|
||||
name = "V-Pot",
|
||||
},
|
||||
{
|
||||
id = "v-select",
|
||||
name = "V-Select",
|
||||
},
|
||||
{
|
||||
id = "fader-touch",
|
||||
name = "Fader Touch",
|
||||
},
|
||||
{
|
||||
id = "select",
|
||||
name = "Select",
|
||||
},
|
||||
{
|
||||
id = "mute",
|
||||
name = "Mute",
|
||||
},
|
||||
{
|
||||
id = "solo",
|
||||
name = "Solo",
|
||||
},
|
||||
{
|
||||
id = "record-ready",
|
||||
name = "Record-ready",
|
||||
},
|
||||
{
|
||||
id = "v-pot-leds",
|
||||
name = "V-Pot LEDs",
|
||||
},
|
||||
{
|
||||
id = "lcd",
|
||||
name = "LCD",
|
||||
},
|
||||
{
|
||||
id = "meter",
|
||||
name = "Meter",
|
||||
},
|
||||
}
|
||||
|
||||
local mappings: { realearn.Mapping } = {
|
||||
{
|
||||
id = "main/fader",
|
||||
group = "fader",
|
||||
source = realearn.Source.MidiPitchBendChangeValue {
|
||||
channel = 8,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "main/fader",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "jog",
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = 60,
|
||||
character = "Relative1",
|
||||
fourteen_bit = false,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "jog",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "main/fader/touch",
|
||||
group = "fader-touch",
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 112,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "main/fader/touch",
|
||||
character = "Button",
|
||||
learnable = false,
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "marker",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 84,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "marker",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "read",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 74,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "read",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "write",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 75,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "write",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "ch-left",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 48,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "ch-left",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "ch-right",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 49,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "ch-right",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "bank-left",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 46,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "bank-left",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "bank-right",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 47,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "bank-right",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "rewind",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 91,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "rewind",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "fast-fwd",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 92,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "fast-fwd",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "play",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 94,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "play",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "stop",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 93,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "stop",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "record",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 95,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "record",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "cycle",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 86,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "cycle",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "zoom",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 100,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "zoom",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "scrub",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 101,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "scrub",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "cursor-left",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 98,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "cursor-left",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "cursor-right",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 99,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "cursor-right",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "cursor-up",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 96,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "cursor-up",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "cursor-down",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 97,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "cursor-down",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "nudge",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 85,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "nudge",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "drop",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 87,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "drop",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "replace",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 88,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "replace",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "click",
|
||||
source = {
|
||||
kind = "MidiNoteVelocity",
|
||||
channel = 0,
|
||||
key_number = 89,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "click",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "solo",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 90,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "solo",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "f1",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 54,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "f1",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "f2",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 55,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "f2",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "f3",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 56,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "f3",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "f4",
|
||||
source = {
|
||||
kind = "MidiNoteVelocity",
|
||||
channel = 0,
|
||||
key_number = 57,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "f4",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "f5",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 58,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "f5",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "f6",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 59,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "f6",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "smpte-beats",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 53,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "smpte-beats",
|
||||
character = "Button",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "lcd/assignment",
|
||||
group = "lcd",
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MackieSevenSegmentDisplay {
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "lcd/assignment",
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "lcd/timecode",
|
||||
group = "lcd",
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MackieSevenSegmentDisplay {
|
||||
scope = "Tc",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = "lcd/timecode",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
-- For each channel
|
||||
for ch = 0, channel_count - 1 do
|
||||
local human_ch = ch + 1
|
||||
local prefix = "ch"..human_ch.."/"
|
||||
local v_select = realearn.Mapping {
|
||||
id = prefix.."v-select",
|
||||
group = "v-select",
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 32 + ch,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."v-select",
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
local fader_touch = realearn.Mapping {
|
||||
id = prefix.."fader/touch",
|
||||
group = "fader-touch",
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 104 + ch,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."fader/touch",
|
||||
character = "Button",
|
||||
learnable = false,
|
||||
},
|
||||
}
|
||||
local select = realearn.Mapping {
|
||||
id = prefix.."select",
|
||||
group = "select",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 24 + ch,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."select",
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
local fader = realearn.Mapping {
|
||||
id = prefix.."fader",
|
||||
group = "fader",
|
||||
source = realearn.Source.MidiPitchBendChangeValue {
|
||||
channel = ch,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."fader",
|
||||
},
|
||||
}
|
||||
local v_pot_control = realearn.Mapping {
|
||||
id = prefix.."v-pot/control",
|
||||
group = "v-pot",
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = 16 + ch,
|
||||
character = "Relative3",
|
||||
fourteen_bit = false,
|
||||
},
|
||||
glue = {
|
||||
step_factor_interval = {1, 100},
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."v-pot",
|
||||
},
|
||||
}
|
||||
local v_pot_feedback_default = realearn.Mapping {
|
||||
id = prefix.."v-pot/feedback",
|
||||
group = "v-pot-leds",
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiRaw {
|
||||
pattern = "B0 3"..ch.." [0000 dcba]",
|
||||
},
|
||||
glue = {
|
||||
source_interval = {0, 0.75},
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."v-pot",
|
||||
},
|
||||
}
|
||||
local v_pot_feedback_wrap = realearn.Mapping {
|
||||
id = prefix.."v-pot/wrap",
|
||||
group = "v-pot-leds",
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiRaw {
|
||||
pattern = "B0 3"..ch.." [0010 dcba]",
|
||||
},
|
||||
glue = {
|
||||
source_interval = {0, 0.75},
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."v-pot/wrap",
|
||||
},
|
||||
}
|
||||
local v_pot_feedback_boost_cut = realearn.Mapping {
|
||||
id = prefix.."v-pot/boost-cut",
|
||||
group = "v-pot-leds",
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiRaw {
|
||||
pattern = "B0 3"..ch.." [0001 dcba]",
|
||||
},
|
||||
glue = {
|
||||
source_interval = {0.05, 0.75},
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."v-pot/boost-cut",
|
||||
},
|
||||
}
|
||||
local v_pot_feedback_single = realearn.Mapping {
|
||||
id = prefix.."v-pot/single",
|
||||
group = "v-pot-leds",
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiRaw {
|
||||
pattern = "B0 3"..ch.." [0000 dcba]",
|
||||
},
|
||||
glue = {
|
||||
source_interval = {0, 0.75},
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."v-pot/single",
|
||||
},
|
||||
}
|
||||
local v_pot_feedback_spread = realearn.Mapping {
|
||||
id = prefix.."v-pot/spread",
|
||||
group = "v-pot-leds",
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiRaw {
|
||||
pattern = "B0 3"..ch.." [0011 dcba]",
|
||||
},
|
||||
glue = {
|
||||
source_interval = {0, 0.4},
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."v-pot/spread",
|
||||
},
|
||||
}
|
||||
local mute = realearn.Mapping {
|
||||
id = prefix.."mute",
|
||||
group = "mute",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 16 + ch,
|
||||
},
|
||||
target = {
|
||||
kind = "Virtual",
|
||||
id = prefix.."mute",
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
local solo = realearn.Mapping {
|
||||
id = prefix.."solo",
|
||||
group = "solo",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 8 + ch,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."solo",
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
local record_ready = realearn.Mapping {
|
||||
id = prefix.."record-ready",
|
||||
group = "record-ready",
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 0 + ch,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."record-ready",
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
local normal_lcd_line_1 = realearn.Source.MackieLcd {
|
||||
channel = ch,
|
||||
line = 0,
|
||||
}
|
||||
local x_touch_lcd_line_1 = realearn.Source.XTouchMackieLcd {
|
||||
channel = ch,
|
||||
line = 0,
|
||||
}
|
||||
local lcd_line1 = realearn.Mapping {
|
||||
id = prefix.."lcd/line1",
|
||||
group = "lcd",
|
||||
control_enabled = false,
|
||||
source = if config.support_x_touch_colors then x_touch_lcd_line_1 else normal_lcd_line_1,
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."lcd/line1",
|
||||
},
|
||||
}
|
||||
local normal_lcd_line_2 = realearn.Source.MackieLcd {
|
||||
channel = ch,
|
||||
line = 1,
|
||||
}
|
||||
local x_touch_lcd_line_2 = realearn.Source.XTouchMackieLcd {
|
||||
channel = ch,
|
||||
line = 1,
|
||||
}
|
||||
local lcd_line2 = realearn.Mapping {
|
||||
id = prefix.."lcd/line2",
|
||||
group = "lcd",
|
||||
control_enabled = false,
|
||||
source = if config.support_x_touch_colors then x_touch_lcd_line_2 else normal_lcd_line_2,
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."lcd/line2",
|
||||
},
|
||||
}
|
||||
local meter = realearn.Mapping {
|
||||
id = prefix.."meter/peak",
|
||||
group = "meter",
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiRaw {
|
||||
pattern = "D0 [0"..binary_eight[ch].." dcba]",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = prefix.."meter/peak",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, v_select)
|
||||
table.insert(mappings, fader_touch)
|
||||
table.insert(mappings, select)
|
||||
table.insert(mappings, fader)
|
||||
table.insert(mappings, v_pot_control)
|
||||
table.insert(mappings, v_pot_feedback_default)
|
||||
table.insert(mappings, v_pot_feedback_wrap)
|
||||
table.insert(mappings, v_pot_feedback_boost_cut)
|
||||
table.insert(mappings, v_pot_feedback_single)
|
||||
table.insert(mappings, v_pot_feedback_spread)
|
||||
table.insert(mappings, mute)
|
||||
table.insert(mappings, solo)
|
||||
table.insert(mappings, record_ready)
|
||||
table.insert(mappings, lcd_line1)
|
||||
table.insert(mappings, lcd_line2)
|
||||
table.insert(mappings, meter)
|
||||
end
|
||||
|
||||
return realearn.Compartment {
|
||||
groups = groups,
|
||||
mappings = mappings,
|
||||
custom_data = {
|
||||
companion = config.companion_data,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
return module
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
--- name: Mackie Control Universal
|
||||
--- realearn_version: 2.16.0
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: Mackie
|
||||
--- device_name: Control Universal
|
||||
--- description: |
|
||||
--- This controller preset implements the Mackie Control Universal (MCU) MIDI protocol. It is supported by many
|
||||
--- DAW control surfaces out there. I have tested it with Behringer X-Touch One, Behringer X-Touch Compact and
|
||||
--- iCON Platform M+.
|
||||
--- setup_instructions: |
|
||||
--- You probably must put your controller into MCU mode for using this controller preset.
|
||||
--- provided_schemes: [daw]
|
||||
|
||||
--!strict
|
||||
|
||||
local commons = require("mackie/control-universal-lib/preset-common")
|
||||
|
||||
return commons.create_compartment {
|
||||
companion_data = nil,
|
||||
support_x_touch_colors = false,
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../api/luau/midi_script_source_runtime.luau
|
||||
+330
@@ -0,0 +1,330 @@
|
||||
--!strict
|
||||
|
||||
local midi_script = require("midi_script_source_runtime")
|
||||
|
||||
local module = {}
|
||||
|
||||
--- There's no way to put pads in a pulsing state with the true RGB sys-ex messages, so
|
||||
--- we are back to an old-fashioned color palette. Whatever, close enough.
|
||||
local color_palette: { midi_script.RgbColor } = {
|
||||
{ r = 0x61, g = 0x61, b = 0x61 },
|
||||
{ r = 0xb3, g = 0xb3, b = 0xb3 },
|
||||
{ r = 0xdd, g = 0xdd, b = 0xdd },
|
||||
{ r = 0xff, g = 0xff, b = 0xff },
|
||||
{ r = 0xfc, g = 0xb3, b = 0xb3 },
|
||||
{ r = 0xfa, g = 0x61, b = 0x61 },
|
||||
{ r = 0xdd, g = 0x61, b = 0x61 },
|
||||
{ r = 0xb3, g = 0x61, b = 0x61 },
|
||||
{ r = 0xfe, g = 0xf3, b = 0xd5 },
|
||||
{ r = 0xfb, g = 0xb3, b = 0x61 },
|
||||
{ r = 0xdd, g = 0x8c, b = 0x61 },
|
||||
{ r = 0xb3, g = 0x76, b = 0x61 },
|
||||
{ r = 0xfc, g = 0xee, b = 0xa1 },
|
||||
{ r = 0xfb, g = 0xff, b = 0x61 },
|
||||
{ r = 0xdd, g = 0xdd, b = 0x61 },
|
||||
{ r = 0xb3, g = 0xb3, b = 0x61 },
|
||||
{ r = 0xdd, g = 0xff, b = 0xa1 },
|
||||
{ r = 0xc2, g = 0xff, b = 0x61 },
|
||||
{ r = 0xa1, g = 0xdd, b = 0x61 },
|
||||
{ r = 0x81, g = 0xb3, b = 0x61 },
|
||||
{ r = 0xc2, g = 0xff, b = 0xb3 },
|
||||
{ r = 0x61, g = 0xfe, b = 0x61 },
|
||||
{ r = 0x61, g = 0xdd, b = 0x61 },
|
||||
{ r = 0x61, g = 0xb3, b = 0x61 },
|
||||
{ r = 0xc2, g = 0xff, b = 0xc2 },
|
||||
{ r = 0x61, g = 0xfe, b = 0x8c },
|
||||
{ r = 0x61, g = 0xdd, b = 0x76 },
|
||||
{ r = 0x61, g = 0xb3, b = 0x6b },
|
||||
{ r = 0xc2, g = 0xfe, b = 0xcc },
|
||||
{ r = 0x61, g = 0xfe, b = 0xcc },
|
||||
{ r = 0x61, g = 0xdd, b = 0xa1 },
|
||||
{ r = 0x61, g = 0xb3, b = 0x81 },
|
||||
{ r = 0xc2, g = 0xfe, b = 0xf3 },
|
||||
{ r = 0x61, g = 0xfd, b = 0xe9 },
|
||||
{ r = 0x61, g = 0xdd, b = 0xc2 },
|
||||
{ r = 0x61, g = 0xb3, b = 0x96 },
|
||||
{ r = 0xc2, g = 0xf3, b = 0xff },
|
||||
{ r = 0x61, g = 0xee, b = 0xff },
|
||||
{ r = 0x61, g = 0xc7, b = 0xdd },
|
||||
{ r = 0x61, g = 0xa1, b = 0xb3 },
|
||||
{ r = 0xc2, g = 0xdd, b = 0xff },
|
||||
{ r = 0x61, g = 0xc7, b = 0xff },
|
||||
{ r = 0x61, g = 0xa1, b = 0xdd },
|
||||
{ r = 0x61, g = 0x81, b = 0xb3 },
|
||||
{ r = 0xa1, g = 0x8c, b = 0xff },
|
||||
{ r = 0x61, g = 0x61, b = 0xff },
|
||||
{ r = 0x61, g = 0x61, b = 0xdd },
|
||||
{ r = 0x61, g = 0x61, b = 0xb3 },
|
||||
{ r = 0xcc, g = 0xb3, b = 0xff },
|
||||
{ r = 0xa1, g = 0x61, b = 0xff },
|
||||
{ r = 0x81, g = 0x61, b = 0xdd },
|
||||
{ r = 0x76, g = 0x61, b = 0xb3 },
|
||||
{ r = 0xfe, g = 0xb3, b = 0xff },
|
||||
{ r = 0xfe, g = 0x61, b = 0xff },
|
||||
{ r = 0xdd, g = 0x61, b = 0xdd },
|
||||
{ r = 0xb3, g = 0x61, b = 0xb3 },
|
||||
{ r = 0xfd, g = 0xb3, b = 0xd5 },
|
||||
{ r = 0xfc, g = 0x61, b = 0xc2 },
|
||||
{ r = 0xdd, g = 0x61, b = 0xa1 },
|
||||
{ r = 0xb3, g = 0x61, b = 0x8c },
|
||||
{ r = 0xfa, g = 0x76, b = 0x61 },
|
||||
{ r = 0xe9, g = 0xb3, b = 0x61 },
|
||||
{ r = 0xdd, g = 0xc2, b = 0x61 },
|
||||
{ r = 0xa1, g = 0xa1, b = 0x61 },
|
||||
{ r = 0x61, g = 0xb3, b = 0x61 },
|
||||
{ r = 0x61, g = 0xb3, b = 0x8c },
|
||||
{ r = 0x61, g = 0x8c, b = 0xd5 },
|
||||
{ r = 0x61, g = 0x61, b = 0xff },
|
||||
{ r = 0x61, g = 0xb3, b = 0xb3 },
|
||||
{ r = 0x8c, g = 0x62, b = 0xf3 },
|
||||
{ r = 0xcc, g = 0xb3, b = 0xc2 },
|
||||
{ r = 0x8c, g = 0x76, b = 0x81 },
|
||||
{ r = 0xfa, g = 0x61, b = 0x61 },
|
||||
{ r = 0xf3, g = 0xff, b = 0xa1 },
|
||||
{ r = 0xee, g = 0xfc, b = 0x61 },
|
||||
{ r = 0xcc, g = 0xff, b = 0x60 },
|
||||
{ r = 0x76, g = 0xdd, b = 0x61 },
|
||||
{ r = 0x61, g = 0xfe, b = 0xcc },
|
||||
{ r = 0x61, g = 0xe9, b = 0xff },
|
||||
{ r = 0x61, g = 0xa1, b = 0xff },
|
||||
{ r = 0x8c, g = 0x61, b = 0xff },
|
||||
{ r = 0xcc, g = 0x61, b = 0xfc },
|
||||
{ r = 0xee, g = 0x8c, b = 0xdd },
|
||||
{ r = 0xa1, g = 0x76, b = 0x61 },
|
||||
{ r = 0xfb, g = 0xa1, b = 0x61 },
|
||||
{ r = 0xdd, g = 0xf9, b = 0x62 },
|
||||
{ r = 0xd5, g = 0xff, b = 0x8c },
|
||||
{ r = 0x61, g = 0xfe, b = 0x61 },
|
||||
{ r = 0xb3, g = 0xff, b = 0xa1 },
|
||||
{ r = 0xcc, g = 0xfc, b = 0xd5 },
|
||||
{ r = 0xb3, g = 0xfe, b = 0xf6 },
|
||||
{ r = 0xcc, g = 0xe4, b = 0xff },
|
||||
{ r = 0xa1, g = 0xc2, b = 0xf6 },
|
||||
{ r = 0xd5, g = 0xc2, b = 0xf9 },
|
||||
{ r = 0xf9, g = 0x8c, b = 0xff },
|
||||
{ r = 0xfc, g = 0x61, b = 0xcc },
|
||||
{ r = 0xfb, g = 0xc2, b = 0x61 },
|
||||
{ r = 0xf3, g = 0xee, b = 0x61 },
|
||||
{ r = 0xe4, g = 0xff, b = 0x61 },
|
||||
{ r = 0xdd, g = 0xcc, b = 0x61 },
|
||||
{ r = 0xb3, g = 0xa1, b = 0x61 },
|
||||
{ r = 0x61, g = 0xba, b = 0x76 },
|
||||
{ r = 0x76, g = 0xc2, b = 0x8c },
|
||||
{ r = 0x81, g = 0x81, b = 0xa1 },
|
||||
{ r = 0x81, g = 0x8c, b = 0xcc },
|
||||
{ r = 0xcc, g = 0xaa, b = 0x81 },
|
||||
{ r = 0xdd, g = 0x61, b = 0x61 },
|
||||
{ r = 0xf9, g = 0xb3, b = 0xa1 },
|
||||
{ r = 0xf9, g = 0xba, b = 0x76 },
|
||||
{ r = 0xfc, g = 0xf3, b = 0x8d },
|
||||
{ r = 0xe9, g = 0xf9, b = 0xa1 },
|
||||
{ r = 0xd5, g = 0xee, b = 0x76 },
|
||||
{ r = 0x81, g = 0x81, b = 0xa1 },
|
||||
{ r = 0xf9, g = 0xf9, b = 0xd5 },
|
||||
{ r = 0xdd, g = 0xfc, b = 0xe4 },
|
||||
{ r = 0xe9, g = 0xe9, b = 0xff },
|
||||
{ r = 0xe4, g = 0xd5, b = 0xff },
|
||||
{ r = 0xb3, g = 0xb3, b = 0xb3 },
|
||||
{ r = 0xd5, g = 0xd5, b = 0xd5 },
|
||||
{ r = 0xf9, g = 0xff, b = 0xff },
|
||||
{ r = 0xe9, g = 0x61, b = 0x61 },
|
||||
{ r = 0xaa, g = 0x62, b = 0x61 },
|
||||
{ r = 0x81, g = 0xf6, b = 0x62 },
|
||||
{ r = 0x61, g = 0xb3, b = 0x61 },
|
||||
{ r = 0xf3, g = 0xee, b = 0x61 },
|
||||
{ r = 0xb3, g = 0xa1, b = 0x61 },
|
||||
{ r = 0xee, g = 0xc2, b = 0x61 },
|
||||
{ r = 0xc2, g = 0x76, b = 0x61 },
|
||||
}
|
||||
|
||||
--- Returns the 0-based index within the given palette array.
|
||||
local function find_closest_color_in_palette(color: midi_script.RgbColor, palette: { midi_script.RgbColor }): number
|
||||
local ifurthest = 0
|
||||
local furthest = 3 * math.pow(255, 2) + 1
|
||||
for i, c in palette do
|
||||
if color.r == c.r and color.g == c.g and color.b == c.b then
|
||||
return i - 1
|
||||
end
|
||||
local distance = math.pow((color.r - c.r), 2) + math.pow((color.g - c.g), 2) + math.pow((color.b - c.b), 2)
|
||||
if distance < furthest then
|
||||
furthest = distance
|
||||
ifurthest = i - 1
|
||||
end
|
||||
end
|
||||
return ifurthest
|
||||
end
|
||||
|
||||
type FeedbackEntry = {
|
||||
behavior: number,
|
||||
color: (number | midi_script.RgbColor)?,
|
||||
brightness: number?,
|
||||
}
|
||||
local solid = 0x90
|
||||
local flashing = 0x91
|
||||
local pulsing = 0x92
|
||||
local black_color = 0
|
||||
local green_color = 0x15
|
||||
local white_color = { r = 255, g = 255, b = 255 }
|
||||
local red_color = { r = 255, g = 0, b = 0 }
|
||||
|
||||
local dark = 0.75
|
||||
local medium = 0.90
|
||||
|
||||
local function create_feedback_table(play_color: number?): { [string]: FeedbackEntry? }
|
||||
return {
|
||||
["playtime.slot_state.empty"] = {
|
||||
behavior = solid,
|
||||
color = black_color,
|
||||
},
|
||||
["playtime.slot_state.armed"] = {
|
||||
behavior = solid,
|
||||
color = red_color,
|
||||
brightness = dark,
|
||||
},
|
||||
["playtime.slot_state.stopped"] = {
|
||||
behavior = solid,
|
||||
brightness = dark,
|
||||
},
|
||||
["playtime.slot_state.ignited"] = {
|
||||
behavior = solid,
|
||||
brightness = dark,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_play_start"] = {
|
||||
behavior = flashing,
|
||||
color = play_color,
|
||||
},
|
||||
["playtime.slot_state.playing"] = {
|
||||
behavior = pulsing,
|
||||
color = play_color,
|
||||
},
|
||||
["playtime.slot_state.paused"] = {
|
||||
behavior = solid,
|
||||
brightness = medium,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_play_stop"] = {
|
||||
behavior = flashing,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_play_restart"] = {
|
||||
behavior = flashing,
|
||||
color = play_color,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_record_start"] = {
|
||||
behavior = solid,
|
||||
color = red_color,
|
||||
brightness = medium,
|
||||
},
|
||||
["playtime.slot_state.recording"] = {
|
||||
behavior = pulsing,
|
||||
color = red_color,
|
||||
},
|
||||
["playtime.slot_state.scheduled_for_record_stop"] = {
|
||||
behavior = flashing,
|
||||
color = red_color,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
-- Uses original color when playing (currently disabled, will probably be a configuration option in the future)
|
||||
local colorful_feedback_table = create_feedback_table(nil)
|
||||
|
||||
-- Uses green color when playing
|
||||
local green_feedback_table = create_feedback_table(green_color)
|
||||
|
||||
local function build_messages(
|
||||
pad_index: number,
|
||||
behavior: number,
|
||||
color_index: number
|
||||
): { midi_script.MidiMessage }
|
||||
if behavior == pulsing then
|
||||
return {
|
||||
{ 0x92, pad_index, color_index },
|
||||
}
|
||||
elseif behavior == flashing then
|
||||
-- Flashing between actual color and black
|
||||
return {
|
||||
{ 0x90, pad_index, color_index },
|
||||
{ 0x91, pad_index, black_color },
|
||||
}
|
||||
else
|
||||
-- Solid
|
||||
return {
|
||||
{ 0x90, pad_index, color_index },
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
local function adjust_brightness(c: midi_script.RgbColor, factor: number): midi_script.RgbColor
|
||||
return {
|
||||
r = math.floor(c.r * factor),
|
||||
g = math.floor(c.g * factor),
|
||||
b = math.floor(c.b * factor),
|
||||
}
|
||||
end
|
||||
|
||||
local function transform_and_find_closest_color_in_palette(original_color: midi_script.RgbColor, brightness: number?): number
|
||||
local transformed_color = if brightness then adjust_brightness(original_color, brightness) else original_color
|
||||
local index = find_closest_color_in_palette(transformed_color, color_palette)
|
||||
if index == 0 then
|
||||
-- Don't let it become black just because of the darkening
|
||||
return find_closest_color_in_palette(original_color, color_palette)
|
||||
end
|
||||
return index
|
||||
end
|
||||
|
||||
local function get_palette_color_index(entry: FeedbackEntry, rgb_color: midi_script.RgbColor?): number
|
||||
if type(entry.color) == "number" then
|
||||
return entry.color
|
||||
end
|
||||
local final_rgb_color = entry.color or rgb_color or white_color
|
||||
return transform_and_find_closest_color_in_palette(final_rgb_color, entry.brightness)
|
||||
end
|
||||
|
||||
|
||||
function module.pad_script(
|
||||
pad_index: number,
|
||||
y: midi_script.InputValue,
|
||||
context: midi_script.Context
|
||||
): midi_script.Output
|
||||
local address = pad_index
|
||||
local off_output = {
|
||||
address = pad_index,
|
||||
messages = build_messages(pad_index, solid, black_color),
|
||||
}
|
||||
-- Handle "off" feedback
|
||||
if y == nil then
|
||||
return off_output
|
||||
end
|
||||
-- Handle numeric feedback
|
||||
if type(y) == "number" then
|
||||
-- Translate number to solid feedback color
|
||||
local color_index = math.floor(y * 127)
|
||||
return {
|
||||
address = address,
|
||||
messages = {
|
||||
{ solid, pad_index, color_index },
|
||||
},
|
||||
}
|
||||
end
|
||||
-- Handle text feedback
|
||||
if type(y) == "string" then
|
||||
-- This is a grid controller, typically used for controlling a Playtime matrix, so we should be able to
|
||||
-- handle text feedback that conforms to Playtime's clip state convention.
|
||||
local entry = green_feedback_table[y]
|
||||
if entry == nil then
|
||||
-- Unknown texts switch the LED off
|
||||
return off_output
|
||||
end
|
||||
local color_index = get_palette_color_index(entry, context.feedback_event.color)
|
||||
return {
|
||||
address = pad_index,
|
||||
messages = build_messages(pad_index, entry.behavior, color_index),
|
||||
}
|
||||
end
|
||||
-- Complex feedback is highly individual. It doesn't make sense to handle this in a general-purpose controller preset.
|
||||
return {
|
||||
address = address,
|
||||
messages = {},
|
||||
}
|
||||
end
|
||||
|
||||
return module
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
--- name: Launchpad Mini mk3 - Live mode
|
||||
--- realearn_version: 2.16.0-pre.8
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: Novation
|
||||
--- device_name: Launchpad Mini mk3
|
||||
--- description: |
|
||||
--- This controller preset exposes all control elements of the Launchpad Mini mk3 in a neutral way. It supports
|
||||
--- ReaLearn color feedback as well as Playtime slot status feedback.
|
||||
--- midi_identity_pattern: F0 7E ? 06 02 00 20 29 13 01 00 00 * F7
|
||||
--- midi_output_port_patterns: ["macos:*DAW*", "windows:LPMiniMK3 MIDI"]
|
||||
--- provided_schemes: [novation/launchpad-mini-mk3/live, grid]
|
||||
|
||||
--!strict
|
||||
|
||||
-- Requires
|
||||
|
||||
local preset_runtime = require("preset_runtime")
|
||||
local realearn = require("realearn")
|
||||
|
||||
-- Define MIDI scripts
|
||||
|
||||
local common_lua = preset_runtime.include_str("novation/launchpad-lib/compartment-common.luau")
|
||||
|
||||
local function build_pad_script(pad_index: number): string
|
||||
return `return require("compartment").pad_script({pad_index}, y, context)`
|
||||
end
|
||||
|
||||
-- Single buttons
|
||||
|
||||
local function simple_button(id: string, name: string, cc: number): realearn.Mapping
|
||||
return realearn.Mapping {
|
||||
id = id,
|
||||
name = name,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = cc,
|
||||
character = "Button",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local init_mapping = realearn.Mapping {
|
||||
name = "Enter DAW mode and select session layout",
|
||||
source = realearn.Source.MidiScript {
|
||||
script_kind = "Lua",
|
||||
script = [[
|
||||
local standalone_mode = 0x00
|
||||
local daw_mode = 0x01
|
||||
local session_layout = 0x00
|
||||
local mode = if y == nil then standalone_mode else daw_mode
|
||||
local enter_or_leave_daw_mode_msg = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x0D, 0x10, mode, 0xF7 }
|
||||
local select_session_layout = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x0D, 0x00, session_layout, 0xF7 }
|
||||
|
||||
local messages = {
|
||||
enter_or_leave_daw_mode_msg,
|
||||
}
|
||||
if y then
|
||||
table.insert(messages, select_session_layout)
|
||||
end
|
||||
|
||||
return {
|
||||
messages = messages
|
||||
}
|
||||
]]
|
||||
},
|
||||
target = realearn.Target.Dummy {
|
||||
}
|
||||
}
|
||||
|
||||
local mappings = {
|
||||
init_mapping,
|
||||
|
||||
simple_button("cursor-up", "Up", 91),
|
||||
simple_button("cursor-down", "Down", 92),
|
||||
simple_button("cursor-left", "Left", 93),
|
||||
simple_button("cursor-right", "Right", 94),
|
||||
simple_button("session", "Session", 95),
|
||||
simple_button("drums", "Drums", 96),
|
||||
simple_button("keys", "Keys", 97),
|
||||
simple_button("user", "User", 98),
|
||||
}
|
||||
|
||||
-- Clip launch buttons
|
||||
|
||||
for col = 0, 7 do
|
||||
local human_col = col + 1
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local key_number_offset = 11 + (7 - row) * 10
|
||||
local id = `col{human_col}/row{human_row}/pad`
|
||||
local control_mapping = realearn.Mapping {
|
||||
id = id,
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = key_number_offset + col,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
local feedback_mapping = realearn.Mapping {
|
||||
id = `{id}-feedback`,
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiScript {
|
||||
script_kind = "Lua",
|
||||
script = build_pad_script(key_number_offset + col),
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, control_mapping)
|
||||
table.insert(mappings, feedback_mapping)
|
||||
end
|
||||
end
|
||||
|
||||
-- Scene launch buttons
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local id = `row{human_row}/play`
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = 19 + (7 - row) * 10,
|
||||
character = "Button",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
return realearn.Compartment {
|
||||
common_lua = common_lua,
|
||||
mappings = mappings,
|
||||
custom_data = {
|
||||
grid = {
|
||||
column_count = 8,
|
||||
row_count = 8,
|
||||
},
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
--- name: Launchpad mk1 - Live mode
|
||||
--- realearn_version: 2.16.0-pre.8
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: Novation
|
||||
--- device_name: Launchpad mk1
|
||||
--- description: |
|
||||
--- This controller preset exposes all control elements of the Launchpad mk1 in a neutral way. It supports Playtime slot status feedback.
|
||||
---
|
||||
--- This device cannot be auto-detected because it doesn't support the MIDI device inquiry protocol.
|
||||
--- provided_schemes: [novation/launchpad-mk1, grid]
|
||||
|
||||
--!strict
|
||||
|
||||
-- Requires
|
||||
|
||||
local realearn = require("realearn")
|
||||
|
||||
-- Single buttons
|
||||
|
||||
local function simple_button(id: string, name: string, cc: number): realearn.Mapping
|
||||
return realearn.Mapping {
|
||||
id = id,
|
||||
name = name,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = cc,
|
||||
character = "Button",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local init_mapping = realearn.Mapping {
|
||||
name = "Enable flashing LEDs",
|
||||
source = realearn.Source.MidiRaw {
|
||||
pattern = "B0 00 28",
|
||||
},
|
||||
target = realearn.Target.Dummy {
|
||||
}
|
||||
}
|
||||
|
||||
local mappings = {
|
||||
init_mapping,
|
||||
simple_button("cursor-up", "Up", 104),
|
||||
simple_button("cursor-down", "Down", 105),
|
||||
simple_button("cursor-left", "Left", 106),
|
||||
simple_button("cursor-right", "Right", 107),
|
||||
simple_button("session", "session", 108),
|
||||
simple_button("user-1", "user 1", 109),
|
||||
simple_button("user-2", "user 2", 110),
|
||||
simple_button("mixer", "mixer", 111),
|
||||
}
|
||||
|
||||
-- Clip launch buttons
|
||||
|
||||
local leds = {
|
||||
off = 12,
|
||||
red_low = 13,
|
||||
red_full = 15,
|
||||
amber_low = 29,
|
||||
amber_full = 63,
|
||||
yellow_full = 62,
|
||||
green_low = 28,
|
||||
green_full = 60,
|
||||
red_flashing = 11,
|
||||
amber_flashing = 59,
|
||||
yellow_flashing = 58,
|
||||
green_flashing = 56,
|
||||
}
|
||||
|
||||
for col = 0, 7 do
|
||||
local human_col = col + 1
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local key_number_offset = row * 16
|
||||
local id = `col{human_col}/row{human_row}/pad`
|
||||
local control_mapping = realearn.Mapping {
|
||||
id = id,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = key_number_offset + col,
|
||||
},
|
||||
glue = realearn.Glue {
|
||||
feedback_value_table = {
|
||||
kind = "FromTextToDiscrete",
|
||||
value = {
|
||||
["playtime.slot_state.empty"] = leds.off,
|
||||
["playtime.slot_state.armed"] = leds.red_low,
|
||||
["playtime.slot_state.stopped"] = leds.amber_low,
|
||||
["playtime.slot_state.ignited"] = leds.amber_low,
|
||||
["playtime.slot_state.scheduled_for_play_start"] = leds.green_flashing,
|
||||
["playtime.slot_state.playing"] = leds.green_full,
|
||||
["playtime.slot_state.paused"] = leds.amber_low,
|
||||
["playtime.slot_state.scheduled_for_play_stop"] = leds.amber_flashing,
|
||||
["playtime.slot_state.scheduled_for_play_restart"] = leds.green_flashing,
|
||||
["playtime.slot_state.scheduled_for_record_start"] = leds.red_flashing,
|
||||
["playtime.slot_state.recording"] = leds.red_full,
|
||||
["playtime.slot_state.scheduled_for_record_stop"] = leds.green_flashing,
|
||||
},
|
||||
}
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, control_mapping)
|
||||
end
|
||||
end
|
||||
|
||||
-- Scene launch buttons
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local id = `row{human_row}/play`
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = 8 + row * 16,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
return realearn.Compartment {
|
||||
mappings = mappings,
|
||||
custom_data = {
|
||||
grid = {
|
||||
column_count = 8,
|
||||
row_count = 8,
|
||||
},
|
||||
}
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
--- name: Launchpad Pro mk2 - Live mode
|
||||
--- realearn_version: 2.16.0-pre.8
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: Novation
|
||||
--- device_name: Launchpad Pro mk2
|
||||
--- description: |
|
||||
--- This controller preset exposes all control elements of the Launchpad Pro mk2 in a neutral way. It supports
|
||||
--- ReaLearn color feedback as well as Playtime slot status feedback.
|
||||
--- # I leave part of the family code dynamic. It's not always 00: https://github.com/helgoboss/helgobox/issues/939
|
||||
--- midi_identity_pattern: F0 7E ? 06 02 00 20 29 51 00 ? 00 * F7
|
||||
--- midi_output_port_patterns: ["macos:*Live*", "windows:*Launchpad Pro"]
|
||||
--- provided_schemes: [novation/launchpad-pro-mk2/live, grid]
|
||||
|
||||
--!strict
|
||||
|
||||
-- Requires
|
||||
|
||||
local preset_runtime = require("preset_runtime")
|
||||
local realearn = require("realearn")
|
||||
|
||||
-- Define MIDI scripts
|
||||
|
||||
local common_lua = preset_runtime.include_str("novation/launchpad-lib/compartment-common.luau")
|
||||
|
||||
local function build_pad_script(pad_index: number): string
|
||||
return `return require("compartment").pad_script({pad_index}, y, context)`
|
||||
end
|
||||
|
||||
-- Single buttons
|
||||
|
||||
local function simple_button(id: string, name: string, cc: number): realearn.Mapping
|
||||
return realearn.Mapping {
|
||||
id = id,
|
||||
name = name,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = cc,
|
||||
character = "Button",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local init_mapping = realearn.Mapping {
|
||||
name = "Enter live mode",
|
||||
source = realearn.Source.MidiScript {
|
||||
script_kind = "Lua",
|
||||
script = [[
|
||||
local live_mode = 0x00
|
||||
local standalone_mode = 0x01
|
||||
local mode = if y == nil then standalone_mode else live_mode
|
||||
|
||||
return {
|
||||
messages = {
|
||||
{ 0xF0, 0x00, 0x20, 0x29, 0x02, 0x10, 0x21, mode, 0xF7 }
|
||||
}
|
||||
}
|
||||
]]
|
||||
},
|
||||
target = realearn.Target.Dummy {
|
||||
}
|
||||
}
|
||||
|
||||
local mappings = {
|
||||
init_mapping,
|
||||
simple_button("cursor-up", "Up", 91),
|
||||
simple_button("cursor-down", "Down", 92),
|
||||
simple_button("cursor-left", "Left", 93),
|
||||
simple_button("cursor-right", "Right", 94),
|
||||
simple_button("session", "Session", 95),
|
||||
simple_button("note", "Note", 96),
|
||||
simple_button("device", "Device", 97),
|
||||
simple_button("user", "User", 98),
|
||||
simple_button("shift", "Shift", 80),
|
||||
simple_button("click", "Click", 70),
|
||||
simple_button("undo", "Undo", 60),
|
||||
simple_button("delete", "Delete", 50),
|
||||
simple_button("quantize", "Quantise", 40),
|
||||
simple_button("duplicate", "Duplicate", 30),
|
||||
simple_button("double", "Double", 20),
|
||||
simple_button("record", "Record", 10),
|
||||
simple_button("record-arm", "Record Arm", 1),
|
||||
simple_button("track-select", "Track Select", 2),
|
||||
simple_button("mute", "Mute", 3),
|
||||
simple_button("solo", "Solo", 4),
|
||||
simple_button("volume", "Volume", 5),
|
||||
simple_button("pan", "Pan", 6),
|
||||
simple_button("sends", "Sends", 7),
|
||||
simple_button("stop-clip", "Stop Clip", 8),
|
||||
}
|
||||
|
||||
-- Clip launch buttons
|
||||
|
||||
for col = 0, 7 do
|
||||
local human_col = col + 1
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local key_number_offset = 11 + (7 - row) * 10
|
||||
local id = `col{human_col}/row{human_row}/pad`
|
||||
local control_mapping = realearn.Mapping {
|
||||
id = id,
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = key_number_offset + col,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Multi",
|
||||
},
|
||||
}
|
||||
local feedback_mapping = realearn.Mapping {
|
||||
id = `{id}-feedback`,
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiScript {
|
||||
script_kind = "Lua",
|
||||
script = build_pad_script(key_number_offset + col),
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Multi",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, control_mapping)
|
||||
table.insert(mappings, feedback_mapping)
|
||||
end
|
||||
end
|
||||
|
||||
-- Scene launch buttons
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local id = `row{human_row}/play`
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = 19 + (7 - row) * 10,
|
||||
character = "Button",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
return realearn.Compartment {
|
||||
common_lua = common_lua,
|
||||
mappings = mappings,
|
||||
custom_data = {
|
||||
grid = {
|
||||
column_count = 8,
|
||||
row_count = 8,
|
||||
},
|
||||
}
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
--- name: Launchpad Pro mk3 - Live mode
|
||||
--- realearn_version: 2.16.0-pre.8
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: Novation
|
||||
--- device_name: Launchpad Pro mk3
|
||||
--- description: |
|
||||
--- This controller preset exposes all control elements of the Launchpad Pro mk3 in a neutral way. It supports
|
||||
--- ReaLearn color feedback as well as Playtime slot status feedback.
|
||||
--- midi_identity_pattern: F0 7E ? 06 02 00 20 29 23 01 00 00 * F7
|
||||
--- midi_output_port_patterns: ["macos:*DAW*", "windows:*MIDIOUT3*"]
|
||||
--- provided_schemes: [novation/launchpad-pro-mk3/live, grid]
|
||||
|
||||
--!strict
|
||||
|
||||
-- Requires
|
||||
|
||||
local preset_runtime = require("preset_runtime")
|
||||
local realearn = require("realearn")
|
||||
|
||||
-- Define MIDI scripts
|
||||
|
||||
local common_lua = preset_runtime.include_str("novation/launchpad-lib/compartment-common.luau")
|
||||
|
||||
local function build_pad_script(pad_index: number): string
|
||||
return `return require("compartment").pad_script({pad_index}, y, context)`
|
||||
end
|
||||
|
||||
-- Single buttons
|
||||
|
||||
local function simple_button(id: string, name: string, cc: number): realearn.Mapping
|
||||
return realearn.Mapping {
|
||||
id = id,
|
||||
name = name,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = cc,
|
||||
character = "Button",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local init_mapping = realearn.Mapping {
|
||||
name = "Enter DAW mode and select session layout",
|
||||
source = realearn.Source.MidiScript {
|
||||
script_kind = "Lua",
|
||||
script = [[
|
||||
local standalone_mode = 0x00
|
||||
local daw_mode = 0x01
|
||||
local session_layout = 0x00
|
||||
local session_layout_page = 0x00
|
||||
local mode = if y == nil then standalone_mode else daw_mode
|
||||
local enter_or_leave_daw_mode_msg = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x0E, 0x10, mode, 0xF7 }
|
||||
local select_session_layout = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x0E, 0x00, session_layout, session_layout_page, 0x00, 0xF7 }
|
||||
|
||||
local messages = {
|
||||
enter_or_leave_daw_mode_msg,
|
||||
}
|
||||
if y then
|
||||
table.insert(messages, select_session_layout)
|
||||
end
|
||||
|
||||
return {
|
||||
messages = messages
|
||||
}
|
||||
]]
|
||||
},
|
||||
target = realearn.Target.Dummy {
|
||||
}
|
||||
}
|
||||
|
||||
local mappings = {
|
||||
init_mapping,
|
||||
simple_button("shift", "Shift", 90),
|
||||
simple_button("cursor-left", "Left", 91),
|
||||
simple_button("cursor-right", "Right", 92),
|
||||
simple_button("session", "Session", 93),
|
||||
|
||||
simple_button("cursor-up", "Up", 80),
|
||||
simple_button("cursor-down", "Down", 70),
|
||||
simple_button("delete", "Clear", 60),
|
||||
simple_button("duplicate", "Duplicate", 50),
|
||||
simple_button("quantize", "Quantise", 40),
|
||||
simple_button("fixed-length", "Fixed length", 30),
|
||||
simple_button("play", "Play", 20),
|
||||
simple_button("record", "Record", 10),
|
||||
|
||||
simple_button("record-arm", "Record Arm", 1),
|
||||
simple_button("mute", "Mute", 2),
|
||||
simple_button("solo", "Solo", 3),
|
||||
simple_button("volume", "Volume", 4),
|
||||
simple_button("pan", "Pan", 5),
|
||||
simple_button("sends", "Sends", 6),
|
||||
simple_button("device", "Device", 7),
|
||||
simple_button("stop-clip", "Stop Clip", 8),
|
||||
}
|
||||
|
||||
-- Clip launch buttons
|
||||
|
||||
for col = 0, 7 do
|
||||
local human_col = col + 1
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local key_number_offset = 11 + (7 - row) * 10
|
||||
local id = `col{human_col}/row{human_row}/pad`
|
||||
local control_mapping = realearn.Mapping {
|
||||
id = id,
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = key_number_offset + col,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Multi",
|
||||
},
|
||||
}
|
||||
local feedback_mapping = realearn.Mapping {
|
||||
id = `{id}-feedback`,
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiScript {
|
||||
script_kind = "Lua",
|
||||
script = build_pad_script(key_number_offset + col),
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Multi",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, control_mapping)
|
||||
table.insert(mappings, feedback_mapping)
|
||||
end
|
||||
end
|
||||
|
||||
-- Scene launch buttons
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local id = `row{human_row}/play`
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = 19 + (7 - row) * 10,
|
||||
character = "Button",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
-- Column action buttons
|
||||
for col = 0, 7 do
|
||||
local human_col = col + 1
|
||||
local id = `col{human_col}/action`
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = 101 + col,
|
||||
character = "Button",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
return realearn.Compartment {
|
||||
common_lua = common_lua,
|
||||
mappings = mappings,
|
||||
custom_data = {
|
||||
grid = {
|
||||
column_count = 8,
|
||||
row_count = 8,
|
||||
},
|
||||
}
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
--- name: Launchpad X - Live mode
|
||||
--- realearn_version: 2.16.0-pre.8
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: Novation
|
||||
--- device_name: Launchpad X
|
||||
--- description: |
|
||||
--- This controller preset exposes all control elements of the Launchpad X in a neutral way. It supports
|
||||
--- ReaLearn color feedback as well as Playtime slot status feedback.
|
||||
--- midi_identity_pattern: F0 7E ? 06 02 00 20 29 03 01 00 00 * F7
|
||||
--- midi_output_port_patterns: ["macos:*DAW*", "windows:LPX MIDI"]
|
||||
--- provided_schemes: [novation/launchpad-x/live, grid]
|
||||
|
||||
--!strict
|
||||
|
||||
-- Requires
|
||||
|
||||
local preset_runtime = require("preset_runtime")
|
||||
local realearn = require("realearn")
|
||||
|
||||
-- Define MIDI scripts
|
||||
|
||||
local common_lua = preset_runtime.include_str("novation/launchpad-lib/compartment-common.luau")
|
||||
|
||||
local function build_pad_script(pad_index: number): string
|
||||
return `return require("compartment").pad_script({pad_index}, y, context)`
|
||||
end
|
||||
|
||||
-- Single buttons
|
||||
|
||||
local function simple_button(id: string, name: string, cc: number): realearn.Mapping
|
||||
return realearn.Mapping {
|
||||
id = id,
|
||||
name = name,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = cc,
|
||||
character = "Button",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local init_mapping = realearn.Mapping {
|
||||
name = "Enter DAW mode and select session layout",
|
||||
source = realearn.Source.MidiScript {
|
||||
script_kind = "Lua",
|
||||
script = [[
|
||||
local standalone_mode = 0x00
|
||||
local daw_mode = 0x01
|
||||
local session_layout = 0x00
|
||||
local mode = if y == nil then standalone_mode else daw_mode
|
||||
local enter_or_leave_daw_mode_msg = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x0C, 0x10, mode, 0xF7 }
|
||||
local select_session_layout = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x0C, 0x00, session_layout, 0xF7 }
|
||||
|
||||
local messages = {
|
||||
enter_or_leave_daw_mode_msg,
|
||||
}
|
||||
if y then
|
||||
table.insert(messages, select_session_layout)
|
||||
end
|
||||
|
||||
return {
|
||||
messages = messages
|
||||
}
|
||||
]]
|
||||
},
|
||||
target = realearn.Target.Dummy {
|
||||
}
|
||||
}
|
||||
|
||||
local mappings = {
|
||||
init_mapping,
|
||||
|
||||
simple_button("cursor-up", "Up", 91),
|
||||
simple_button("cursor-down", "Down", 92),
|
||||
simple_button("cursor-left", "Left", 93),
|
||||
simple_button("cursor-right", "Right", 94),
|
||||
simple_button("session", "Session", 95),
|
||||
simple_button("note", "Note", 96),
|
||||
simple_button("custom", "Custom", 97),
|
||||
simple_button("record", "Record", 98),
|
||||
}
|
||||
|
||||
-- Clip launch buttons
|
||||
|
||||
for col = 0, 7 do
|
||||
local human_col = col + 1
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local key_number_offset = 11 + (7 - row) * 10
|
||||
local id = `col{human_col}/row{human_row}/pad`
|
||||
local control_mapping = realearn.Mapping {
|
||||
id = id,
|
||||
feedback_enabled = false,
|
||||
source = realearn.Source.MidiNoteVelocity {
|
||||
channel = 0,
|
||||
key_number = key_number_offset + col,
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Multi",
|
||||
},
|
||||
}
|
||||
local feedback_mapping = realearn.Mapping {
|
||||
id = `{id}-feedback`,
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiScript {
|
||||
script_kind = "Lua",
|
||||
script = build_pad_script(key_number_offset + col),
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Multi",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, control_mapping)
|
||||
table.insert(mappings, feedback_mapping)
|
||||
end
|
||||
end
|
||||
|
||||
-- Scene launch buttons
|
||||
for row = 0, 7 do
|
||||
local human_row = row + 1
|
||||
local id = `row{human_row}/play`
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = 19 + (7 - row) * 10,
|
||||
character = "Button",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
|
||||
return realearn.Compartment {
|
||||
common_lua = common_lua,
|
||||
mappings = mappings,
|
||||
custom_data = {
|
||||
grid = {
|
||||
column_count = 8,
|
||||
row_count = 8,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../api/luau/playtime.luau
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../api/luau/preset_runtime.luau
|
||||
@@ -0,0 +1 @@
|
||||
../../api/luau/realearn.luau
|
||||
+722
@@ -0,0 +1,722 @@
|
||||
--!strict
|
||||
|
||||
local realearn = require("realearn")
|
||||
|
||||
local module = {}
|
||||
|
||||
export type PresetMode = "native" | "midi-absolute" | "midi-relative"
|
||||
|
||||
export type PresetConfig = {
|
||||
mode: PresetMode,
|
||||
|
||||
}
|
||||
|
||||
function module.create_compartment(config: PresetConfig): realearn.Compartment
|
||||
-- Config
|
||||
|
||||
-- With this, we can simulate true relative control.
|
||||
--
|
||||
-- In MIDI mode, the encoders of the Console 1 send absolute control values, not relative ones. This is
|
||||
-- not optimal because it means we can't define step sizes, wrap etc. However, as long as feedback is enabled, at least we don't
|
||||
-- need to suffer from parameter jumps (a common disadvantage of absolute control).
|
||||
-- This is because the Console 1 doesn't just use the feedback to set the LED ring, it also resets its internal encoder
|
||||
-- value to the incoming feedback value.
|
||||
--
|
||||
-- If we simulate relative control, we get the advantages of relative control. However, it doesn't
|
||||
-- work so nicely with feedback :( The "reset-internal-encoder-value" mechanism mentioned above interferes.
|
||||
-- Without further treatment, this makes the control stuck. We can make control work by not sending echo feedback
|
||||
-- but then the indicated LED ring value is incorrect when we turn the encoder (however, it is correct when changing the parameter
|
||||
-- in REAPER itself - as long as we don't disable feedback completely).
|
||||
-- The technique we use right now is to compare with the previously sent feedback value - if available - and otherwise the previously
|
||||
-- sent control value. This sort of works, but there can be glitches because it's not always sure that the last-sent feedback value
|
||||
-- has actually been received by the controller.
|
||||
local simulate_relative_control_in_midi_mode = config.mode == "midi-relative"
|
||||
|
||||
local native_mode = config.mode == "native"
|
||||
|
||||
-- Code
|
||||
|
||||
local realearn = require("realearn")
|
||||
|
||||
local sysex_to_relative_transformation = [[
|
||||
y_type = 1;
|
||||
y = prev_timestamp == 0 ? (
|
||||
1
|
||||
) : (
|
||||
// Implement encoder acceleration based on timestamp diffs
|
||||
diff_millis = (realearn_timestamp - prev_timestamp) * 1000;
|
||||
added = 10 / diff_millis;
|
||||
// realearn_dbg(added);
|
||||
1 + added
|
||||
);
|
||||
prev_timestamp = realearn_timestamp;
|
||||
]]
|
||||
|
||||
local abs_to_rel_transformation = [[
|
||||
y_type = 1;
|
||||
// If the last-sent feedback value is available, we use this one as reference (because the controller
|
||||
// resets its internal value to the last-sent feedback value). If not (e.g. if feedback is disabled),
|
||||
// we use the last-sent control value as reference.
|
||||
ref = realearn_last_feedback_value == prev_last_feedback_value ? prev_x : realearn_last_feedback_value;
|
||||
y = count == 0 ? (
|
||||
// On first invocation, we don't have any reference value to compare to
|
||||
0
|
||||
) : x > ref || x == 1 ? (
|
||||
// Controller sends higher number than reference value or encoder hit right boundary. Looks like an increment.
|
||||
1
|
||||
) : x < ref || x == 0 ? (
|
||||
// Controller sends lower number than reference value or encoder hit left boundary. Looks like a decrement.
|
||||
-1
|
||||
) : (
|
||||
// No change
|
||||
none
|
||||
);
|
||||
prev_last_feedback_value = last_feedback_value;
|
||||
prev_x = x;
|
||||
count += 1;
|
||||
]]
|
||||
|
||||
local mappings = {}
|
||||
|
||||
local function button(
|
||||
id: string,
|
||||
target: realearn.Target,
|
||||
name: string,
|
||||
cc: number?,
|
||||
on_sysex: string,
|
||||
off_sysex: string
|
||||
)
|
||||
local cc_source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = cc,
|
||||
character = "Button",
|
||||
}
|
||||
if native_mode then
|
||||
local on_mapping = realearn.Mapping {
|
||||
id = `{id}-on`,
|
||||
feedback_enabled = false,
|
||||
name = name,
|
||||
source = realearn.Source.MidiRaw {
|
||||
pattern = on_sysex,
|
||||
},
|
||||
target = target,
|
||||
}
|
||||
table.insert(mappings, on_mapping)
|
||||
local off_mapping = realearn.Mapping {
|
||||
id = `{id}-off`,
|
||||
feedback_enabled = false,
|
||||
name = name,
|
||||
source = realearn.Source.MidiRaw {
|
||||
pattern = off_sysex,
|
||||
},
|
||||
glue = {
|
||||
reverse = true,
|
||||
},
|
||||
target = target,
|
||||
}
|
||||
table.insert(mappings, off_mapping)
|
||||
if cc then
|
||||
local feedback_mapping = realearn.Mapping {
|
||||
id = `{id}-feedback`,
|
||||
control_enabled = false,
|
||||
name = name,
|
||||
source = cc_source,
|
||||
target = target,
|
||||
}
|
||||
table.insert(mappings, feedback_mapping)
|
||||
end
|
||||
else
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
name = name,
|
||||
source = cc_source,
|
||||
target = target,
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
end
|
||||
|
||||
local function named_button(id: string, name: string, cc: number?, on_sysex: string, off_sysex: string)
|
||||
local target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Button",
|
||||
}
|
||||
button(id, target, name, cc, on_sysex, off_sysex)
|
||||
end
|
||||
|
||||
local function numbered_button(index: number, name: string, cc: number, on_sysex: string, off_sysex: string)
|
||||
local target = realearn.Target.Virtual {
|
||||
id = index,
|
||||
character = "Button",
|
||||
}
|
||||
button(tostring(index), target, name, cc, on_sysex, off_sysex)
|
||||
end
|
||||
|
||||
local function encoder(id: string, name: string, cc: number, cw_sysex: string, ccw_sysex: string)
|
||||
local cc_source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = cc,
|
||||
character = "Range",
|
||||
-- Preventing echo feedback would make the LED ring show the incorrect value when we turn the encoder
|
||||
-- (it would be correct when changing the parameter in REAPER itself).
|
||||
-- feedback_behavior = "PreventEchoFeedback",
|
||||
}
|
||||
local target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Multi",
|
||||
}
|
||||
if native_mode then
|
||||
local cw_mapping = realearn.Mapping {
|
||||
id = `{id}-cw`,
|
||||
feedback_enabled = false,
|
||||
name = name,
|
||||
source = realearn.Source.MidiRaw {
|
||||
pattern = cw_sysex,
|
||||
character = "Button",
|
||||
},
|
||||
glue = realearn.Glue {
|
||||
control_transformation = sysex_to_relative_transformation,
|
||||
step_factor_interval = {1, 100},
|
||||
},
|
||||
target = target,
|
||||
}
|
||||
local ccw_mapping = realearn.Mapping {
|
||||
id = `{id}-ccw`,
|
||||
feedback_enabled = false,
|
||||
name = name,
|
||||
source = realearn.Source.MidiRaw {
|
||||
pattern = ccw_sysex,
|
||||
character = "Button",
|
||||
},
|
||||
glue = {
|
||||
control_transformation = sysex_to_relative_transformation,
|
||||
step_factor_interval = {1, 100},
|
||||
reverse = true,
|
||||
},
|
||||
target = target,
|
||||
}
|
||||
local feedback_mapping = realearn.Mapping {
|
||||
id = `{id}-feedback`,
|
||||
control_enabled = false,
|
||||
name = name,
|
||||
source = cc_source,
|
||||
target = target,
|
||||
}
|
||||
table.insert(mappings, cw_mapping)
|
||||
table.insert(mappings, ccw_mapping)
|
||||
table.insert(mappings, feedback_mapping)
|
||||
else
|
||||
local mapping = realearn.Mapping {
|
||||
id = id,
|
||||
name = name,
|
||||
source = cc_source,
|
||||
glue = realearn.Glue {
|
||||
control_transformation = if simulate_relative_control_in_midi_mode then abs_to_rel_transformation else nil,
|
||||
},
|
||||
target = target,
|
||||
}
|
||||
table.insert(mappings, mapping)
|
||||
end
|
||||
end
|
||||
|
||||
local function meter(id: string, name: string, cc: number)
|
||||
local m = realearn.Mapping {
|
||||
id = id,
|
||||
name = name,
|
||||
control_enabled = false,
|
||||
source = realearn.Source.MidiControlChangeValue {
|
||||
channel = 0,
|
||||
controller_number = cc,
|
||||
character = "Range",
|
||||
},
|
||||
target = realearn.Target.Virtual {
|
||||
id = id,
|
||||
character = "Multi",
|
||||
},
|
||||
}
|
||||
table.insert(mappings, m)
|
||||
end
|
||||
|
||||
-- Named buttons in row 1
|
||||
named_button("display-on", "Display: On", 102, "", "")
|
||||
named_button(
|
||||
"display/mode",
|
||||
"Display: Mode",
|
||||
104,
|
||||
"F0 7D 00 00 00 00 02 00 01 7F 01 02 55 0A 0C F7",
|
||||
"F0 7D 00 00 00 00 02 00 01 00 41 38 39 27 01 F7"
|
||||
)
|
||||
named_button(
|
||||
"page/prev",
|
||||
"Page: -",
|
||||
97,
|
||||
"F0 7D 00 00 00 00 02 00 03 7F 33 34 37 08 0D F7",
|
||||
"F0 7D 00 00 00 00 02 00 03 00 73 0E 5B 25 00 F7"
|
||||
)
|
||||
named_button(
|
||||
"page/next",
|
||||
"Page: +",
|
||||
96,
|
||||
"F0 7D 00 00 00 00 02 00 04 7F 7C 75 21 4F 0E F7",
|
||||
"F0 7D 00 00 00 00 02 00 04 00 3C 4F 4D 62 03 F7"
|
||||
)
|
||||
named_button(
|
||||
"track/group",
|
||||
"Track: Group",
|
||||
123,
|
||||
"F0 7D 00 00 00 00 02 00 19 7F 03 19 4D 53 06 F7",
|
||||
"F0 7D 00 00 00 00 02 00 19 00 43 23 21 7E 0B F7"
|
||||
)
|
||||
named_button(
|
||||
"track/copy",
|
||||
"Track: Copy",
|
||||
120,
|
||||
"F0 7D 00 00 00 00 02 00 1A 7F 28 34 1E 10 07 F7",
|
||||
"F0 7D 00 00 00 00 02 00 1A 00 68 0E 72 3D 0A F7"
|
||||
)
|
||||
named_button(
|
||||
"order",
|
||||
"Order",
|
||||
14,
|
||||
"F0 7D 00 00 00 00 02 00 3A 7F 3D 30 3A 32 0A F7",
|
||||
"F0 7D 00 00 00 00 02 00 3A 00 7D 0A 56 1F 07 F7"
|
||||
)
|
||||
named_button(
|
||||
"external-sidechain",
|
||||
"External Sidechain",
|
||||
17,
|
||||
"F0 7D 00 00 00 00 02 00 3B 7F 24 2B 0B 73 0A F7",
|
||||
"F0 7D 00 00 00 00 02 00 3B 00 64 11 67 5E 07 F7"
|
||||
)
|
||||
-- Numbered buttons in row 1
|
||||
numbered_button(
|
||||
0,
|
||||
`Select track 1`,
|
||||
21,
|
||||
"F0 7D 00 00 00 00 02 00 05 7F 65 6E 10 0E 0E F7",
|
||||
"F0 7D 00 00 00 00 02 00 05 00 25 54 7C 23 03 F7"
|
||||
)
|
||||
numbered_button(
|
||||
1,
|
||||
`Select track 2`,
|
||||
22,
|
||||
"F0 7D 00 00 00 00 02 00 06 7F 4E 43 43 4D 0F F7",
|
||||
"F0 7D 00 00 00 00 02 00 06 00 0E 79 2F 60 02 F7"
|
||||
)
|
||||
numbered_button(
|
||||
2,
|
||||
`Select track 3`,
|
||||
23,
|
||||
"F0 7D 00 00 00 00 02 00 07 7F 57 58 72 0C 0F F7",
|
||||
"F0 7D 00 00 00 00 02 00 07 00 17 62 1E 21 02 F7"
|
||||
)
|
||||
numbered_button(
|
||||
3,
|
||||
`Select track 4`,
|
||||
24,
|
||||
"F0 7D 00 00 00 00 02 00 08 7F 50 40 6E 43 02 F7",
|
||||
"F0 7D 00 00 00 00 02 00 08 00 10 7A 02 6E 0F F7"
|
||||
)
|
||||
numbered_button(
|
||||
4,
|
||||
`Select track 5`,
|
||||
25,
|
||||
"F0 7D 00 00 00 00 02 00 09 7F 49 5B 5F 02 02 F7",
|
||||
"F0 7D 00 00 00 00 02 00 09 00 09 61 33 2F 0F F7"
|
||||
)
|
||||
numbered_button(
|
||||
5,
|
||||
`Select track 6`,
|
||||
26,
|
||||
"F0 7D 00 00 00 00 02 00 0A 7F 62 76 0C 41 03 F7",
|
||||
"F0 7D 00 00 00 00 02 00 0A 00 22 4C 60 6C 0E F7"
|
||||
)
|
||||
numbered_button(
|
||||
6,
|
||||
"Select track 7",
|
||||
27,
|
||||
"F0 7D 00 00 00 00 02 00 0B 7F 7B 6D 3D 00 03 F7",
|
||||
"F0 7D 00 00 00 00 02 00 0B 00 3B 57 51 2D 0E F7"
|
||||
)
|
||||
numbered_button(
|
||||
7,
|
||||
"Select track 8",
|
||||
28,
|
||||
"F0 7D 00 00 00 00 02 00 0C 7F 34 2C 2B 47 00 F7",
|
||||
"F0 7D 00 00 00 00 02 00 0C 00 74 16 47 6A 0D F7"
|
||||
)
|
||||
numbered_button(
|
||||
8,
|
||||
"Select track 9",
|
||||
29,
|
||||
"F0 7D 00 00 00 00 02 00 0D 7F 2D 37 1A 06 00 F7",
|
||||
"F0 7D 00 00 00 00 02 00 0D 00 6D 0D 76 2B 0D F7"
|
||||
)
|
||||
numbered_button(
|
||||
9,
|
||||
"Select track 10",
|
||||
30,
|
||||
"F0 7D 00 00 00 00 02 00 0E 7F 06 1A 49 45 01 F7",
|
||||
"F0 7D 00 00 00 00 02 00 0E 00 46 20 25 68 0C F7"
|
||||
)
|
||||
numbered_button(
|
||||
10,
|
||||
"Select track 11",
|
||||
31,
|
||||
"F0 7D 00 00 00 00 02 00 0F 7F 1F 01 78 04 01 F7",
|
||||
"F0 7D 00 00 00 00 02 00 0F 00 5F 3B 14 29 0C F7"
|
||||
)
|
||||
numbered_button(
|
||||
11,
|
||||
"Select track 12",
|
||||
32,
|
||||
"F0 7D 00 00 00 00 02 00 10 7F 52 5B 76 1A 08 F7",
|
||||
"F0 7D 00 00 00 00 02 00 10 00 12 61 1A 37 05 F7"
|
||||
)
|
||||
numbered_button(
|
||||
12,
|
||||
"Select track 13",
|
||||
33,
|
||||
"F0 7D 00 00 00 00 02 00 11 7F 4B 40 47 5B 08 F7",
|
||||
"F0 7D 00 00 00 00 02 00 11 00 0B 7A 2B 76 05 F7"
|
||||
)
|
||||
numbered_button(
|
||||
13,
|
||||
"Select track 14",
|
||||
34,
|
||||
"F0 7D 00 00 00 00 02 00 12 7F 60 6D 14 18 09 F7",
|
||||
"F0 7D 00 00 00 00 02 00 12 00 20 57 78 35 04 F7"
|
||||
)
|
||||
numbered_button(
|
||||
14,
|
||||
"Select track 15",
|
||||
35,
|
||||
"F0 7D 00 00 00 00 02 00 13 7F 79 76 25 59 09 F7",
|
||||
"F0 7D 00 00 00 00 02 00 13 00 39 4C 49 74 04 F7"
|
||||
)
|
||||
numbered_button(
|
||||
15,
|
||||
"Select track 16",
|
||||
36,
|
||||
"F0 7D 00 00 00 00 02 00 14 7F 36 37 33 1E 0A F7",
|
||||
"F0 7D 00 00 00 00 02 00 14 00 76 0D 5F 33 07 F7"
|
||||
)
|
||||
numbered_button(
|
||||
16,
|
||||
"Select track 17",
|
||||
37,
|
||||
"F0 7D 00 00 00 00 02 00 15 7F 2F 2C 02 5F 0A F7",
|
||||
"F0 7D 00 00 00 00 02 00 15 00 6F 16 6E 72 07 F7"
|
||||
)
|
||||
numbered_button(
|
||||
17,
|
||||
"Select track 18",
|
||||
38,
|
||||
"F0 7D 00 00 00 00 02 00 16 7F 04 01 51 1C 0B F7",
|
||||
"F0 7D 00 00 00 00 02 00 16 00 44 3B 3D 31 06 F7"
|
||||
)
|
||||
numbered_button(
|
||||
18,
|
||||
"Select track 19",
|
||||
39,
|
||||
"F0 7D 00 00 00 00 02 00 17 7F 1D 1A 60 5D 0B F7",
|
||||
"F0 7D 00 00 00 00 02 00 17 00 5D 20 0C 70 06 F7"
|
||||
)
|
||||
numbered_button(
|
||||
19,
|
||||
"Select track 20",
|
||||
40,
|
||||
"F0 7D 00 00 00 00 02 00 18 7F 1A 02 7C 12 06 F7",
|
||||
"F0 7D 00 00 00 00 02 00 18 00 5A 38 10 3F 0B F7"
|
||||
)
|
||||
-- Buttons in row 2
|
||||
named_button(
|
||||
"shape",
|
||||
"Shape",
|
||||
53,
|
||||
"F0 7D 00 00 00 00 02 00 21 7F 14 06 71 28 01 F7",
|
||||
"F0 7D 00 00 00 00 02 00 21 00 54 3C 1D 05 0C F7"
|
||||
)
|
||||
named_button(
|
||||
"eq",
|
||||
"Equalizer",
|
||||
80,
|
||||
"F0 7D 00 00 00 00 02 00 27 7F 42 5C 56 2E 02 F7",
|
||||
"F0 7D 00 00 00 00 02 00 27 00 02 66 3A 03 0F F7"
|
||||
)
|
||||
named_button(
|
||||
"comp",
|
||||
"Compressor",
|
||||
46,
|
||||
"F0 7D 00 00 00 00 02 00 34 7F 23 33 17 3C 07 F7",
|
||||
"F0 7D 00 00 00 00 02 00 34 00 63 09 7B 11 0A F7"
|
||||
)
|
||||
-- Buttons in row 3
|
||||
named_button(
|
||||
"eq/low/type",
|
||||
"EQ: Low type",
|
||||
93,
|
||||
"F0 7D 00 00 00 00 02 00 28 7F 45 44 4A 61 0F F7",
|
||||
"F0 7D 00 00 00 00 02 00 28 00 05 7E 26 4C 02 F7"
|
||||
)
|
||||
named_button(
|
||||
"eq/high/type",
|
||||
"EQ: High type",
|
||||
65,
|
||||
"F0 7D 00 00 00 00 02 00 31 7F 5E 44 63 79 05 F7",
|
||||
"F0 7D 00 00 00 00 02 00 31 00 1E 7E 0F 54 08 F7"
|
||||
)
|
||||
-- Buttons in row 4
|
||||
named_button(
|
||||
"shape/hard-gate",
|
||||
"Shape: Hard Gate",
|
||||
59,
|
||||
"F0 7D 00 00 00 00 02 00 23 7F 26 30 13 2A 00 F7",
|
||||
"F0 7D 00 00 00 00 02 00 23 00 66 0A 7F 07 0D F7"
|
||||
)
|
||||
named_button(
|
||||
"solo",
|
||||
"Solo",
|
||||
13,
|
||||
"F0 7D 00 00 00 00 02 00 3F 7F 40 47 4E 77 08 F7",
|
||||
"F0 7D 00 00 00 00 02 00 3F 00 00 7D 22 5A 05 F7"
|
||||
)
|
||||
named_button(
|
||||
"mute",
|
||||
"Mute",
|
||||
12,
|
||||
"F0 7D 00 00 00 00 02 00 40 7F 68 60 2B 4E 04 F7",
|
||||
"F0 7D 00 00 00 00 02 00 40 00 28 5A 47 63 09 F7"
|
||||
)
|
||||
-- Remaining buttons
|
||||
named_button(
|
||||
"filters-to-compressor",
|
||||
"Filters to Compressor",
|
||||
61,
|
||||
"F0 7D 00 00 00 00 02 00 1E 7F 4C 58 5B 14 05 F7",
|
||||
"F0 7D 00 00 00 00 02 00 1E 00 0C 62 37 39 08 F7"
|
||||
)
|
||||
named_button(
|
||||
"phase-inv",
|
||||
"Phase Inv.",
|
||||
108,
|
||||
"F0 7D 00 00 00 00 02 00 1F 7F 55 43 6A 55 05 F7",
|
||||
"F0 7D 00 00 00 00 02 00 1F 00 15 79 06 78 08 F7"
|
||||
)
|
||||
named_button(
|
||||
"preset",
|
||||
"Preset",
|
||||
58,
|
||||
"F0 7D 00 00 00 00 02 00 20 7F 0D 1D 40 69 01 F7",
|
||||
"F0 7D 00 00 00 00 02 00 20 00 4D 27 2C 44 0C F7"
|
||||
)
|
||||
if native_mode then
|
||||
named_button(
|
||||
"fine-adjust",
|
||||
"Fine Adjust",
|
||||
nil,
|
||||
"F0 7D 00 00 00 00 02 00 02 7F 2A 2F 06 49 0D F7",
|
||||
"F0 7D 00 00 00 00 02 00 02 00 6A 15 6A 64 00 F7"
|
||||
)
|
||||
end
|
||||
-- Encoders in row 1
|
||||
encoder(
|
||||
"high-cut",
|
||||
"High Cut",
|
||||
105,
|
||||
"F0 7D 00 00 00 00 02 00 1C 7F 7E 6E 39 16 04 F7",
|
||||
"F0 7D 00 00 00 00 02 00 1C 00 3E 54 55 3B 09 F7"
|
||||
)
|
||||
encoder(
|
||||
"shape/gate-release",
|
||||
"Shape: Gate Release",
|
||||
56,
|
||||
"F0 7D 00 00 00 00 02 00 24 7F 69 71 05 6D 03 F7",
|
||||
"F0 7D 00 00 00 00 02 00 24 00 29 4B 69 40 0E F7"
|
||||
)
|
||||
encoder(
|
||||
"eq/low-mid/type",
|
||||
"EQ: Low Mid Type",
|
||||
90,
|
||||
"F0 7D 00 00 00 00 02 00 2C 7F 21 28 0F 65 0D F7",
|
||||
"F0 7D 00 00 00 00 02 00 2C 00 61 12 63 48 00 F7"
|
||||
)
|
||||
encoder(
|
||||
"eq/high-mid/type",
|
||||
"EQ: High Mid Type",
|
||||
87,
|
||||
"F0 7D 00 00 00 00 02 00 2F 7F 0A 05 5C 26 0C F7",
|
||||
"F0 7D 00 00 00 00 02 00 2F 00 4A 3F 30 0B 01 F7"
|
||||
)
|
||||
encoder(
|
||||
"comp/attack",
|
||||
"Comp: Attack",
|
||||
51,
|
||||
"F0 7D 00 00 00 00 02 00 37 7F 08 1E 44 7F 06 F7",
|
||||
"F0 7D 00 00 00 00 02 00 37 00 48 24 28 52 0B F7"
|
||||
)
|
||||
encoder(
|
||||
"drive",
|
||||
"Drive",
|
||||
15,
|
||||
"F0 7D 00 00 00 00 02 00 3C 7F 6B 6A 1D 34 09 F7",
|
||||
"F0 7D 00 00 00 00 02 00 3C 00 2B 50 71 19 04 F7"
|
||||
)
|
||||
-- Encoders in row 2
|
||||
encoder(
|
||||
"shape/gate",
|
||||
"Shape: Gate",
|
||||
54,
|
||||
"F0 7D 00 00 00 00 02 00 22 7F 3F 2B 22 6B 00 F7",
|
||||
"F0 7D 00 00 00 00 02 00 22 00 7F 11 4E 46 0D F7"
|
||||
)
|
||||
encoder(
|
||||
"comp/ratio",
|
||||
"Comp: Ratio",
|
||||
49,
|
||||
"F0 7D 00 00 00 00 02 00 35 7F 3A 28 26 7D 07 F7",
|
||||
"F0 7D 00 00 00 00 02 00 35 00 7A 12 4A 50 0A F7"
|
||||
)
|
||||
-- Encoders in row 3
|
||||
encoder(
|
||||
"low-cut",
|
||||
"Low Cut",
|
||||
103,
|
||||
"F0 7D 00 00 00 00 02 00 1D 7F 67 75 08 57 04 F7",
|
||||
"F0 7D 00 00 00 00 02 00 1D 00 27 4F 64 7A 09 F7"
|
||||
)
|
||||
encoder(
|
||||
"shape/sustain",
|
||||
"Shape: Sustain",
|
||||
55,
|
||||
"F0 7D 00 00 00 00 02 00 25 7F 70 6A 34 2C 03 F7",
|
||||
"F0 7D 00 00 00 00 02 00 25 00 30 50 58 01 0E F7"
|
||||
)
|
||||
encoder(
|
||||
"eq/low/freq",
|
||||
"EQ: Low Frequency",
|
||||
92,
|
||||
"F0 7D 00 00 00 00 02 00 29 7F 5C 5F 7B 20 0F F7",
|
||||
"F0 7D 00 00 00 00 02 00 29 00 1C 65 17 0D 02 F7"
|
||||
)
|
||||
encoder(
|
||||
"eq/low-mid/freq",
|
||||
"EQ: Low Mid Frequency",
|
||||
89,
|
||||
"F0 7D 00 00 00 00 02 00 2B 7F 6E 69 19 22 0E F7",
|
||||
"F0 7D 00 00 00 00 02 00 2B 00 2E 53 75 0F 03 F7"
|
||||
)
|
||||
encoder(
|
||||
"eq/high-mid/freq",
|
||||
"EQ: High Mid Frequency",
|
||||
86,
|
||||
"F0 7D 00 00 00 00 02 00 2E 7F 13 1E 6D 67 0C F7",
|
||||
"F0 7D 00 00 00 00 02 00 2E 00 53 24 01 4A 01 F7"
|
||||
)
|
||||
encoder(
|
||||
"eq/high/freq",
|
||||
"EQ: High Frequency",
|
||||
83,
|
||||
"F0 7D 00 00 00 00 02 00 32 7F 75 69 30 3A 04 F7",
|
||||
"F0 7D 00 00 00 00 02 00 32 00 35 53 5C 17 09 F7"
|
||||
)
|
||||
encoder(
|
||||
"comp/release",
|
||||
"Comp: Release",
|
||||
48,
|
||||
"F0 7D 00 00 00 00 02 00 38 7F 0F 06 58 30 0B F7",
|
||||
"F0 7D 00 00 00 00 02 00 38 00 4F 3C 34 1D 06 F7"
|
||||
)
|
||||
encoder(
|
||||
"character",
|
||||
"Character",
|
||||
18,
|
||||
"F0 7D 00 00 00 00 02 00 3D 7F 72 71 2C 75 09 F7",
|
||||
"F0 7D 00 00 00 00 02 00 3D 00 32 4B 40 58 04 F7"
|
||||
)
|
||||
-- Encoders in row 4
|
||||
encoder(
|
||||
"input/gain",
|
||||
"Input Gain",
|
||||
107,
|
||||
"F0 7D 00 00 00 00 02 00 1B 7F 31 2F 2F 51 07 F7",
|
||||
"F0 7D 00 00 00 00 02 00 1B 00 71 15 43 7C 0A F7"
|
||||
)
|
||||
encoder(
|
||||
"comp/parallel-dry-wet",
|
||||
"Comp: Parallel Dry/Wet",
|
||||
50,
|
||||
"F0 7D 00 00 00 00 02 00 36 7F 11 05 75 3E 06 F7",
|
||||
"F0 7D 00 00 00 00 02 00 36 00 51 3F 19 13 0B F7"
|
||||
)
|
||||
-- Encoders in row 5
|
||||
encoder(
|
||||
"shape/punch",
|
||||
"Shape: Punch",
|
||||
57,
|
||||
"F0 7D 00 00 00 00 02 00 26 7F 5B 47 67 6F 02 F7",
|
||||
"F0 7D 00 00 00 00 02 00 26 00 1B 7D 0B 42 0F F7"
|
||||
)
|
||||
encoder(
|
||||
"eq/low/gain",
|
||||
"EQ: Low Gain",
|
||||
91,
|
||||
"F0 7D 00 00 00 00 02 00 2A 7F 77 72 28 63 0E F7",
|
||||
"F0 7D 00 00 00 00 02 00 2A 00 37 48 44 4E 03 F7"
|
||||
)
|
||||
encoder(
|
||||
"eq/low-mid/gain",
|
||||
"EQ: Low Mid Gain",
|
||||
88,
|
||||
"F0 7D 00 00 00 00 02 00 2D 7F 38 33 3E 24 0D F7",
|
||||
"F0 7D 00 00 00 00 02 00 2D 00 78 09 52 09 00 F7"
|
||||
)
|
||||
encoder(
|
||||
"eq/high-mid/gain",
|
||||
"EQ: High Mid Gain",
|
||||
85,
|
||||
"F0 7D 00 00 00 00 02 00 30 7F 47 5F 52 38 05 F7",
|
||||
"F0 7D 00 00 00 00 02 00 30 00 07 65 3E 15 08 F7"
|
||||
)
|
||||
encoder(
|
||||
"eq/high/gain",
|
||||
"EQ: High Gain",
|
||||
82,
|
||||
"F0 7D 00 00 00 00 02 00 33 7F 6C 72 01 7B 04 F7",
|
||||
"F0 7D 00 00 00 00 02 00 33 00 2C 48 6D 56 09 F7"
|
||||
)
|
||||
encoder(
|
||||
"comp/threshold",
|
||||
"Comp: Threshold",
|
||||
47,
|
||||
"F0 7D 00 00 00 00 02 00 39 7F 16 1D 69 71 0B F7",
|
||||
"F0 7D 00 00 00 00 02 00 39 00 56 27 05 5C 06 F7"
|
||||
)
|
||||
encoder(
|
||||
"pan",
|
||||
"Pan",
|
||||
10,
|
||||
"F0 7D 00 00 00 00 02 00 3E 7F 59 5C 7F 36 08 F7",
|
||||
"F0 7D 00 00 00 00 02 00 3E 00 19 66 13 1B 05 F7"
|
||||
)
|
||||
encoder(
|
||||
"output/volume",
|
||||
"Volume",
|
||||
7,
|
||||
"F0 7D 00 00 00 00 02 00 41 7F 71 7B 1A 0F 04 F7",
|
||||
"F0 7D 00 00 00 00 02 00 41 00 31 41 76 22 09 F7"
|
||||
)
|
||||
-- Meters
|
||||
meter("input/meter/left", "Input Meter: Left channel", 110)
|
||||
meter("input/meter/right", "Input Meter: Right channel", 111)
|
||||
meter("output/meter/left", "Output Meter: Left channel", 112)
|
||||
meter("output/meter/right", "Output Meter: Right channel", 113)
|
||||
meter("shape/meter", "Shape Meter", 114)
|
||||
meter("comp/meter", "Compressor Meter", 115)
|
||||
|
||||
return realearn.Compartment {
|
||||
mappings = mappings,
|
||||
}
|
||||
end
|
||||
|
||||
return module
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
--- name: Console 1 mk2 - MIDI absolute mode
|
||||
--- realearn_version: 2.16.12
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: Softube
|
||||
--- device_name: Console 1 mk2
|
||||
--- description: |
|
||||
--- This controller preset implements support for the Softube Console 1 controller in MIDI mode, enabling absolute control.
|
||||
---
|
||||
--- Pros:
|
||||
--- * LED feedback without glitches
|
||||
--- * Button "On" is available and can be customized
|
||||
---
|
||||
--- Cons:
|
||||
--- * Buttons can't be turned into momentary buttons (because Console1 doesn't send any message on release)
|
||||
--- * True relative control is not possible (no user-defined step sizes and no wrap)
|
||||
--- * Without pressing "Fine Adjust", encoder control is very coarse
|
||||
--- * Button "Fine Adjust" can't be customized (it just switches to fine control on hardware side)
|
||||
--- * In order to avoid parameter jumps with the encoders, feedback must be enabled (alternatively, you can use
|
||||
--- ReaLearn's takeover modes)
|
||||
---
|
||||
--- setup_instructions: |
|
||||
--- 1. Connect the controller
|
||||
--- 2. Ensure that the Console 1 On-Screen Display software is **not** running!
|
||||
---
|
||||
--- provided_schemes: [softube/console1-mk2]
|
||||
|
||||
--!strict
|
||||
|
||||
-- Config
|
||||
|
||||
-- With this, we can simulate true relative control.
|
||||
--
|
||||
-- In MIDI mode, the encoders of the Console 1 send absolute control values, not relative ones. This is
|
||||
-- not optimal because it means we can't define step sizes, wrap etc. However, as long as feedback is enabled, at least we don't
|
||||
-- need to suffer from parameter jumps (a common disadvantage of absolute control).
|
||||
-- This is because the Console 1 doesn't just use the feedback to set the LED ring, it also resets its internal encoder
|
||||
-- value to the incoming feedback value.
|
||||
--
|
||||
-- If we simulate relative control, we get the advantages of relative control. However, it doesn't
|
||||
-- work so nicely with feedback :( The "reset-internal-encoder-value" mechanism mentioned above interferes.
|
||||
-- Without further treatment, this makes the control stuck. We can make control work by not sending echo feedback
|
||||
-- but then the indicated LED ring value is incorrect when we turn the encoder (however, it is correct when changing the parameter
|
||||
-- in REAPER itself - as long as we don't disable feedback completely).
|
||||
-- The technique we use right now is to compare with the previously sent feedback value - if available - and otherwise the previously
|
||||
-- sent control value. This sort of works, but there can be glitches because it's not always sure that the last-sent feedback value
|
||||
-- has actually been received by the controller.
|
||||
|
||||
local commons = require("softube/console1-mk2-lib/preset-common")
|
||||
return commons.create_compartment {
|
||||
mode = "midi-absolute",
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
--- name: Console 1 mk2 - MIDI relative mode
|
||||
--- realearn_version: 2.16.12
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: Softube
|
||||
--- device_name: Console 1 mk2
|
||||
--- description: |
|
||||
--- This controller preset implements support for the Softube Console 1 controller in MIDI mode, enabling relative control.
|
||||
---
|
||||
--- Pros:
|
||||
--- * True relative control
|
||||
--- * Button "On" is available and can be customized
|
||||
---
|
||||
--- Cons:
|
||||
--- * Buttons can't be turned into momentary buttons (because Console1 doesn't send any message on release)
|
||||
--- * Occasional control and feedback glitches are possible (Console1 encoders send absolute messages in a way that makes
|
||||
--- it hard to convert them into relative messages)
|
||||
--- * Reacting to encoder increments (or decrements) only via encoder filter doesn't work
|
||||
--- * Button "Fine Adjust" doesn't have any effect and can't be customized
|
||||
---
|
||||
--- setup_instructions: |
|
||||
--- 1. Connect the controller
|
||||
--- 2. Ensure that the Console 1 On-Screen Display software is **not** running!
|
||||
---
|
||||
--- provided_schemes: [softube/console1-mk2]
|
||||
|
||||
--!strict
|
||||
|
||||
-- Config
|
||||
|
||||
local commons = require("softube/console1-mk2-lib/preset-common")
|
||||
return commons.create_compartment {
|
||||
mode = "midi-relative",
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
--- name: Console 1 mk2 - Native mode
|
||||
--- realearn_version: 2.16.12
|
||||
--- author: helgoboss
|
||||
--- device_manufacturer: Softube
|
||||
--- device_name: Console 1 mk2
|
||||
--- description: |
|
||||
--- This controller preset implements support for the Softube Console 1 controller in native mode.
|
||||
---
|
||||
--- Pros:
|
||||
--- * True relative control without glitches
|
||||
--- * True momentary buttons
|
||||
--- * LED feedback without glitches
|
||||
--- * Button "Fine Adjust" is available and can be customized
|
||||
---
|
||||
--- Cons:
|
||||
--- * Button "On" is not available
|
||||
--- * Using Softube plug-ins that connect to the Console 1 is not possible (they would interfere)
|
||||
---
|
||||
--- setup_instructions: |
|
||||
--- 1. Connect the controller
|
||||
--- 2. Start the Console 1 On-Screen Display software
|
||||
--- 3. Make sure to not use any Softube plug-ins
|
||||
---
|
||||
--- provided_schemes: [softube/console1-mk2]
|
||||
|
||||
--!strict
|
||||
|
||||
local commons = require("softube/console1-mk2-lib/preset-common")
|
||||
return commons.create_compartment {
|
||||
mode = "native",
|
||||
}
|
||||
Reference in New Issue
Block a user