Reorganize top-level directories with clearer naming convention

app -> app-desktop-macos, presets -> app-presets, server -> remote-server,
daw-config-reaper -> osc-config-daw, plugin-reaper-realearn -> plugin-reaper-relearn.
Updated run.py and presets.py path references accordingly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Paul Lipscomb
2026-07-15 17:51:05 -04:00
parent e58f06d9fa
commit 7ecc718f5d
2256 changed files with 11 additions and 5 deletions
@@ -0,0 +1,34 @@
--- name: APC Key 25 mk2 - Playtime
--- realearn_version: 2.16.0-pre.8
--- author: helgoboss
--- device_manufacturer: Akai
--- device_name: APC Key 25 mk2
--- description: |
--- This main preset turns the APC Key 25 mk2 into a capable device for controlling Playtime. Hold Shift
--- to access advanced functions.
--- used_schemes: [akai/apc-key-25-mk2]
--- required_features: [playtime]
--!strict
local commons = require("akai/apc-lib/playtime-commons")
return commons.create_compartment {
use_column_stop_buttons = true,
stop_column_if_slot_empty = true,
mute_track_button_id = "row3/play",
arm_track_button_id = "row4/play",
column_count = 8,
row_count = 5,
up_button_id = "col1/stop",
down_button_id = "col2/stop",
left_button_id = "col3/stop",
right_button_id = "col4/stop",
volume_button_id = "col5/stop",
pan_button_id = "col6/stop",
send_button_id = "col7/stop",
device_button_id = "col8/stop",
stop_all_clips_button_id = "stop-all-clips",
stop_all_clips_need_shift = false,
}
@@ -0,0 +1,33 @@
--- name: APC Key 25 - Playtime
--- realearn_version: 2.16.0-pre.8
--- author: helgoboss
--- device_manufacturer: Akai
--- device_name: APC Key 25
--- description: |
--- This main preset turns the APC Key 25 mk1 into a capable device for controlling Playtime. Hold Shift or Sustain
--- to access advanced functions.
--- used_schemes: [akai/apc-key-25]
--- required_features: [playtime]
--!strict
local commons = require("akai/apc-lib/playtime-commons")
return commons.create_compartment {
use_column_stop_buttons = true,
stop_column_if_slot_empty = true,
mute_track_button_id = "row4/play",
arm_track_button_id = "row3/play",
column_count = 8,
row_count = 5,
up_button_id = "col1/stop",
down_button_id = "col2/stop",
left_button_id = "col3/stop",
right_button_id = "col4/stop",
volume_button_id = "col5/stop",
pan_button_id = "col6/stop",
send_button_id = "col7/stop",
device_button_id = "col8/stop",
stop_all_clips_button_id = "stop-all-clips",
stop_all_clips_need_shift = false,
}
@@ -0,0 +1,886 @@
--!strict
local util = require("util")
local realearn = require("realearn")
local playtime_util = require("playtime_util")
local module = {}
export type ApcPlaytimePresetConfig = {
mute_track_button_id: string,
arm_track_button_id: string,
use_column_stop_buttons: boolean,
stop_column_if_slot_empty: boolean,
column_count: number,
row_count: number,
up_button_id: string,
down_button_id: string,
left_button_id: string,
right_button_id: string,
volume_button_id: string,
pan_button_id: string,
send_button_id: string,
device_button_id: string,
stop_all_clips_button_id: string,
stop_all_clips_need_shift: boolean,
}
function module.create_compartment(config: ApcPlaytimePresetConfig): realearn.Compartment
-- Aliases
local partial_mapping = util.partial_mapping
local turbo = playtime_util.turbo
local scroll_vertically = playtime_util.scroll_vertically
local scroll_horizontally = playtime_util.scroll_horizontally
-- Types
type Mode = {
index: number,
label: string,
}
type ModeMap = { [string]: Mode }
type ParameterMap = { [string]: realearn.Parameter }
type GroupMap = { [string]: realearn.Group }
-- Constants
local column_mode_count = 100
local knob_mode_count = 100
-- Column modes
local column_modes: ModeMap = {
stop = {
index = 0,
label = "Stop clip",
},
solo = {
index = 1,
label = "Solo",
},
record_arm = {
index = 2,
label = "Record arm",
},
mute = {
index = 3,
label = "Mute",
},
select = {
index = 4,
label = "Track select",
},
}
local sorted_column_modes = util.sorted_by_index(column_modes)
-- Knob modes
local knob_modes: ModeMap = {
volume = {
index = 0,
label = "Volume",
},
pan = {
index = 1,
label = "Pan",
},
sends = {
index = 2,
label = "Sends",
},
device = {
index = 3,
label = "Device",
},
}
local sorted_knob_modes = util.sorted_by_index(knob_modes)
-- Parameters
local params: ParameterMap = {
shift = {
index = 0,
name = "Shift modifier",
},
column_mode = {
index = 1,
name = "Column mode",
value_count = column_mode_count,
value_labels = util.extract_labels(sorted_column_modes),
},
knob_mode = {
index = 2,
name = "Knob mode",
value_count = knob_mode_count,
value_labels = util.extract_labels(sorted_knob_modes),
},
send = {
index = 3,
name = "Send",
value_count = 2,
},
sustain = {
index = 4,
name = "Sustain modifier",
},
}
-- Domain functions
local function create_index_expression(variable_name: string, index: number): string
return `{variable_name} + {index}`
end
local function create_col_expression(col: number): string
return create_index_expression("control_unit_column_index", col)
end
local function create_row_expression(row: number): string
return create_index_expression("control_unit_row_index", row)
end
local function create_slot_selector(col: number, row: number): realearn.PlaytimeSlotDescriptor
return realearn.PlaytimeSlotDescriptor.Dynamic {
column_expression = create_col_expression(col),
row_expression = create_row_expression(row),
}
end
local function create_column_selector(col: number): realearn.PlaytimeColumnDescriptor
return realearn.PlaytimeColumnDescriptor.Dynamic {
expression = create_col_expression(col),
}
end
local function create_row_selector(row: number): realearn.PlaytimeRowDescriptor
return realearn.PlaytimeRowDescriptor.Dynamic {
expression = create_row_expression(row),
}
end
local function knob(index: number)
return partial_mapping {
source = realearn.Source.Virtual {
character = "Multi",
id = index,
},
}
end
local function button(id: string)
return partial_mapping {
source = realearn.Source.Virtual {
character = "Button",
id = id,
},
}
end
local function column_stop_button(col: number)
return button(`col{col + 1}/stop`)
end
local function row_play_button(row: number)
return button(`row{row + 1}/play`)
end
local function slot_button(col: number, row: number)
return partial_mapping {
source = realearn.Source.Virtual {
character = "Multi",
id = `col{col + 1}/row{row + 1}/pad`,
},
}
end
local function shift_pressed(on: boolean)
return partial_mapping {
activation_condition = realearn.ActivationCondition.Modifier {
modifiers = {
{
parameter = params.shift.index,
on = on,
},
{
parameter = params.sustain.index,
on = false,
},
},
},
}
end
local function sustain_pressed(on: boolean)
return partial_mapping {
activation_condition = realearn.ActivationCondition.Modifier {
modifiers = {
{
parameter = params.sustain.index,
on = on,
},
{
parameter = params.shift.index,
on = false,
},
},
},
}
end
local function shift_or_sustain_pressed()
return partial_mapping {
activation_condition = realearn.ActivationCondition.Expression {
condition = `p[{params.shift.index}] || p[{params.sustain.index}]`,
},
}
end
local function shift_and_sustain_pressed()
return partial_mapping {
activation_condition = realearn.ActivationCondition.Modifier {
modifiers = {
{
parameter = params.sustain.index,
on = true,
},
{
parameter = params.shift.index,
on = true,
},
},
},
}
end
local function fire_max(millis: number)
return partial_mapping {
glue = {
fire_mode = realearn.FireMode.Normal {
press_duration_interval = { 0, millis },
},
},
}
end
local function fire_after_timeout(millis: number)
return partial_mapping {
glue = {
fire_mode = realearn.FireMode.AfterTimeout {
timeout = millis,
},
},
}
end
local function fire_on_single_press(max_duration: number)
return partial_mapping {
glue = {
fire_mode = realearn.FireMode.OnSinglePress {
max_duration = max_duration,
},
},
}
end
local function fire_on_double_press()
return partial_mapping {
glue = {
fire_mode = realearn.FireMode.OnDoublePress(),
},
}
end
local no_mod = shift_pressed(false)
local shift = shift_pressed(true)
local sustain = sustain_pressed(true)
local shift_or_sustain = shift_or_sustain_pressed()
local short_press = fire_max(200)
local long_press = fire_after_timeout(1000)
local single_press = fire_on_single_press(200)
local double_press = fire_on_double_press()
local function clip_matrix_action(action: realearn.PlaytimeMatrixAction)
return partial_mapping {
target = realearn.Target.PlaytimeMatrixAction {
action = action,
},
}
end
local function clip_column_action(col: number, action: realearn.PlaytimeColumnAction)
return partial_mapping {
target = realearn.Target.PlaytimeColumnAction {
column = create_column_selector(col),
action = action,
},
}
end
local function clip_row_action(row: number, action: realearn.PlaytimeRowAction)
return partial_mapping {
target = realearn.Target.PlaytimeRowAction {
row = create_row_selector(row),
action = action,
},
}
end
local function clip_column_track(col: number): realearn.TrackDescriptor
return realearn.TrackDescriptor.FromClipColumn {
column = create_column_selector(col),
context = "Playback",
}
end
local function column_track_target(col: number, track_target_kind: realearn.TargetKind, exclusive: boolean?)
return partial_mapping {
target = {
kind = track_target_kind,
track = clip_column_track(col),
exclusivity = if exclusive then "WithinFolderOnOnly" else nil,
} :: any,
}
end
local function route_target(col: number, route_target_kind: realearn.TargetKind)
return partial_mapping {
target = {
kind = route_target_kind,
route = realearn.RouteDescriptor.Dynamic {
track = clip_column_track(col),
expression = `p[{params.send.index}]`,
},
} :: any,
}
end
local function clip_transport_action(col: number, row: number, action: realearn.PlaytimeSlotTransportAction)
return partial_mapping {
target = realearn.Target.PlaytimeSlotTransportAction {
slot = create_slot_selector(col, row),
action = action,
stop_column_if_slot_empty = config.stop_column_if_slot_empty,
},
}
end
local function clip_management_action(col: number, row: number, action: realearn.PlaytimeSlotManagementAction)
return partial_mapping {
target = realearn.Target.PlaytimeSlotManagementAction {
slot = create_slot_selector(col, row),
action = action,
},
}
end
local function transport_action(action: realearn.TransportAction)
return partial_mapping {
target = realearn.Target.TransportAction {
action = action,
},
}
end
local function reaper_action(command: realearn.ReaperCommand)
return partial_mapping {
target = realearn.Target.ReaperAction {
command = command,
invocation = "Trigger",
},
}
end
local function toggle()
return partial_mapping {
glue = {
absolute_mode = "ToggleButton",
},
}
end
local function pick_up()
return partial_mapping {
glue = {
takeover_mode = "PickUpTolerant",
},
}
end
local function incremental()
return partial_mapping {
glue = {
absolute_mode = "IncrementalButton",
},
}
end
local function wrap()
return partial_mapping {
glue = {
wrap = true,
},
}
end
local function control_disabled()
return partial_mapping {
control_enabled = false,
visible_in_projection = false,
}
end
local function feedback_disabled()
return partial_mapping {
feedback_enabled = false,
}
end
local function set_param(index: number)
return partial_mapping {
target = realearn.Target.CompartmentParameterValue {
parameter = realearn.CompartmentParameterDescriptor.ById {
index = index,
},
},
}
end
local function name(n: string)
return partial_mapping {
name = n,
}
end
local function group(g: realearn.Group)
return partial_mapping {
group = g.id,
}
end
local function set_mode(mode: Mode, mode_count: number, mode_param_index: number)
local target_value = mode.index / (mode_count - 1)
return partial_mapping {
name = mode.label,
glue = {
target_interval = { target_value, target_value },
out_of_range_behavior = "Min",
},
target = realearn.Target.CompartmentParameterValue {
parameter = realearn.CompartmentParameterDescriptor.ById {
index = mode_param_index,
},
},
}
end
local function set_column_mode(mode: Mode)
return set_mode(mode, column_mode_count, params.column_mode.index)
end
local function set_knob_mode(mode: Mode)
return set_mode(mode, knob_mode_count, params.knob_mode.index)
end
local function column_mode_is(column_mode: Mode)
return realearn.ActivationCondition.Bank {
parameter = params.column_mode.index,
bank_index = column_mode.index,
}
end
local function knob_mode_is(knob_mode)
return realearn.ActivationCondition.Bank {
parameter = params.knob_mode.index,
bank_index = knob_mode.index,
}
end
-- Groups
local groups: GroupMap = {
slot_modes = {
name = "Slot modes",
},
column_modes = {
name = "Column modes",
},
record_settings = {
name = "Record settings",
},
knob_modes = {
name = "Knob modes",
},
slot_feedback = {
name = "Slot feedback",
},
slot_play = {
name = "Slot play",
},
slot_clear = {
name = "Slot clear",
},
slot_quantize = {
name = "Slot quantize",
},
slot_copy_or_paste = {
name = "Slot copy or paste",
},
slot_double = {
name = "Slot double section",
},
slot_halve = {
name = "Slot halve section",
},
column_stop = {
name = "Column stop",
activation_condition = column_mode_is(column_modes.stop),
},
row_play_scene = {
name = "Row play scene",
},
row_build_scene = {
name = "Row build scene",
},
row_copy_or_paste_scene = {
name = "Row copy or paste scene",
},
row_clear_scene = {
name = "Row clear scene",
},
column_solo = {
name = "Column solo",
activation_condition = column_mode_is(column_modes.solo),
},
column_record_arm = {
name = "Column record arm",
activation_condition = column_mode_is(column_modes.record_arm),
},
column_mute = {
name = "Column mute",
activation_condition = column_mode_is(column_modes.mute),
},
column_select = {
name = "Column select",
activation_condition = column_mode_is(column_modes.select),
},
knob_volume = {
name = "Knob volume",
activation_condition = knob_mode_is(knob_modes.volume),
},
knob_pan = {
name = "Knob pan",
activation_condition = knob_mode_is(knob_modes.pan),
},
knob_sends = {
name = "Knob sends",
activation_condition = knob_mode_is(knob_modes.sends),
},
knob_device = {
name = "Knob device",
activation_condition = knob_mode_is(knob_modes.device),
},
}
util.set_keys_as_ids(groups)
-- Mappings
local mappings = {
name("Play/stop") + no_mod + button("play") + toggle() + clip_matrix_action("PlayIgnitedOrEnterSilenceMode"),
name("Shift modifier") + button("shift") + set_param(params.shift.index),
name("Sustain modifier") + button("sustain") + set_param(params.sustain.index),
name("Undo") + shift + button("play") + clip_matrix_action("Undo"),
name("Record") + no_mod + button("record") + clip_matrix_action("SmartRecord"),
name("Redo") + shift + button("record") + clip_matrix_action("Redo"),
name("Build scene") + sustain + button("record") + clip_matrix_action("BuildScene"),
name("Switch send")
+ group(groups.knob_sends)
+ feedback_disabled()
+ shift
+ button("col7/stop")
+ incremental()
+ wrap()
+ set_param(params.send.index),
name("Column stop mode")
+ group(groups.column_modes)
+ shift
+ button("row1/play")
+ set_column_mode(column_modes.stop),
name("Column solo mode")
+ group(groups.column_modes)
+ shift
+ button("row2/play")
+ set_column_mode(column_modes.solo),
name("Column arm mode")
+ group(groups.column_modes)
+ shift
+ button(config.arm_track_button_id)
+ set_column_mode(column_modes.record_arm),
name("Column mute mode")
+ group(groups.column_modes)
+ shift
+ button(config.mute_track_button_id)
+ set_column_mode(column_modes.mute),
name("Column select mode")
+ group(groups.column_modes)
+ shift
+ button("row5/play")
+ set_column_mode(column_modes.select),
}
if config.stop_all_clips_need_shift then
-- We have a device that has a "Stop all clips" button but it needs shift to be pressed
table.insert(
mappings,
name("Stop all clips") + shift + button(config.stop_all_clips_button_id) + clip_matrix_action("Stop")
)
else
-- We have a device with a dedicated "Stop all clips" button
table.insert(
mappings,
name("Stop all clips") + no_mod + button(config.stop_all_clips_button_id) + clip_matrix_action("Stop")
)
table.insert(
mappings,
name("Click") + shift + button(config.stop_all_clips_button_id) + reaper_action(40364)
)
end
if config.use_column_stop_buttons then
-- Scrolling
table.insert(
mappings,
name("Scroll up") + shift_or_sustain + button(config.up_button_id) + turbo() + scroll_vertically(-1)
)
table.insert(
mappings,
name("Scroll down") + shift_or_sustain + button(config.down_button_id) + turbo() + scroll_vertically(1)
)
table.insert(
mappings,
name("Scroll left") + shift_or_sustain + button(config.left_button_id) + turbo() + scroll_horizontally(-1)
)
table.insert(
mappings,
name("Scroll right") + shift_or_sustain + button(config.right_button_id) + turbo() + scroll_horizontally(1)
)
-- Modes
table.insert(
mappings,
name("Knob volume mode")
+ group(groups.knob_modes)
+ shift
+ button(config.volume_button_id)
+ set_knob_mode(knob_modes.volume)
)
table.insert(
mappings,
name("Knob pan mode")
+ group(groups.knob_modes)
+ shift
+ button(config.pan_button_id)
+ set_knob_mode(knob_modes.pan)
)
table.insert(
mappings,
name("Knob send mode")
+ group(groups.knob_modes)
+ shift
+ button(config.send_button_id)
+ set_knob_mode(knob_modes.sends)
)
table.insert(
mappings,
name("Knob device mode")
+ group(groups.knob_modes)
+ shift
+ button(config.device_button_id)
+ set_knob_mode(knob_modes.device)
)
end
-- For each column
for col = 0, config.column_count - 1 do
-- Column stop button functions
if config.use_column_stop_buttons then
table.insert(
mappings,
name("Stop column")
+ group(groups.column_stop)
+ no_mod
+ column_stop_button(col)
+ clip_column_action(col, "Stop")
)
table.insert(
mappings,
name("Solo track")
+ group(groups.column_solo)
+ no_mod
+ toggle()
+ column_stop_button(col)
+ column_track_target(col, "TrackSoloState")
)
table.insert(
mappings,
name("Arm track")
+ group(groups.column_record_arm)
+ no_mod
+ toggle()
+ column_stop_button(col)
+ clip_column_action(col, "ArmStateExclusive")
)
table.insert(
mappings,
name("Mute track")
+ group(groups.column_mute)
+ no_mod
+ toggle()
+ column_stop_button(col)
+ column_track_target(col, "TrackMuteState")
)
table.insert(
mappings,
name("Select track")
+ group(groups.column_select)
+ no_mod
+ toggle()
+ column_stop_button(col)
+ column_track_target(col, "TrackSelectionState", true)
)
end
-- Knob functions
table.insert(
mappings,
name("Track volume") + group(groups.knob_volume) + knob(col) + pick_up() + column_track_target(col, "TrackVolume")
)
table.insert(
mappings,
name("Track pan") + group(groups.knob_pan) + knob(col) + pick_up() + column_track_target(col, "TrackPan")
)
table.insert(
mappings,
name("Track send volume") + group(groups.knob_sends) + knob(col) + pick_up() + route_target(col, "RouteVolume")
)
end
-- For each row
for row = 0, config.row_count - 1 do
table.insert(
mappings,
name("Play scene")
+ group(groups.row_play_scene)
+ feedback_disabled()
+ no_mod
+ row_play_button(row)
+ clip_row_action(row, "PlayScene")
)
table.insert(
mappings,
name("Copy or paste")
+ group(groups.row_copy_or_paste_scene)
+ sustain
+ short_press
+ row_play_button(row)
+ clip_row_action(row, "CopyOrPasteScene")
)
table.insert(
mappings,
name("Long = Clear")
+ group(groups.row_clear_scene)
+ feedback_disabled()
+ sustain
+ long_press
+ row_play_button(row)
+ clip_row_action(row, "ClearScene")
)
end
-- For each slot
for col = 0, config.column_count - 1 do
for row = 0, config.row_count - 1 do
-- Feedback
table.insert(
mappings,
name("Slot feedback")
+ group(groups.slot_feedback)
+ control_disabled()
+ slot_button(col, row)
+ playtime_util.slot_state_text_feedback()
+ clip_transport_action(col, row, "Trigger")
)
-- Control
table.insert(
mappings,
name("Slot trigger")
+ group(groups.slot_play)
+ feedback_disabled()
+ no_mod
+ slot_button(col, row)
+ clip_transport_action(col, row, "Trigger")
)
table.insert(
mappings,
name("Copy or paste")
+ group(groups.slot_copy_or_paste)
+ feedback_disabled()
+ sustain
+ single_press
+ slot_button(col, row)
+ toggle()
+ clip_management_action(col, row, "CopyOrPasteClip")
)
table.insert(
mappings,
name("Long = Delete")
+ group(groups.slot_clear)
+ feedback_disabled()
+ sustain
+ long_press
+ slot_button(col, row)
+ clip_management_action(col, row, "ClearSlot")
)
table.insert(
mappings,
name("2x = Edit")
+ group(groups.slot_quantize)
+ feedback_disabled()
+ sustain
+ double_press
+ slot_button(col, row)
+ toggle()
+ clip_management_action(col, row, "EditClip")
)
--table.insert(mappings, name("Overdub clip") + group(groups.slot_play) + feedback_disabled() + shift + single_press + slot_button(col, row) + toggle() + clip_transport_action(col, row, "RecordStop", false))
--table.insert(mappings, name("2x = Double section") + group(groups.slot_double) + feedback_disabled() + shift + double_press + slot_button(col, row) + adjust_clip_section_length_action(col, row, 2))
--table.insert(mappings, name("1x = Halve section") + group(groups.slot_double) + feedback_disabled() + shift + single_press + slot_button(col, row) + adjust_clip_section_length_action(col, row, 0.5))
table.insert(
mappings,
name("Fill slot")
+ group(groups.slot_quantize)
+ feedback_disabled()
+ shift
+ single_press
+ slot_button(col, row)
+ clip_management_action(col, row, "FillSlotWithSelectedItem")
)
end
end
return realearn.Compartment {
parameters = util.sorted_by_index(params),
groups = util.to_array(groups),
mappings = mappings :: any,
custom_data = {
playtime = {
control_unit = {
column_count = config.column_count,
row_count = config.row_count,
},
},
},
}
end
return module
@@ -0,0 +1,34 @@
--- name: APC mini mk2 - Playtime
--- realearn_version: 2.16.0-pre.8
--- author: helgoboss
--- device_manufacturer: Akai
--- device_name: APC mini mk2
--- description: |
--- This main preset turns the APC mini mk2 into a capable device for controlling Playtime. Hold Shift
--- to access advanced functions.
--- used_schemes: [akai/apc-mini-mk2]
--- required_features: [playtime]
--!strict
local commons = require("akai/apc-lib/playtime-commons")
return commons.create_compartment {
use_column_stop_buttons = true,
stop_column_if_slot_empty = true,
mute_track_button_id = "row3/play",
arm_track_button_id = "row4/play",
column_count = 8,
row_count = 8,
up_button_id = "col5/stop",
down_button_id = "col6/stop",
left_button_id = "col7/stop",
right_button_id = "col8/stop",
volume_button_id = "col1/stop",
pan_button_id = "col2/stop",
send_button_id = "col3/stop",
device_button_id = "col4/stop",
stop_all_clips_button_id = "row8/play",
stop_all_clips_need_shift = true,
}
@@ -0,0 +1,34 @@
--- name: APC mini - Playtime
--- realearn_version: 2.16.0-pre.8
--- author: helgoboss
--- device_manufacturer: Akai
--- device_name: APC mini
--- description: |
--- This main preset turns the APC mini into a capable device for controlling Playtime. Hold Shift
--- to access advanced functions.
--- used_schemes: [akai/apc-mini]
--- required_features: [playtime]
--!strict
local commons = require("akai/apc-lib/playtime-commons")
return commons.create_compartment {
use_column_stop_buttons = true,
stop_column_if_slot_empty = true,
mute_track_button_id = "row4/play",
arm_track_button_id = "row3/play",
column_count = 8,
row_count = 8,
up_button_id = "col1/stop",
down_button_id = "col2/stop",
left_button_id = "col3/stop",
right_button_id = "col4/stop",
volume_button_id = "col5/stop",
pan_button_id = "col6/stop",
send_button_id = "col7/stop",
device_button_id = "col8/stop",
stop_all_clips_button_id = "row8/play",
stop_all_clips_need_shift = true,
}