Skip to content

Commit

Permalink
Add cc_limit option (#19)
Browse files Browse the repository at this point in the history
* Add cc_limit option

* Add some documentation

* CR fix
  • Loading branch information
danut007ro committed May 27, 2022
1 parent 906b20c commit b6402f4
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -42,6 +42,7 @@ passthrough assigns some midi routing settings for each connected midi device in
- `Quantize midi` wraps note data to scales (quantization is set per connected midi device, so different scales can be used if desired)
- `Root` sets the root note of the current scale
- `Scale` sets the scale type (Major, Minor.. )
- `CC limit` sets the limit of midi CC messages to be sent for every channel per `25ms` timeframe. if more messages than this limit are received, then the last messages (per channel) will be sent automatically on next timeframe. this is useful when a midi controller is generating too many messages too fast (eg. moving all the faders at once on a novation launchcontrol xl). the `Pass all` option allows all CC messages to passthrough, without any kind of limiting. the `Pass none` option doesn't allow any midi CC messages to passthrough, effectively removing all of them

additionally, `Midi panic` is a toggle to stop all active notes if some notes are hanging.

Expand Down
58 changes: 54 additions & 4 deletions lib/core.lua
Expand Up @@ -7,7 +7,11 @@ pt.input_channels = {"No change"}
pt.output_channels = {"Device src."}
pt.toggles = {"no", "yes"}
pt.scales = {}
pt.cc_limits = {"Pass all", "Pass none"}
for i = 1, 10 do table.insert(pt.cc_limits, i) end
local active_notes = {}
local cc_limit_count = {}
local cc_limit_init = {}

-- TODO: this is a mess and needs refactoring
id_port_lookup = {} -- used to lookup midi port by id
Expand Down Expand Up @@ -42,6 +46,37 @@ pt.build_scale = function(root, scale, index)
pt.scales[index] = MusicUtil.generate_scale_of_length(root, scale, 128)
end

-- CC LIMIT --
local function cc_limit_send(msg, target, out_ch, cc_limit)
if cc_limit == 2 then
return
end

if cc_limit == 1 then
target:cc(msg.cc, msg.val, out_ch)

return
end

if cc_limit_count[target] == nil then
cc_limit_count[target] = 0
end

if cc_limit_count[target] < cc_limit - 2 then
target:cc(msg.cc, msg.val, out_ch)
cc_limit_count[target] = cc_limit_count[target] + 1
else
if cc_limit_init[target] == nil then
cc_limit_init[target] = {}
end
if cc_limit_init[target][out_ch] == nil then
cc_limit_init[target][out_ch] = {}
end

cc_limit_init[target][out_ch][msg.cc] = msg.val
end
end

-- MIDI DEVICE DETECTION --
for i = 1, 16 do
table.insert(pt.input_channels, i)
Expand Down Expand Up @@ -110,6 +145,8 @@ pt.setup_midi = function()
id_port_lookup = id_port_map

pt.targets = targets

metro.init(pt.handle_cc_limit, 0.025):start()
end

pt.root_note_formatter = MusicUtil.note_num_to_name
Expand Down Expand Up @@ -143,7 +180,7 @@ pt.stop_all_notes = function()
end

-- DATA HANDLERS --
pt.handle_midi_data = function(msg, target, out_ch, quantize_midi, current_scale)
pt.handle_midi_data = function(msg, target, out_ch, quantize_midi, current_scale, cc_limit)
local note = msg.note

if note ~= nil then
Expand All @@ -167,7 +204,7 @@ pt.handle_midi_data = function(msg, target, out_ch, quantize_midi, current_scale
elseif msg.type == "program_change" then
target:program_change(msg.val, out_ch)
elseif msg.type == "cc" then
target:cc(msg.cc, msg.val, out_ch)
cc_limit_send(msg, target, out_ch, cc_limit)
end
end

Expand All @@ -183,7 +220,20 @@ pt.handle_clock_data = function(msg, target)
end
end

pt.device_event = function(origin, device_target, input_channel, output_channel, send_clock, quantize_midi, current_scale, data)
pt.handle_cc_limit = function()
for target, v in pairs(cc_limit_init) do
for out_ch, ccs in pairs(v) do
for cc, value in pairs(ccs) do
target:cc(cc, value, out_ch)
end
end
end

cc_limit_count = {}
cc_limit_init = {}
end

pt.device_event = function(origin, device_target, input_channel, output_channel, send_clock, quantize_midi, current_scale, cc_limit, data)
if #data == 0 then
print("no data")
return
Expand All @@ -202,7 +252,7 @@ pt.device_event = function(origin, device_target, input_channel, output_channel,
local scale = pt.scales[origin]

for k, v in pairs(connections) do
pt.handle_midi_data(msg, v, out_ch, quantize_midi, scale)
pt.handle_midi_data(msg, v, out_ch, quantize_midi, scale, cc_limit)
end
end

Expand Down
21 changes: 17 additions & 4 deletions lib/mod.lua
Expand Up @@ -49,7 +49,8 @@ function write_state()
io.write("send_clock="..v.send_clock..",")
io.write("quantize_midi="..v.quantize_midi..",")
io.write("current_scale="..v.current_scale..",")
io.write("root_note="..v.root_note.."}")
io.write("root_note="..v.root_note..",")
io.write("cc_limit="..v.cc_limit.."}")
end
io.write("}\n")
io.close(f)
Expand All @@ -63,6 +64,10 @@ function read_state()
end

for i = 1, tab.count(state) do
if state[i].cc_limit == nil then
state[i].cc_limit = 1
end

core.build_scale(state[i].root_note, state[i].current_scale, state[i].dev_port)
end
end
Expand Down Expand Up @@ -116,7 +121,8 @@ function create_config()
send_clock = 1,
quantize_midi = 1,
current_scale = 1,
root_note = 0
root_note = 0,
cc_limit = 1
}
else
state[v.port].dev_port = v.port
Expand Down Expand Up @@ -195,7 +201,13 @@ function create_config()
action = function()
core.build_scale(state[k].root_note, state[k].current_scale, k)
end
}
},
cc_limit = {
param_type = "option",
id = "cc_limit",
name = "CC limit",
options = core.cc_limits
}
}

config[k].target.action(state[k].target)
Expand All @@ -220,6 +232,7 @@ function device_event(id, data)
port_config.send_clock,
port_config.quantize_midi,
port_config.current_scale,
port_config.cc_limit,
data)

api.user_event(id, data)
Expand Down Expand Up @@ -277,7 +290,7 @@ local get_menu_pagination_table = function()
end

-- MOD MENU --
local screen_order = {"active", "target", "input_channel", "output_channel", "send_clock", "quantize_midi", "root_note", "current_scale", "midi_panic"}
local screen_order = {"active", "target", "input_channel", "output_channel", "send_clock", "quantize_midi", "root_note", "current_scale", "cc_limit", "midi_panic"}
local m = {
list=screen_order,
pos=0,
Expand Down
10 changes: 8 additions & 2 deletions lib/passthrough.lua
Expand Up @@ -29,6 +29,7 @@ local function device_event(id, data)
params:get("send_clock_"..port)==2,
params:get("quantize_midi_"..port),
params:get("current_scale_"..port),
params:get("cc_limit_"..port),
data)

Passthrough.user_event(id, data)
Expand All @@ -48,7 +49,7 @@ function Passthrough.init()
if core.has_devices == true then

port_amount = tab.count(core.ports)
params:add_group("PASSTHROUGH", 9*port_amount + 2)
params:add_group("PASSTHROUGH", 10*port_amount + 2)

for k, v in pairs(core.ports) do
params:add_separator(v.port .. ': ' .. v.name)
Expand Down Expand Up @@ -134,7 +135,12 @@ function Passthrough.init()
core.build_scale(params:get("root_note_"..v.port), params:get("current_scale_"..v.port), v.port)
end
}

params:add {
type = "option",
id = "cc_limit_"..v.port,
name = "CC limit",
options = core.cc_limits
}
end
params:add_separator("All devices")
params:add {
Expand Down

0 comments on commit b6402f4

Please sign in to comment.