Macro Widgets Expression Control

I’m going to ask this here in scripting because I preseme the way to do this is via a script. Here’s the idea…

I have 9 hardware controls mapped to widgets. Each of these widgets control a function in a VST, either Modulation or a VST’s Macro functinon.

I want to take a 10th widget, mapped to an expression pedal, and drive the others by a percentage to that expression pedal.

If the expression pedal is at 50%… it’s having no effect on the other 9 widgets… if it’s a 0% it’s pulling them from their current positon down by 50% linearly (or by what the widget’s curve is set to) and conversely if the pedal goes to 100%, it increases their values by 50%.

If the expresion pedal is returned to 50% position, whatever the other controls are set to with their hardware positions returns to that position.

Basically this would act the way macro controls do in VSTs where a macro might control several other controls but across different ranges. I’d be using the other 9 hardware controls to establish what the center point of those ranges were.

Grouping doesn’t allow me to do this. Seems like a simple idea I’m sure someone has done already in a script?

Here’s a visual…

I haven’t done anything like that, but it sounds like a job for scripting.

As I understand it, each of the 9 widgets can be adjusted by you in real time through hardware controls.

You want your expression pedal to control widget 10, which will act as something like a “gain” control over the other 9 widgets.

I would think the way you would have to implement that would be to have 9 other widgets (perhaps hidden widgets) actually linked to the VSTs, and your script would have to set the values of those widgets based on something like “hardware knob position * gain” where your “gain” would be based on that 10th widget as you described.

I would think you’d want to register a callback for changes to all 10 of those hardware widgets, and each time one of them changes you’d want to recalculate what the hidden widget value should be, then have the script set that.

2 Likes

Widget scaling lets you do that for individual widgets but do you know of any plugins where the actual scaling amount of each “macro” can itself be controlled from somewhere else? I’ve never seen that. I have seen this in mixers (e.g, DCAs) but that’s very different (and very limited)

@Vindes is correct - this would be a job for GP Script.

Kilohearts PhasePlant does this, you can set the scale of each paramater that is feeding the macro.

Yes and I’ve done something simliar with scalling before where widgets were linked but with different scalings. Effectively I want to change the scalings themselves with an external real time parameter.

I have PhasePlant — I know you can set the scale of each parameter, and that’s not really any different than setting the scaling curve for individual widgets in GP that are grouped together.

But you can’t set that scaling programmatically, which is what you’re wanting to do with Gig Performer. You can only set it with the mouse by dragging in the little circle.

\

right, and in theory if those little cicles were themselves exposed parameters, I would be able to widget map them and drive them with independant hardware controls and sort of get at the same idea, but they are not.

image

when I’ve grouped widgets in the past wtih different scales (often reversed scales) they are being driven by a single hardware control… and what I am thinking of uses indepenant controls to separate these values out in real time.

I’ll think on what @vindes proposed and see if I can build something wtih that methodology in mind.

I made a rackspace according to your description, but i used an additional row of knobs to work as “initial values”. So you always are able to not only get back to how it was, but also to see the initial values vizualized.
Turning an intitial-knob will set the (blue) knob accordingly, while turning a blue knob won’t affect the initial value. The blue knob will then “jump” back to the initial-controlled value when the boss-knob is moved again, so better not touch the blue ones! (Maybe it would be better to shrink those).
Turning the red “Boss-Knob” will then adjust the nine other knobs by half of their initial value up or down (if possible). Doubleclicking the knob will bring it back to 50%

The Boss-knob should be MIDI-learned to your pedeal, while the blue knobs should be parameter-learned to the plugin(s).

BossOf9

Here is the gig file:
BossOfNine.gig (242.7 KB)

This is the script:

var
sKnb : widget
tKnb1, tKnb2, tKnb3, tKnb4, tKnb5, tKnb6, tKnb7, tKnb8 ,tKnb9 : widget
iKnb1, iKnb2, iKnb3, iKnb4, iKnb5, iKnb6, iKnb7, iKnb8 ,iKnb9 : widget

kVal1, kVal2, kVal3, kVal4, kVal5, kVal6, kVal7, kVal8 ,kVal9 : double

kGroup : widget array = [tKnb1, tKnb2, tKnb3, tKnb4, tKnb5, tKnb6, tKnb7, tKnb8 ,tKnb9]
iGroup : widget array = [iKnb1, iKnb2, iKnb3, iKnb4, iKnb5, iKnb6, iKnb7, iKnb8 ,iKnb9]

kValues : double array = [kVal1, kVal2, kVal3, kVal4, kVal5, kVal6, kVal7, kVal8 ,kVal9]


//user function to (re)set all knobs to the initial-knob's values
function InitKnobs()
var
index : integer
    For index = 0; index < Size(kGroup); index = index+1 Do
        SetWidgetValue (kGroup[index],GetWidgetValue(iGroup[index]))
    end
End

//user function to set the knobs according to the "boss-knob's" position
function BossOrder(factor : double)
var
index : integer
    For index = 0; index < Size(kGroup); index = index+1 Do
        SetWidgetValue (kGroup[index],kValues[index]+(kValues[index]*factor))
    end
End


//user function to read the knobs values and store them in a variable array
function GetKvals ()
var
index : integer
    For index = 0; index < Size(kGroup); index = index+1 Do
        kValues[index] = GetWidgetValue(kGroup[index])
    end
End

Initialization
    SetWidgetValue(sKnb, 0.5) //set boss-knob to 0.5
    InitKnobs() //copy the inital-knobs values to the knobs
    GetKvals() //read & store the knobs values
End

//when itial knobs are moved, set knob values accordingly
On WidgetValueChanged (w : Widget, index: integer, iVal: double) from iKnb1, iKnb2, iKnb3, iKnb4, iKnb5, iKnb6, iKnb7, iKnb8 ,iKnb9
    SetWidgetValue (kGroup[index], iVal)
    GetKvals() //re-read the new knob values
End

//when boss-knob is moved, change the knobs values relatively
On WidgetValueChanged (kVal : double) from sKnb
    BossOrder(kVal-0.5)
End

8 Likes

I just worked on this topic last week and here is how I do it:

Master_Ratio_Fader

Master_Ratio_Fader_GP4.gig (118.8 KB)

var
  FADER_1, FADER_2,FADER_3,FADER_4,FADER_5,FADER_6,FADER_7,FADER_8, FADER_M : Widget;  
  FADER         : widget array = [FADER_1, FADER_2,FADER_3,FADER_4,FADER_5,FADER_6,FADER_7,FADER_8];
  
  FADER_LoopBlocker   : Integer array = [0, 0, 0, 0, 0, 0, 0, 0];
  FADER_M_LoopBlocker : Integer = 0;
  
  faderValue    : double array = [FADER_1.GetWidgetValue(), FADER_2.GetWidgetValue(), FADER_3.GetWidgetValue(), FADER_4.GetWidgetValue(),
                                  FADER_5.GetWidgetValue(), FADER_6.GetWidgetValue(), FADER_7.GetWidgetValue(), FADER_8.GetWidgetValue()];
                                   
function NormalizeToMax(value : double array) // change the name as it doesn't take care of zeros
Var
  i                : integer;
  idOfMax          : integer = iMax(value);
  normalizingValue : double = value[idOfMax];  
  
  If value[idOfMax] != 1.0
  Then
    If normalizingValue != 0.0
    Then
      For i=0; i<value.Size(); i=i+1 Do value[i] = value[i] / normalizingValue; End  
    Else 
      For i=0; i<value.Size(); i=i+1 Do value[i] = 1.0; End
    End
  End  
End

On WidgetValueChanged(FADER_i : Widget, i : integer, newValue : double) from FADER_1, FADER_2,FADER_3,FADER_4,FADER_5,FADER_6,FADER_7,FADER_8
Var
  volumeMax : double;  
  If FADER_LoopBlocker[i] == 0
  Then
    faderValue[i] = newValue / (FADER_M.GetWidgetValue()+0.000001); 
    
    NormalizeToMax(faderValue);    
    volumeMax = GetWidgetValue(FADER[iMax(faderValue)]);
    
    If FADER_M.GetWidgetValue() != volumeMax
    Then
      FADER_M.SetWidgetValue(volumeMax);
      FADER_M_LoopBlocker = FADER_M_LoopBlocker+1;
    End
  Else
   FADER_LoopBlocker[i] = FADER_LoopBlocker[i]-1;  
  End
End

On WidgetValueChanged (newValue : double) from FADER_M
Var
  i :integer;
 If FADER_M_LoopBlocker == 0 
 Then
  For i=0; i<faderValue.Size(); i=i+1
  Do // Test necessary to avoir incrementing the locker while hte callbac won't be called if the set value is identical
    If GetWidgetValue(FADER[i]) != faderValue[i] * newValue Then SetWidgetValue(FADER[i], faderValue[i] * newValue); FADER_LoopBlocker[i] = FADER_LoopBlocker[i]+1; End
  End
 Else
   FADER_M_LoopBlocker = FADER_M_LoopBlocker-1;
 End
End

On Variation(oldVariation : integer, newVariation : integer)
Var i : Integer=0; 
  For i=0; i<FADER.Size(); i=i+1 Do faderValue[i]=GetWidgetValue(FADER[i]); End
  NormalizeToMax(faderValue);
  FADER_M_LoopBlocker = 1;  
  FADER_M.SetWidgetValue(GetWidgetValue(FADER[iMax(faderValue)]));
End

Initialization
  NormalizeToMax(faderValue);
  FADER_M_LoopBlocker = 1;
  FADER_M.SetWidgetValue(GetWidgetValue(FADER[iMax(faderValue)]));  
End
6 Likes

Thank you @schamass and @David-san… both of these look very cool.

I think the boss-knob (great name btw) is more what I am after and I did just test it quickly, works very well.

David-san’s version is interesting in that the highest value also pushes the master fader up or down. I will try that out tonight too.

I figured this would be something someone else had tried or would be useful to others.

1 Like

I implemented it, but my original inspiration comes from @LeeHarvey who uses this kind of thing.

1 Like