With resolution i meant what the Twister send when it does eg half a turn and how smooth that refelcts on the controlled parameter. I might be wrong in the feeling but i never liked it when i adjusted the the delta range on my encoders and they jumped eg 4 points per resolution. In an ideal world i would like my encoders to behave like potis and the twister ones come near to that i feel IF you can keep them at high resolution/low delta values.
To emulate an inbuilt "per parameter" scale value or variable min max values i add these manually into the map file at least for the few stepped parameters where it is needed. There are two ways to do this.
- mode value
- custom text mapping object that you automatically parse for the values in the codec.
It IS work though. But since it only happens in the map file it can be done whenever you have to edit it anyways eg because you add a new device.
You COULD also use the push function of the Twister to increase or reduce the scaling btw.
Edit: This might be a brainfart or a non starter. But normal controls have a local min max value defind in remote init. This value then gets scaled to the hosts actual item min max values - thats why with normal potis you can easily turn the knob through stepped values since they are correctly scaled. Now in the remote docs deltas are defined without a min max value but maybe you can add them and then you could scale this up by eg factor 10 (0-1270) plus a scale value of 10 and then you could dial down the scale value to your needs. I am pretty sure its not going to work like that but maybe it does.
Remote: Relative Knobs On Stepped Parameters
-
- Posts: 67
- Joined: 05 Jun 2024
I see. The script however does the opposite. Its default scale variable (which can be simply set to "1" to neutralize it) doesn't make the control jump 4 points per delta but 0.1 point per delta. This slowdown was necessary because the tiniest movement with a not so slow movement speed would result in drastic knob movements. So the scale value actually gives some physical space to the knob.electrofux wrote: ↑09 Apr 2025With resolution i meant what the Twister send when it does eg half a turn and how smooth that refelcts on the controlled parameter. I might be wrong in the feeling but i never liked it when i adjusted the the delta range on my encoders and they jumped eg 4 points per resolution. In an ideal world i would like my encoders to behave like potis and the twister ones come near to that i feel IF you can keep them at high resolution/low delta values.
But I think you have a point though. When applying that scale, you'll have the Twister's lowest value 1/-1 become a fraction and that fraction is not a meaningful step for Reason's devices. So there is a chain of slow delta values that are only relevant within the script and disregarded by Reason until they reach a new integer value. I've made some adjustments to the script so that the scale value is now an exponent. This allows to keep the lowest value at 1/-1 but tweak the higher values when rotating faster to the take value range declared towards Reason:
Code: Select all
-- MIDI Fighter Twister Remote Codec
-- with custom implementation for relative knobs
-- const variables --
--_________________--
-- the amount of knobs
KNOBS_COUNT = 64
-- the amount of knobs that are also a button
KNOB_BUTTONS_COUNT = 64
KNOB_BUTTONS_NOTE_START = 16
-- the minimum value of a knob
KNOB_MIN = 0
-- the maximum value of a knob
KNOB_MAX = 127
-- how much a single delta value is scaled (basically a speed parameter)
KNOB_SCALE = 1.5 * (math.log(KNOB_MAX + 1) / math.log(128)) - 1
-- in delta mode, the center/neutral value (which we never receive because it's a rotation of nothing/zero)
KNOB_DELTA_BASE = 64
-- data structures --
--_________________--
-- current parameter value from Reason (Rack devices, Mixer, ...)
reason_param_values = {}
-- previously processed parameter value from Reason (Rack devices, Mixer, ...)
reason_param_values_previous = {}
-- the accumulated delta of a physical control knob/encoder on top of its assigned reason_param_value
controller_accumulated_deltas = {}
-- Reason Remote Codec implementations --
-- ____________________________________--
function remote_init(manufacturer, model)
local items = {}
local inputs = {}
local outputs = {}
for cc = 0, KNOBS_COUNT - 1 do
local name = string.format("CC %02d", cc)
table.insert(items, {name = name, input = "value", output = "value", min = KNOB_MIN, max = KNOB_MAX})
table.insert(inputs, {pattern = string.format("b0 %02x xx", cc), name = name})
reason_param_values[cc + 1] = -1
controller_accumulated_deltas[cc + 1] = 0
end
for push_encoder_index = 0, KNOB_BUTTONS_COUNT - 1 do
local name = string.format("Push Encoder %02d", push_encoder_index)
table.insert(items, { name = name, input = "button" })
table.insert(inputs, { pattern = string.format("91 %02x ?<???x>", push_encoder_index + KNOB_BUTTONS_NOTE_START), name = name })
end
table.insert(items, { name = "Left Button 1", input = "button" })
table.insert(inputs, { pattern = string.format("93 08 ?<???x>"), name = "Left Button 1" })
table.insert(items, { name = "Left Button 2", input = "button" })
table.insert(inputs, { pattern = string.format("93 09 ?<???x>"), name = "Left Button 2" })
table.insert(items, { name = "Left Button 3", input = "button" })
table.insert(inputs, { pattern = string.format("93 0a ?<???x>"), name = "Left Button 3" })
table.insert(items, { name = "Right Button 1", input = "button" })
table.insert(inputs, { pattern = string.format("93 0b ?<???x>"), name = "Right Button 1" })
table.insert(items, { name = "Right Button 2", input = "button" })
table.insert(inputs, { pattern = string.format("93 0c ?<???x>"), name = "Right Button 2" })
table.insert(items, { name = "Right Button 3", input = "button" })
table.insert(inputs, { pattern = string.format("93 0d ?<???x>"), name = "Right Button 3" })
remote.define_items(items)
remote.define_auto_inputs(inputs)
remote.define_auto_outputs(outputs)
end
function remote_probe()
return {
}
end
function remote_prepare_for_use()
local retEvents={
}
return retEvents
end
function remote_release_from_use()
local retEvents={
}
return retEvents
end
function remote_process_midi(event)
for cc = 0, KNOBS_COUNT - 1 do
local match = remote.match_midi(string.format("b0 %02x xx", cc), event)
if match then
local index = cc + 1
local current_value= remote.get_item_value(index)
local current_delta = match.x - KNOB_DELTA_BASE
local sign = current_delta < 0 and -1 or 1
current_delta = sign * math.abs(current_delta)^KNOB_SCALE
local new_value = controller_accumulated_deltas[index] + current_delta + current_value
new_value = math.max(KNOB_MIN, math.min(KNOB_MAX, new_value))
controller_accumulated_deltas[index] = new_value - current_value
remote.handle_input({
time_stamp = event.time_stamp,
item = index,
value = new_value
})
return true
end
end
return false
end
function remote_set_state(changed_items)
for _, index in ipairs(changed_items) do
reason_param_values[index] = remote.get_item_value(index)
end
end
function remote_deliver_midi()
local events = {}
for index = 1, KNOBS_COUNT do
local new_value = reason_param_values[index]
local old_value = reason_param_values_previous[index]
if new_value == old_value then
-- nothing to do yet, but apply range limit to delta
local current_delta = controller_accumulated_deltas[index]
if (new_value + current_delta < KNOB_MIN) or (new_value + current_delta > KNOB_MAX) then
controller_accumulated_deltas[index] = 0
end
else
controller_accumulated_deltas[index] = 0
local midi = remote.make_midi(string.format("b0 %02x %02x", index - 1, new_value/KNOB_MAX * 127))
table.insert(events, midi)
reason_param_values_previous[index] = new_value
end
end
return events
end
The first is for KNOB_MAX=127, the second is for KNOB_MAX=16383. The third one is blending between the previous two and is the one actually used for KNOB_SCALE.
There were also some magic numbers still not replaced by variables which caused stepped parameters to behave wrong when using a different value than 127 for KNOB_MAX.
Here I'm comparing the step size of the MF Twister in the script's 14 bit relative mode against the fine and coarse mouse step size: And here's the same physical knob movement applied to a frequency (float) parameter and a mode (stepped) parameter:
Interesting! What is that custom text mapping object? Do you mean the remotable item's value string?electrofux wrote: ↑09 Apr 2025To emulate an inbuilt "per parameter" scale value or variable min max values i add these manually into the map file at least for the few stepped parameters where it is needed. There are two ways to do this.
- mode value
- custom text mapping object that you automatically parse for the values in the codec.
It IS work though. But since it only happens in the map file it can be done whenever you have to edit it anyways eg because you add a new device.
Do you know how to access the scale value of an item from the map? There's no remote.get_item_scale() so I wonder if that's only used for delta auto inputs?
That's what I tried initially before creating this thread. Sadly, that doesn't work. The min/max values just get ignored for the a delta input. This is what led me to create the lua codec that acts towards Reason as if the controls were all in absolute mode but communicates with the MF Twister in relative mode.electrofux wrote: ↑09 Apr 2025Edit: This might be a brainfart or a non starter. But normal controls have a local min max value defind in remote init. This value then gets scaled to the hosts actual item min max values - thats why with normal potis you can easily turn the knob through stepped values since they are correctly scaled. Now in the remote docs deltas are defined without a min max value but maybe you can add them and then you could scale this up by eg factor 10 (0-1270) plus a scale value of 10 and then you could dial down the scale value to your needs. I am pretty sure its not going to work like that but maybe it does.
You do not have the required permissions to view the files attached to this post.
-
- Posts: 924
- Joined: 21 Jan 2015
to get values over from the map to the codec you add a map item eg:
map newmapitem "string"
and then you get the value with remote.get_item_value. You can add delimiters and explode the string to have more values encoded in it.
OR you add a mode value in the map and do the same but with remote.get_item_mode.
Getting the scale value seems not to be possible. It looks like it is applied to anything that is delta automatically.
map newmapitem "string"
and then you get the value with remote.get_item_value. You can add delimiters and explode the string to have more values encoded in it.
OR you add a mode value in the map and do the same but with remote.get_item_mode.
Getting the scale value seems not to be possible. It looks like it is applied to anything that is delta automatically.
-
- Posts: 67
- Joined: 05 Jun 2024
I'm neither finding this in the Remote Codec SDK manual nor am I able to get Reason to accept this. Here's what I do in my map file:electrofux wrote: ↑11 Apr 2025to get values over from the map to the codec you add a map item eg:
map newmapitem "string"
Code: Select all
Scope Propellerhead Software se.propellerheads.Europa
Map CC 00 Osc1 Filter Freq
// Adding the line below causes Reason to reject the map/codec
Map newmapitem "test"
Failed to load control surface: DJ TechTools, MIDI Fighter Twister (Relative Custom).
Map File Errors:
Line 645: Undefined command.
Really strange, because according to the Reason Remote SDK manual, this call will retrieve the value from the currently controlled device's parameter (e.g. a knob like Filter Cutoff on a Reason Rack device synth). The value returned is usually a number - but you imply when this is a custom text mapping, this function will return a string instead?electrofux wrote: ↑11 Apr 2025and then you get the value with remote.get_item_value. You can add delimiters and explode the string to have more values encoded in it.
Yes, that's also my observation.electrofux wrote: ↑11 Apr 2025Getting the scale value seems not to be possible. It looks like it is applied to anything that is delta automatically.
The advantage of the current state of my script is that all those ranges are scaled automatically by Reason due to having all controls declared as absolute. But with the MFT actually being used in relative mode and the relative message processing being done in the lua script, you can set its range as high as you like and it'll automatically scale the accelerated values to a range that feels right while you'll still be able to make single step increments when turning the encoders slowly. This is applied to all parameters so you don't need to manually set scale values for e.g. stepped parameters.
-
- Information
-
Who is online
Users browsing this forum: CommonCrawl [Bot] and 4 guests