Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conditional activation (or banks/shift) for Controller Mapping #231

Closed
vonglan opened this issue Mar 13, 2021 · 21 comments
Closed

Conditional activation (or banks/shift) for Controller Mapping #231

vonglan opened this issue Mar 13, 2021 · 21 comments
Labels
enhancement New feature or request high priority need more info Further information is requested realearn Related to ReaLearn

Comments

@vonglan
Copy link

vonglan commented Mar 13, 2021

As described in #205 , I would like to define a standard set of virtual parameters, to control typical analog-style synth VSTs.
I then want to control this with different controllers, for example an OB6, or an APC20 if I sit at my digital piano.

To be able to address for example a third oscillator in a minimoog VST with the OB6, I need a "shift" function. For this, I want to use the "Arp on/off" button on the OB6. If this is switched on, the VCO2 controls should go to the Oscillator 3 Virtual Parameters (and the LFO controls to LFO2 parameters).
Similarly, I want to use the APC20's 8 faders in 8 or 9 banks.

In a main mapping, this can be nicely achieved with conditional activation.
But for my use case (and if I want to keep a clean "mapping set design" to decouple controllers from VSTs), I need it in the Controller Mapping.

@helgoboss helgoboss added the enhancement New feature or request label Mar 13, 2021
@helgoboss
Copy link
Owner

helgoboss commented Mar 13, 2021

Initially I was thinking that contorller mappings should only be used for representing all control elements 1:1 - no lies, no surprises, just a pure representation of everything that is on your controller. That's why I didn't support conditional activation.

However, for your use case I can see how it makes sense - because as I understand you, your goal is not to reflect your controller 1:1 but to create a standard set of control elements. And not all of the controllers have every control element that is necessary, so you need to simulate them in some way. Do I get that right?

Let me see what I can do.

@vonglan
Copy link
Author

vonglan commented Mar 13, 2021

Yes, exactly. The "standard set" is a sort of ideal.
Usually hardware controllers will not be able to address all of these. So this requires mechanisms like
a Shift function or Bank Switching.
On the receiving end, the VSTs will also need to do some mapping, e.g. one virtual parameter "waveform selection" being mapped to three targets (sawtooth, pulse, triangle).
So it is a like having three layers, with two mapping layers in between.

@vonglan
Copy link
Author

vonglan commented Mar 14, 2021

Actually, instead of conditional activation, the new "dynamic selection" syntax would be sufficient, if it could be used here.
I only need shift. Can be implemented with
Target = Shift-Parameter * (Target_B - Target_A) + Target_A
and bank-switching
Target = Bank-Parameter * Bank_Size + Control_Index + Offset

In the Analog Synth controller set, I already arranged the parameter numbers with this Bank Layout - at least for the most common "Banks of 8".
For the simplified "6 Banks of 4" subset, a simple formula with + and * would become very complex. For that, it would be easier to have nested ? : operators available, for example like this:
Target = Bank_Parameter == 0 ? 11 : Bank_Parameter == 1 ? 23 : Bank_Parameter == 2 ? 28 : Bank_Parameter == 3 ? 36 : Bank_Parameter == 4 ? 40 : Bank_Parameter == 5 ? 45

@jackmau
Copy link

jackmau commented Mar 17, 2021

Initially I was thinking that contoller mappings should only be used for representing all control elements 1:1 - no lies, no surprises, just a pure representation of everything that is on your controller. That's why I didn't support conditional activation.

Agreed, but let's face it, our brain automatically attaches to a button a certain function, and I think there will always be buttons which we would only use as shift/parameter modifiers. I agree on the point that from a design perspective it makes more sense tieing controllers to parameters at controller mapping rather than main mapping stage, particularly when using auto load to avoid #186.

@helgoboss
Copy link
Owner

I think one challenge that would come up with this is how to decide which parameters to use.

Imaginary scenario: You make a controller preset that uses parameter 1 for some control element switching. Someone else makes a main preset that uses parameter 1 for something else. BOOM. The two will interfere with each other.

This kind of problems could be prevented by strictly following a convention, e.g. using parameters 1 - 50 for main mappings only and 51 - 100 for controller mappings.

But what if not everybody does this in the presets? Big chaos. Actually, it's a problem with using conditional activation in presets in general. Do we maybe need a "Parameter mapping" feature? So that each preset creator can rely on virtual ReaLearn parameters but the actual mapping to real ReaLearn VST instrument parameters is done by the preset consumer.

@helgoboss helgoboss added the need more info Further information is requested label Mar 19, 2021
@vonglan
Copy link
Author

vonglan commented Mar 19, 2021

(see my comment in #241 )

@vonglan
Copy link
Author

vonglan commented Mar 20, 2021

I have to admit that I am really eager to see this issue implemented, because for me it is a prerequisite to starting with #205 .

I suppose we cannot simply get rid of the numbers and replace them with names (like I suggested for the virtual sources/targets in #244 ), because this is just the standard protocol for VSTs, correct?

Then, my favorite solution would be to define standard numbers for "Shift" and "Bank" (like in the MIDI CC world, 1 is Modulation Wheel etc. but not all numbers are defined). I think "Shift" and "Bank" are universal, stable concepts.
Actually, we would need 2 sets: "Controller Shift", "Main Shift", "Controller Bank", "Main Bank".

Another solution (more like a side-effect) would be to put Controller Mappings and Main Mappings in separate ReaLearn instances - #243 .

But I could also live with the suggested convention (1-50 for main, 51-100 for controller). Couldn't this be supported or even enforced in the GUI?

@helgoboss
Copy link
Owner

I have to admit that I am really eager to see this issue implemented, because for me it is a prerequisite to starting with #205 .

Okay, I've put this on my high-prio list.

I suppose we cannot simply get rid of the numbers and replace them with names (like I suggested for the virtual sources/targets in #244 ), because this is just the standard protocol for VSTs, correct?

Unfortunately not. There are named parameters in REAPER (#241 (comment)) but they have severe limitations. Even if we would find a solution for the fact that you cannot list them, I think getting notified about changes (a prerequisite for feedback) wouldn't be working.

Then, my favorite solution would be to define standard numbers for "Shift" and "Bank" (like in the MIDI CC world, 1 is Modulation Wheel etc. but not all numbers are defined). I think "Shift" and "Bank" are universal, stable concepts.
Actually, we would need 2 sets: "Controller Shift", "Main Shift", "Controller Bank", "Main Bank".

Okay, I'll think about it.

But I could also live with the suggested convention (1-50 for main, 51-100 for controller). Couldn't this be supported or even enforced in the GUI?

You are right, it could be. Would be a possible solution.

@helgoboss
Copy link
Owner

helgoboss commented Mar 21, 2021

Then, my favorite solution would be to define standard numbers for "Shift" and "Bank" (like in the MIDI CC world, 1 is Modulation Wheel etc. but not all numbers are defined). I think "Shift" and "Bank" are universal, stable concepts.
Actually, we would need 2 sets: "Controller Shift", "Main Shift", "Controller Bank", "Main Bank".

But I could also live with the suggested convention (1-50 for main, 51-100 for controller). Couldn't this be supported or even enforced in the GUI?

I think I have a viable solution to the problem. Basically a combination of #186, #209, X and above quoted suggestions:

  1. The main compartment keeps its 100 FX parameters. They will be usable in main compartment groups/mappings only.
  2. I will introduce 100 more FX parameters (101 to 200) which will be usable in the controller compartment only.
    • Expressions/formulas refer to them using p1 to p100 - just like in the main compartment (although the actual FX parameters are actually 101 to 200).
    • In the controller compartment, exposing those parameters as FX parameters doesn't give the user much benefit. Most likely, the author of the controller preset will just use them within the controller preset itself. However, exposing them as FX parameter simplifies the developer's life a lot because the same technique can be used everywhere. And who knows, exposing them as FX parameters might sometimes even be useful (e.g. for workarounds).
  3. I will introduce a new FX selector called <This> which allows preset designers to easily address the own ReaLearn instance (Add "<This>" FX selector #186).
    • Without having to use <By ID> (which wouldn't work at all), <By name> (which breaks easily) or <By position> (which breaks even more easily).
  4. I will make ReaLearn FX parameter names (and number of discrete values) customizable via GUI (Allow to customize internal free parameters #209) and make this information be saved as part of a preset.
    • That way, users can easily see how a main preset (but also controller preset) can be parameterized and assign buttons/faders/etc. accordingly.
    • Status quo: It's already possible to customize ReaLearn FX parameters now, but only by directly modifying the JSON and only for the main compartment. Plus, it's not yet saved within presets.
  5. I will enable both groups and conditional activation for the controller compartment (of course).
  6. In addition to customizable FX parameter names, I think it makes sense indeed to provide some universable, stable default parameter names.
    • Just as a default instead of using "Parameter 1" and "Parameter 2" as defaults, not enforced!

@vonglan Please let me know what you think about that. I will start with some of the things already.

@vonglan
Copy link
Author

vonglan commented Mar 21, 2021

That sounds like a great concept! Seems all the puzzle pieces fit together nicely!

Concerning the default FX parameter names: Even though I argued that "Bank" and "Shift" for example are stable concepts and are good candidates for "fixed" parameters, I also see a danger that users might think there is some implied logic. This needs to be pointed out in the User's Guide.
I am not sure what other candidates there are. Maybe "Track Index Offset" and "Track Target Type", when you apply an 8-encoder controller to Reaper Track Volume/Pan/Send/... of arbitrary 8 consecutive tracks? (I did not use ReaLearn to control Reaper track parameters yet, so I am just guessing.)

@helgoboss
Copy link
Owner

helgoboss commented Mar 21, 2021

You are right, that's a danger. Especially because users don't read user guides (as I had to find out recently).

Maybe we should skip point 6 then and rather add a section in the user guide that says "If you care about your presets to be easily reusable by other users, please consider sticking to the following conventions: bla, bla, bla".

@vonglan
Copy link
Author

vonglan commented Mar 21, 2021

I am not yet sure about point 6.
Would there really be a scenario where it helps to have defaults/conventions?
For #205 , if everything works out, there will be a library of presets for controllers and VSTs.
Bank/Shift/Make-Relative would be just Controller-Mapping-internal parameters, not used outside of that preset. So no default or convention needed.
But "Track Index Offset" and "Track Target Type" (see the example and disclaimer above) might be something that is exposed as virtual target/source, and then evaluated in the Main Mapping.

@vonglan
Copy link
Author

vonglan commented Mar 21, 2021

Haha, I think I confused virtual sources/targets and ReaLearn FX Parameters again in the previous comment. I only thought about communication Controller Mapping --> Main Mapping via virtual targets/sources.
Thinking about it again now:

Bank/Shift/Make-Relative might after all be interesting to be set or read from ReaScript. --> Candidates for default parameters

And "Track Index Offset" - how would that be communicated from Controller Knob to Main Mapping target?
If it is exposed by a Controller Mapping as virtual target, that would not be usable in a dynamic formula in the Main Mapping, as I understand. So it would have to be a parameter. But one that is read from the other compartment!
Might be a contradiction of your point 2 above. We want to avoid accidental clashes. But there might be cases where the parameters are intended for communication between compartments.
So maybe Parameters 101-200 should be accessible in the Main Mapping, but not at the top of the list.

"Zoom factor" (#204 ) might be another candidate (set in Controller Mapping, and then used in Main Mapping formulas).

@helgoboss
Copy link
Owner

Bank/Shift/Make-Relative might after all be interesting to be set or read from ReaScript. --> Candidates for default parameters

Yes, for these things parameters would be probably the right choice because they hold state.

And "Track Index Offset" - how would that be communicated from Controller Knob to Main Mapping target?

By "FX parameter" target. See below.

If it is exposed by a Controller Mapping as virtual target, that would not be usable in a dynamic formula in the Main Mapping, as I understand. So it would have to be a parameter. But one that is read from the other compartment!

Exactly, virtual sources/targets are never usable in dynamic formulas because they don't hold state. Only ReaLearn FX parameters hold state (= have the concept of a current value).

Might be a contradiction of your point 2 above. We want to avoid accidental clashes. But there might be cases where the parameters are intended for communication between compartments.
So maybe Parameters 101-200 should be accessible in the Main Mapping, but not at the top of the list.

That wouldn't be good.

Just to avoid misunderstanding: The expressions/formulas can only access the parameters in their respective compartment (otherwise too much abuse possible). BUT each mapping (no matter in which compartment) can have a FX parameter target that changes parameters 1 - 200 of the current (or really any) ReaLearn instance. You can do this already now BTW, even via "By Name".

Therefore the way controller mappings should communicate state changes to main mappings is by changing main compartment parameters (1 - 100) as a result of button presses etc.

Hence, this isn't a use case for conditional activation in controller mappings. The use case for conditional activation in controller mappings is if you want to simulate some buttons or other control elements that don't even exist on the controller.

@vonglan
Copy link
Author

vonglan commented Mar 22, 2021

Therefore the way controller mappings should communicate state changes to main mappings is by changing main compartment parameters (1 - 100) as a result of button presses etc.

How about 50 Controller-internal, 50 Shared, and 50 Main Mapping parameters?

Hence, this isn't a use case for conditional activation in controller mappings. The use case for conditional activation in controller mappings is if you want to simulate some buttons or other control elements that don't even exist on the controller.

I don't understand this at the moment.
What is important to me: it should be possible to have a set of virtual targets as output of the Controller mapping, some of which are only accessible with a Shift or Bank function that is Controller Mapping-internal, without involvement of the Main Mapping - because the Main Mapping should be generic or targeted to the target VST (example: the OB6's Oscillator 2 Frequency + Shift Button [accidentally labelled "Arp on/off" ;-] should map to "AS/FreqOsc3"; or on a MIDI Fighter Twister, Bank 2 + Encoder 3 should map to the same virtual target).

I had some more thoughts about point 6 (default parameter names):
It will be easier to remove these later (if they turn out to be of no use or annoying) than to introduce them later, when there are many ReaLearn mappings already created with semantically clashing parameters (although of course this would not have any functional impact, as they are only defaults).
So I am for a small set of default parameter names. If you are too, maybe we can collect additional "default parameter candidates" from the other collaborators in an issue.

And another thought:

Expressions/formulas refer to them using p1 to p100 - just like in the main compartment (although the actual FX parameters are actually 101 to 200).

This could also lead to confusion. Maybe show and use them all with their real (technical) number, but in the UI only offering those that are actually meant to be accessible in that compartment.

@helgoboss
Copy link
Owner

helgoboss commented Mar 22, 2021

Therefore the way controller mappings should communicate state changes to main mappings is by changing main compartment parameters (1 - 100) as a result of button presses etc.

How about 50 Controller-internal, 50 Shared, and 50 Main Mapping parameters?

Why would you need shared parameters? I don't see any need for them. As mentioned, you can always use non-virtual targets (with REAPER "FX Parameter target") to trigger a value change of an FX parameter in the other compartment.

The only thing you can't do is accessing the value of an FX parameter of the other compartment in formulas Update and in the conditional activation parameter dropdowns. Compartments are designed in a way to be rather indepent from each other and meant to be freely combined on a mix and match basis. From this perspective, it makes sense that each compartment has its own private set of parameters. If you allow leaking of parameters from one compartment into the other one, it's like begging for interference issues.

If we really need shared parameters (for a reason that I don't know yet), then I would probably make all parameters shared parameters.

Hence, this isn't a use case for conditional activation in controller mappings. The use case for conditional activation in controller mappings is if you want to simulate some buttons or other control elements that don't even exist on the controller.

I don't understand this at the moment.
What is important to me: it should be possible to have a set of virtual targets as output of the Controller mapping, some of which are only accessible with a Shift or Bank function that is Controller Mapping-internal, without involvement of the Main Mapping - because the Main Mapping should be generic or targeted to the target VST (example: the OB6's Oscillator 2 Frequency + Shift Button [accidentally labelled "Arp on/off" ;-] should map to "AS/FreqOsc3"; or on a MIDI Fighter Twister, Bank 2 + Encoder 3 should map to the same virtual target).

Yes, this is the use case for conditional activation for controller mappings. That's what I meant.

I had some more thoughts about point 6 (default parameter names):
It will be easier to remove these later (if they turn out to be of no use or annoying) than to introduce them later, when there are many ReaLearn mappings already created with semantically clashing parameters (although of course this would not have any functional impact, as they are only defaults).
So I am for a small set of default parameter names. If you are too, maybe we can collect additional "default parameter candidates" from the other collaborators in an issue.

Yes, sounds good. What do you suggest to solve the problem that users could think there's implied logic? I guess "RTFM".

And another thought:

Expressions/formulas refer to them using p1 to p100 - just like in the main compartment (although the actual FX parameters are actually 101 to 200).

This could also lead to confusion. Maybe show and use them all with their real (technical) number, but in the UI only offering those that are actually meant to be accessible in that compartment.

I think if we want to emphasize that each compartment has its own private set of parameters that goes from 1 to 100 (which I prefer because of above explained reasons), requiring controller mapping formulas to use p101 to p200 and main mapping formulas to use p1 to p100 would be confusing and implementation detail leakage.

Yes, at the end each private parameter (controller p1 to p100 and main p1 to p100) will be mapped to 200 real VST parameters because VST parameters don't support grouping. But I could make ReaLearn include the compartment and even the p variable name in each parameter name for easier access.

@vonglan
Copy link
Author

vonglan commented Mar 22, 2021

Why would you need shared parameters? I don't see any need for them. As mentioned, you can always use non-virtual targets (with REAPER "FX Parameter target") to trigger a value change of an FX parameter in the other compartment.

The only thing you can't do is accessing the value of an FX parameter of the other compartment in formulas Update and in the conditional activation parameter dropdowns. Compartments are designed in a way to be rather indepent from each other and meant to be freely combined on a mix and match basis. From this perspective, it makes sense that each compartment has its own private set of parameters. If you allow leaking of parameters from one compartment into the other one, it's like begging for interference issues.

If we really need shared parameters (for a reason that I don't know yet), then I would probably make all parameters shared parameters.

Seems right.

So I am for a small set of default parameter names. If you are too, maybe we can collect additional "default parameter candidates" from the other collaborators in an issue.

Yes, sounds good. What do you suggest to solve the problem that users could think there's implied logic? I guess "RTFM".

No idea for that. All FX parameters that are not used might be grayed out. But that would be hard to implement (and access logic from a ReaScript would be impossible to detect), and might still not help.
It should be easy to find the names of the Default FX Parameters in the manual - then users can read there that these are just suggested defaults without logic. "Easy to find" might be hard though for frequently used words like "Bank".

And another thought:

Expressions/formulas refer to them using p1 to p100 - just like in the main compartment (although the actual FX parameters are actually 101 to 200).

This could also lead to confusion. Maybe show and use them all with their real (technical) number, but in the UI only offering those that are actually meant to be accessible in that compartment.

I think if we want to emphasize that each compartment has its own private set of parameters that goes from 1 to 100 (which I prefer because of above explained reasons), requiring controller mapping formulas to use p101 to p200 and main mapping formulas to use p1 to p100 would be confusing and implementation detail leakage.

Yes, at the end each private parameter (controller p1 to p100 and main p1 to p100) will be mapped to 200 real VST parameters because VST parameters don't support grouping. But I could make ReaLearn include the compartment and even the p variable name in each parameter name for easier access.

Yes, that would solve the problem for parameter access from Reaper (where I was worrying about confusion).

@helgoboss
Copy link
Owner

I think I will have it finished by tomorrow. Playing around with it a bit already and it feels somehow right.

BTW. #244 is already implemented. Check it out.

@helgoboss
Copy link
Owner

helgoboss commented Mar 23, 2021

@vonglan This will be in 2.8.0-pre5, available within the next hour. Would appreciate if you could make some tests of all the mentioned things. This required quite some changes/additions to work this way but I think it was worth it.

No set of default parameter names yet. This still needs some input.

@helgoboss
Copy link
Owner

Found a bug myself already. Group updates work either only in main or in controller compartment. Fixing.

@vonglan
Copy link
Author

vonglan commented Mar 23, 2021

Great work! This works very nice. Thanks!
I briefly tested
#231 Added mapping group feature to controller compartment (was previously available in main compartment only)
#231 Added conditional activation to controller compartment (was previously available in main compartment only)
#231 Added 100 more freely assignable VST parameters to ReaLearn (now we have 200 parameters in total divided into the already existing 100 main compartment parameters and 100 new controller compartment parameters)
#209 Added possibility to customize parameter names via header panel context menu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request high priority need more info Further information is requested realearn Related to ReaLearn
Projects
None yet
Development

No branches or pull requests

3 participants