|
05-30-2017, 12:00 PM
|
#1
|
Human being with feelings
Join Date: Dec 2015
Posts: 39
|
Assign the same Parameter to 2 or more GUI elements
Hi,
could you help me please?
Is it possible in WDL-OL to assign the same plugin Parameter (for example "kVolume") to 2 or 3 or more different IControl GUI elements (each of them using different bitmaps for example) ? Everything preserving overall stability obviously...
Tank you in advance!
|
|
|
05-30-2017, 11:26 PM
|
#2
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,646
|
Quote:
Originally Posted by br_ck1
Is it possible in WDL-OL to assign the same plugin Parameter (for example "kVolume") to 2 or 3 or more different IControl GUI elements (each of them using different bitmaps for example) ? Everything preserving overall stability obviously...
|
Yeah, sure. And in general they will all update when you automate the parameter. However, you might have to sync the IControls when changing one of the IControls in the GUI.
|
|
|
05-31-2017, 09:54 AM
|
#3
|
Human being with feelings
Join Date: Dec 2015
Posts: 39
|
Quote:
Originally Posted by Tale
Yeah, sure. And in general they will all update when you automate the parameter. However, you might have to sync the IControls when changing one of the IControls in the GUI.
|
Thank you Tale,
For "sync the IControls" you mean inside "OnParamChange()" update the gui for all icontrols right? Or there's a different way ?
|
|
|
05-31-2017, 11:11 PM
|
#4
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,646
|
Quote:
Originally Posted by br_ck1
For "sync the IControls" you mean inside "OnParamChange()" update the gui for all icontrols right? Or there's a different way ?
|
Another way could be to set a pointer to the other IControl, and then in SetDirty() call the other IControl's SetValueFromPlug().
|
|
|
06-01-2017, 01:41 PM
|
#5
|
Human being with feelings
Join Date: Dec 2015
Posts: 39
|
Thank you so much Tale,
|
|
|
06-01-2017, 09:57 PM
|
#6
|
Human being with feelings
Join Date: Dec 2015
Posts: 331
|
Quote:
Originally Posted by Tale
However, you might have to sync the IControls when changing one of the IControls in the GUI.
|
In general, no—right? Because: you turn the control, it updates the param, the param updates any controls attached to it (the one you're changing manually doesn't re-send to the param, because it has logic that checks for no change in the control).
I have a plugin that is time based; you can set time with a knob, with a numeric text field, and from a tempo field and associated controls (triplet, etc.). I don't do anything special to make the text field follow the knob, for instance.
|
|
|
06-02-2017, 04:09 AM
|
#7
|
Human being with feelings
Join Date: Apr 2012
Posts: 279
|
Quote:
Originally Posted by earlevel
In general, no—right? Because: you turn the control, it updates the param, the param updates any controls attached to it (the one you're changing manually doesn't re-send to the param, because it has logic that checks for no change in the control).
|
I don't think that you're right here. A GUI changed param doesn't send values back to other controls without any further instructions. At least i couldn't find anything like that. I guess txt fields include anything like SetValuefromPlug (i didn't check)? But simply defining the same paramIdx to different controls doesn't sync the GUI.
|
|
|
06-02-2017, 10:57 AM
|
#8
|
Human being with feelings
Join Date: Jan 2017
Posts: 43
|
I ran into this problem also, trying to have multiple controls manage the same parameter. The first way I handled it was:
In the custom control, call mPlug -> SetParameterFromGUI(paramID, normalizedValue) to update the parameter (this then calls OnParamChange in the main .cpp).
Then in OnParamChange also pass a changed parameter value to any controls that use it, for example:
Code:
case (kThreshold):{
double thresh = GetParam(kThreshold) -> Value();
peakMeter -> SetThreshold(thresh);
}
The problem with this is that if you have a control that updates the parameter many times in short succession (a slider, for instance), it makes a small change and updates the parameter, which calls OnParamChange and sends the changed value back to the control that made the change, which has by then made a larger change to the parameter that will get reset. This caused some funky behavior.
My solution was to only allow the control to accept new parameter values when it wasn't actively changing that parameter:
Code:
void SetThreshold(double t){
if (!clicking){
// If the user isn't interacting with the control, update the parameter
threshold = t;
pcThreshold = (36.0 + t) / 36.0;
}
}
This worked pretty well, but it isn't the greatest solution. For instance, if you have a parameter attached to a knob, you have to explicitly set the knob value from within the control, since OnParamChange doesn't update the knobs (understandably so, since it'll usually be a knob calling OnParamChange, as I understand it). So I also had to pass knobs around to every control that needed to handle parameters internally, which got a little nasty to keep track of (but worked).
My new solution (after learning more/better C++) is using a structure that holds all of the relevant information about a parameter. The pointer to this structure can then be sent to any control that needs it, and it handles all the parameter/knob updating stuff.
Here it is:
Code:
struct SmartParam{
IPlugBase* mPlug;
int paramID;
IKnobMultiControl* paramKnob;
double currentValue, normalizedValue, maxValue, minValue;
SmartParam(){}
SmartParam(IPlugBase* pPlug, int ID, IKnobMultiControl* knob, double cVal, double maxVal, double minVal) : mPlug(pPlug), paramID(ID), paramKnob(knob), currentValue(cVal), maxValue(maxVal), minValue(minVal){ normalizedValue = (maxVal - cVal) / (maxVal - minVal); }
void SetValue(double val){
currentValue = val;
normalizedValue = (val - minValue) / (maxValue - minValue);
mPlug -> SetParameterFromGUI(paramID, normalizedValue);
paramKnob -> SetValueFromPlug(normalizedValue);
}
};
I haven't completely integrated this into my project yet, but it seems to work pretty well so far. Let me know if you want to use it (you're more than welcome to do so) and have any questions regarding its implementation.
Hope some of this helps!
MSK
|
|
|
06-02-2017, 02:42 PM
|
#9
|
Human being with feelings
Join Date: Dec 2015
Posts: 331
|
Quote:
Originally Posted by stw
I don't think that you're right here. A GUI changed param doesn't send values back to other controls without any further instructions.
|
Sorry, left out important details. IGraphics::SetParameterFromPlug is how a parameter is set from the plugin. It sets the values of all controls associated with the parameter. That's what I'm referring to. If the controls change, they are marked dirty and redrawn.
The graphics Draw routine is called regularly, and checks for dirty controls, accumulates an update rectangle, then redraws everything that's in or overlaps the rectangle. You could have a group of controls sitting on top of a big dummy control if you want—setting the dummy dirty will force the others to redraw.
Also, for cases in which you may do the setting of a parameter OnParamChange, or similar, call IGraphics::SetParameterFromGUI. For instance, I have tempo controls that calculate a delay time. When the tempo changes, it changes a tempo parameter for the benefit of the host, then in the OnParamChange handler for the tempo parameter, I calculate a new time parameter, and set it with SetParameterFromGUI. Besides setting the parameter, it updates all controls that are attached to the parameter.
PS—I forgot how horribly named these routines are. SetParameterFromPlug, for instance, doesn't set a parameter. It sets controls associated with a parameter to match the value you supply. The parameter isn't sent—it just updates the controls and redraws them if visible. SetParameterFromGUI exists in the plugin and graphics objects, and it very different.
Last edited by earlevel; 06-02-2017 at 08:10 PM.
Reason: Add details about SetParameterFromGUI
|
|
|
06-03-2017, 04:24 AM
|
#10
|
Human being with feelings
Join Date: Apr 2012
Posts: 279
|
Quote:
Originally Posted by earlevel
Sorry, left out important details...
|
Yes you're right, naming of these functions can be confusing. Since i stumbled over this very often when i started with IPlug and i guess almost every other beginner will too, i knocked up a short comparison and explanations on corresponding functions. Feel free to comment, expand or correct any mistakes!
Quote:
class IControl:: // called by: ControlPointer->function()
SetValueFromPlug(double value):
Sets the mValue for a (GUI-)IControl. The value is only held by the control and not pushed to the host. Calls SetDirty(false) => The IControl will be redrawn, but value won’t be pushed to the host.
Additionally mDefaultValue is set to value if < 0 (purpose?).
SetValueFromUserInput(double value):
Same as SetValueFromPlug() but calls SetDirty(true) => value will be pushed to the host.
SetDirty(bool pushParamToPlug // true on default):
Sets mDirty = true => The IControl will be redrawn with its actual mValue. mValue is set either by GUI actions, SetValueFromPlug(), or automation.
If pushParamToPlug == true, mPlug->SetParameterFromGUI(mParamIdx, mValue) [don’t mix up with IGraphics::SetParameterFromGUI(int paramIdx, double normalizedValue)] is called => mValue will be pushed to the IControls associated IParam and OnParamChange() is called afterwards.
SetClean():
Sets mDirty = mRedraw. mRedraw is set to true if called by ControlPointer->Redraw() or by IControlPointer->Hide(), otherwise it’s false. This function usually won’t be called by the user but is used inside IGraphics::Draw() to reset mDirty to false if the GUI drawing has be done.
class IGraphics:: // called by: pGraphics->function() / GetGUI()->function()
SetParameterFromPlug(int paramIdx, double value, bool normalized)
Is called by the host when sending automation data to the plug.
Calls IControl::SetValueFromPlug(double value) for all IControls associated with paramIdx => All IControls with the same paramIdx are synced. (misleading naming. Should rather be called something like: SetControlsWithParamIdx)
SetParameterFromGUI(int paramIdx, double normalizedValue)
Calls IControl::SetValueFromUserInput(normalizedValue) for all IControls associated with paramIdx.
SetControlFromPlug(int controlIdx, double normalizedValue)
Calls IControls::SetValueFromPlug(double value) for an IControl with index nr = controlIdx. Can be used in rare cases if you keep track of controlIdx numbers, what you usually don’t.
controlIdx != paramIdx !!
SetAllControlsDirty()
Calls SetDirty(false) for all IControls.
class IPlug:: // called by: Direct function call / mPlug->function()
SetParameterFromGUI(int paramIdx, double normalizedValue)
Sets Params mValue to normalizedValue and pushes it to the host. OnParamChange() is called afterwards. IControls associated with paramIdx are not updated.
Don’t mix up with IGraphics::SetParameterFromGUI(int paramIdx, double normalizedValue)
OnParamReset()
Calls OnParamChange() for all IParams.
RedrawParamControls()
Calls IGraphics::SetParameterFromPlug() for all IParams => All param associated IControls are updated and redrawn.
class IParam:: // called by: GetParam(paramIdx)->function()
The following functions are usually followed by InformHostOfParamChange()
SetNormalized(double normalizedValue)
Sets mValue of returned paramIdx to 'non-normalized' normalizedValue. No further action.
Set(double value)
Sets mValue of returned paramIdx to value. No further action.
|
Last edited by stw; 06-06-2017 at 01:12 AM.
|
|
|
06-03-2017, 11:43 AM
|
#11
|
Human being with feelings
Join Date: Dec 2015
Posts: 331
|
Nice list!
The only thing I see missing is IPlug::SetParameterFromGUI, and differentiate between IGraphics::SetParameterFromGUI. I just looked at the fact I'm calling IGraphics::SetParameterFromGUI in my OnParamChange, and IPlug::SetParameterFromGUI in my SetChunk override. I had to think about it a bit before I convinced myself that was correct. Annoying duplicity with that one.
|
|
|
06-03-2017, 08:07 PM
|
#12
|
Human being with feelings
Join Date: Dec 2015
Posts: 39
|
Great, thank you for the list and explaination !
|
|
|
06-04-2017, 06:08 AM
|
#13
|
Human being with feelings
Join Date: Apr 2012
Posts: 279
|
Quote:
Originally Posted by earlevel
Nice list!
The only thing I see missing is IPlug::SetParameterFromGUI, and differentiate between IGraphics::SetParameterFromGUI. I just looked at the fact I'm calling IGraphics::SetParameterFromGUI in my OnParamChange, and IPlug::SetParameterFromGUI in my SetChunk override. I had to think about it a bit before I convinced myself that was correct. Annoying duplicity with that one.
|
You're right i left that out. And i left out all IParam:: value setting functions too. Main purpose of that list was to point out which function should be called (and which not) to keep the GUI in sync with associated params or values. AFAIS IParam:: or IPlug:: Setters don't touch any GUI settings if not followed by e.g. RedrawParamControls(). So it would make thigs even more complicated for beginners.
But on the other hand, it's a good idea to have all things in place. I'll complete the list later...
|
|
|
06-04-2017, 10:51 AM
|
#14
|
Human being with feelings
Join Date: Dec 2015
Posts: 331
|
Quote:
Originally Posted by stw
But on the other hand, it's a good idea to have all things in place. I'll complete the list later...
|
Not trying to make work for you! I only mentioned SetParameterFromGUI because it exists in two different but similar forms. Even though you list it under IGraphics, you can bet someone will find the other and use it instead. To make matter worse, most people would be calling it from their plugin code, and the other version can be called directly (e.g, SetParameterFromGUI instead of GetGUI->SetParameterFromGUI).
An unfortunate overlap of names—it's a poor choice for the IGraphics version in particular, since it doesn't set a parameter. It forces an update of controls associated with a parameter. That is, IGraphics::SetParameterFromGUI is what you'd call after a parameter changes from the GUI, to ensure all its controls match.
Last edited by earlevel; 06-04-2017 at 10:53 PM.
|
|
|
06-06-2017, 01:30 AM
|
#15
|
Human being with feelings
Join Date: Apr 2012
Posts: 279
|
Quote:
Originally Posted by earlevel
Not trying to make work for you! I only mentioned SetParameterFromGUI because it exists in two different but similar forms. Even though you list it under IGraphics, you can bet someone will find the other and use it instead. To make matter worse, most people would be calling it from their plugin code, and the other version can be called directly (e.g, SetParameterFromGUI instead of GetGUI->SetParameterFromGUI).
|
Good point! I updated the list. I hope i didn't miss important information
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 10:53 PM.
|