Open helgoboss opened 3 years ago
sounds similar to the "zoom factor" request #204
@vonglan It's something else.
This would need a new kind of target control value in addition to Absolute (%) and Relative (+/- n): Absolute (n)
This should be a new absolute mode "Discrete" or "No scale". It takes absolute discrete control values and passes them on to the target without scaling/squeezing. When adding #315 to the mix, we would then have a quite symmetrical looking set of control value kinds:
Pseudo code:
enum ControlValue {
/// Already existing: Absolute value that represents a percentage (e.g. fader position on the scale from lowest to
/// highest, knob position on the scale from closed to fully opened, key press on the scale from not pressed to
/// pressed with full velocity, key release).
AbsoluteContinuous(UnitValue),
/// New for #184: Absolute value that is capable of retaining the original discrete value, e.g. the played note
/// number, without immediately converting it into a UnitValue and thereby losing that information - which is
/// important for the new "Discrete" mode.
AbsoluteDiscrete(DiscreteValue),
/// New for #315: Relative increment that is very specific in that it already expresses a certain step size.
RelativeContinuous(UnitIncrement),
/// Already existing: Relative increment (e.g. encoder movement)
RelativeDiscrete(DiscreteIncrement),
}
/// Already existing: Represents a percentage in the form of a value of the unit interval (0.0 to 1.0).
struct UnitValue {
// ...
}
/// Already existing: Represents an increment within the positive or negative unit interval (-1.0 to 1.0).
struct UnitIncrement {
// ...
}
struct DiscreteValue{
/// Concrete discrete value.
actual: u32,
/// Maximum value: Good to know in order to be able to instantly convert to a UnitValue whenever we
/// want to go absolute-continuous.
max: u32
}
/// Already existing: Represents a discrete increment, either positive or negative. Example: +5
struct DiscreteIncrement {
// ...
}
On second thought:
On third thought:
Regarding scaling: the scaling based on (source_min ... source_max) and (target_min ... target_max) is logically only possible for absolute sources. But for relative sources, a simple zoom factor (#204 ) would be possible and useful IMHO.
I must say that I do not yet understand the difference between discrete and continuous sources, because technically, I am sure all sources are discrete, as they are digital. To me it seems it is just a ReaLearn convention that for "discrete" sources the smallest increment is encoded as 0.01 or 1%, and then a discrete target can translate that back to "smallest increment" with regard to the target. So I think the difference between the two is just that the discrete increment says to the target "by the way, my smallest delta is xxx, in case you want to use that information".
Could a normal 7-bit potentiometer also be represented as discrete, with the smallest Increment then being 1/127?
Regarding scaling: the scaling based on (source_min ... source_max) and (target_min ... target_max) is logically only possible for absolute sources. But for relative sources, a simple zoom factor (#204 ) would be possible and useful IMHO.
I know, I know, I get the message ;)
I must say that I do not yet understand the difference between discrete and continuous sources, because technically, I am sure all sources are discrete, as they are digital.
Yes, it's all binary in computers but it still makes sense to distinguish between numbers that are countable/discrete (integers) and numbers that are (or at least are perceived as) continuous (floating point numbers). When I say "discrete control value", I mean integers. MIDI only has integers, it doesn't have floating point numbers. In many cases this is just a protocol limitation, e.g. I guess 14-bit CCs are just the MIDI way of controlling something continuous, whereas floating point numbers would be suited better for this purpose.
But there are cases in which the integers in MIDI make much sense, e.g. keys on a piano! There are no other keys between C4 an C#4 ... that means the set of keys is discrete. Up until now, what ReaLearn does is taking the incoming discrete value, e.g. 63 (of 128 possible values) and immediately converts it to the normalized floating point value 0.49606299... by doing 63 / 127
. Because it's easy to process normalized values. It also applies scaling from source min/max to target min/max and thereby squeezing or stretching the value range. That's all great and desired - as long as you have a continuous target, such as volume or pan. But as soon as you have a discrete target - such as "Project: Navigate within tracks" (the set of tracks is discrete) - scaling is usually not desired. If you press key 5 on the MIDI keyboard, you probably want to navigate to track 5 in REAPER ... but this is exactly the scenario which is hard to achieve now, especially because the number of tracks can change.
To me it seems it is just a ReaLearn convention that for "discrete" sources the smallest increment is encoded as 0.01 or 1%, and then a discrete target can translate that back to "smallest increment" with regard to the target. So I think the difference between the two is just that the discrete increment says to the target "by the way, my smallest delta is xxx, in case you want to use that information".
For relative control this doesn't apply. This ticket is about improvement of absolute control via discrete sources only.
Could a normal 7-bit potentiometer also be represented as discrete, with the smallest Increment then being 1/127?
It's the goal of this ticket to improve ReaLearn's processing chain so that the 1 stays a 1 from start (incoming source message) till end (a possibly discrete target). Without any scaling/squeezing/streching) applied on the way (huge difference) and without converting things to floating point numbers (which excludes possible numerical rounding errors happening on the way).
- In which stages do we need to decide whether to use scaling or not? Identify them and decide if it's more feasible to let the target decide about "discrete vs. continuous" or the tuning section.
These are the current operations. The scaling operations among them should be replaced with non-scaling operations (addition/clamping) in discrete mode:
I guess the problem mentioned in point 1 and the fact that it's not just about "retaining" the discreteness of a value but also about applying completely different operations (addition/clamping instead of multiplication) indicates that this should be a property of the tuning section rather than a property of the target.
In any case, it's important that we make already existing controller presets retain incoming discrete values! Without breaking existing behavior of course.
Therefore I think the way to go is this:
Consequences:
My two cents:
Destructive operations in mode "Discrete":
- Control transformation (only if filled with a valid formula)
I think it would be simpler for the user, if the transformation field would always be inactive and hidden for "discrete". If anyone wants to use the formula, then they can't use "discrete".
I changed my mind about that in the meantime:
Then it should be simple: Discrete means discrete all the way (as long as both source and target are discrete).
Sounds good.
Note to self, if I unlock this feature at some point: "Scaled absolute control" vs. "Direct absolute control" is a better distinction. It shouldn't be about continuous and discrete.
Scaled Absolute Control: Source and target values are proportionally scaled to each other, with the target's value range mapped to the source’s percentage.
Direct Absolute Control: Source value directly represents the target value without scaling, with each source value corresponding to a discrete target point.
At the moment, discrete targets with a variable about of discrete values (such as "Selected track" and "FX parameter") are most useful with relative encoders or prev/next buttons. With (absolute) faders and knobs they are only useful for birds-eye view navigation, not for precise control. Because the target range is not constant, precise control is impossible and every change in the number of discrete values (e.g. tracks) will let things fall apart.
We could offer an option to make the number of discrete values irrelevant and set a fixed number of relevant values instead.
Another similar thing: "Seek" target currently always relates to the complete time range in question. Great for many use cases. But if you want the seek increment/decrement for to be the same no matter the size of the time range, you need another solution. Either an action, but that would need #129. Or a new feature, maybe related to the "rounding" step size.