yes, you can inspect mappings and vport assignments.
here’s what a mapping looks like:
p = 'rec_level' -- e.g.
map = norns.pmap.data[p]
tab.print(map)
accum false
ch 1
value 0
out_hi 128
in_hi 127
out_lo 1
dev 2
in_lo 0
cc 24
the field dev
refers to a numerical index in midi.vports
. that’s where you can inspect the device itself:
dev = midi.vports[map.dev]
the device table mostly consists of the assigned handler functions, but also the device name and an opaque handle to the low-level device data. (which isn’t useful to lua)
tab.print(dev)
connected true
start function: 0x418f18
note_on function: 0x419078
song_position function: 0x481a50
name nanoKEY Studio
program_change function: 0x418ed0
device table: 0x60d110
note_off function: 0x47fd28
key_pressure function: 0x418d28
song_select function: 0x481a68
clock function: 0x4197b8
pitchbend function: 0x418bc8
stop function: 0x4800f0
channel_pressure function: 0x418d70
continue function: 0x4594f0
send function: 0x471d50
cc function: 0x47ff10
it should be fine to do these lookups in the param handler, they shouldn’t invoke any costly functions.
mmm… looking at the use case specifically, i’m so far not able to retreive a useful value for the last incoming (unmapped) value from the map data, which is what i expected from the value
field. would like to figure that out without reversing the parameter scaling function, which has a cost. will poke at it a minute, we may have a small bug there if the value
field is supposed to be doing this.
nevermind. of course, you need to perform some kind of scaling back to a MIDI byte anway, because the whole point is that the param can change elsewhere… 1 moment
here’s a basically untested mockup of what i suppose it would look like:
-- something to know which CC channel to echo on
echo_cc_map = {
rec_level = {ch=1, cc=60},
pre_level = {ch=1, cc=61}
}
-- call this from a param action function with the param ID
echo_param = function(id, value)
local map = norns.pmap.data[id]
local dev = midi.vports[map.dev]
local cc = echo_cc_map[id]
local p = params.params[params.lookup[id]]
-- this gets a little annoying;
-- there isn't really a clean API for reversing a parameter mapping.
-- here i'm going to just assume that the param is a `control`,
-- which provides both normalization and un-normalization.
-- (supporting other types presently means manually reversing the map scaling functions,
-- which are implemented in menu/params.lua)
local norm_val = 0
if p.t == 'control' then
norm_val = p.unmap_value(value)
else
-- TODO: other param types
end
local tx = midi.to_data.cc({
ch = echo_cc_map[id].ch,
cc = echo_cc_map[id].cc,
-- or just: cc = cc,
val = util.linlin(0, 1, 0, 127, norm_val)
})
dev:send(tx)
end
ok last update sorry. i don’t have any of these controllers which support bidirectional binding. wihtout digging into documentation, just going to assume that in fact they are set up to receive on the same cc(/channel) that they send on. so in fact instead of the static mapping shown above you would use the CC number retreived from the mapping data. (shown in comment)