Update knob-position to match changed ParamQuantity

I have a knob for controlling PWM of an LFO, which default to a range from 0.01 (1%) to 0.99 (99%). However I have a context-menu where different ranges can be selected. To facilitat this I’ve made a PwmRangeQuantity which allows different ranges to be set (bascially it just changes minValue and maxValue of the ParamQuantity

struct PwmRangeQuantity : ParamQuantity {
	enum pwmRange { pwm_01_99, pwm_05_95, pwm_10_90, pwm_15_85, pwm_20_80, pwm_25_75 };

	PwmRangeQuantity() {
		minValue = 0.01f;
		maxValue = 0.99f;
		defaultValue = 0.5f;
	}

	void setRange(float minRange = 0.01f, float maxRange = 0.99f) {
		float currValue = getValue();

		// Set new range, and clamp value to range
		this->minValue = minRange;
		this->maxValue = maxRange;
		setValue(currValue);
	}

	void setRange(pwmRange range) {
		const float minPwmRange[]{ 0.01f, 0.05f, 0.10f, 0.15f, 0.20f, 0.25f };
		const float maxPwmRange[]{ 0.99f, 0.95f, 0.90f, 0.85f, 0.80f, 0.75f };
		setRange(minPwmRange[range], maxPwmRange[range]);
	}

	void reset() override {
		setRange(0.01f, 0.99f);
		setValue(defaultValue);
	}

	float getDisplayValue() override {
		unit = " %";
		displayMultiplier = 100.f;
		return ParamQuantity::getDisplayValue();
	}
};

If the knob (param) is dialed to 99% (with a range from 1% to 99%) and I select another range (calling the setRange method of my PwmRangeQuantity struct), the visual knob keeps its current position, but the value of the knob/param is changed to 75%, which is just perfect.

However if I change the range back to the range 1% to 99%, the visual knob is still turned fully clockwise, which with the new range should be 99%. The parameter is still correctly “read” as 75% when calling getValue of the param, however I had expected the knob (RoundSmallBlackKnob) to turn a bit couter-clockwise to the 75% position

float pwmValue = params[PWMKNOB_PARAM].getValue();

Perhaps I have addressed this wrongly? I have no problem with the actual min/max of the param to stay fixed at 0.01 to 0.99 (or -1 to +1 or whatever) as long as the tool-tip shows the “correct value” according to the selected range, and right-clicking the knob and enter a value, the knob should set the correct value, but I’m usure how/which methods to override to acomplish this?

Without looking at the code my bet is the knob doesn’t invalidate on range change just in value change. Subclass the knob, override step, cache min and max, dirty the knob if the change, call the superclass step. Something like that is where I would start

Again just speculating not at computer in the code

if you override the param quantity (very easy) you can make the tooltip be anything you want, and you can do the string to float conversion yourself. Without changing anything about the controls you can do that.

@Squinky as I read your suggestion, I shold keep the minMax at fixed levels (e.g. from -1 to +1, or 0 to 1) and then scale what is shown in the tooltip? However I would like it also work with right-clicking the knob and enter a value, hence the entered value needs to be scaled according to selected PWM range, and a fixed min/max-range?

@baconpaul what I have now the actual min/max-range and the param seems to work, as changing the range and later reading the value of the param, the param is clamped as it should (with param at 0.99 and changing range to “25% to 75%” the param is read as 0.75, hence clamped to the new range). Perhaps a hack, I was thinking if I can set “a flag” when PWM-range is changed in the module, and then in the step of the module-widget’s step, can “invalidate” the knob (force it to update) when it sees this flag? Is there a way to force an update of a “knob”?

Not really an answer to your problem, but another way to deal with range changes. Make the knob position the constant factor and calculate the new value based on the constant knob position and the new range.

	void setRange(float minRange = 0.01f, float maxRange = 0.99f) {
		float newValue = rescale(getValue(), minValue, maxValue, minRange, maxRange);

		// Set new range and new value
		this->minValue = minRange;
		this->maxValue = maxRange;
		setValue(newValue);
	}
1 Like

I’m not saying you “should” do anything. That’s your choice.

Yes, I think when you say you want the right click + enter value to be controllable that’s the same thing as providing your own text to number conversion function, yes? The user right clicks (you don’t want to change that, I don’t think). That makes a menu come up (you don’t want to change that, I don’t think). The user types in something (you don’t want to change that, I don’t think). Then they press enter to finalize it (you don’t want to change that, I don’t think). Then your text to number function is called. I think that’s the only thing you want to change. And that is easily done with a custom param quantity.

Lol, someone came from their camping trip in a foul mood.

Just wanted to chip in to tip my hat off to all the vcv plugin developers who offer graceful and supportive suggestions to others without sounding like a cranky job interviewer from Adobe or something.

Hello my friend! How have you been?

Swampedd with work, preparing for a relaxing weekend of vcv experiments, and grateful for all the wonderful contributions of this community, including yours!

2 Likes

Sorry for the delay in reply (vacation). @Squinky I was not trying to imply you were “forcing me” to do anything, I was just trying to make sure I was understanding your suggestion correctly :slight_smile:

In the end I chose the suggestion from @soundismovement as it was pretty simple and I realized it was probably what would make most sense to the users (that the knobs stays stationary).

2 Likes

Just a quick follow up: While working on another module using the same scaling idea suggested by @soundismovement I realized I had a bug. While the scaling worked just fine while running with my patch in VCV, it is not loading correctly. As it will first load the (already scaled) from the json, and and it will later adjust the scaling range of the knob, which in effect will scale the value a 2nd time.

The module I work on now have an attenuate/amplify knob which by default is working in the range -1x to +1x. With context menus I can change between 1x, 2,d 5x or 10x. What I do now is I simply have a fixed scaling range from -1 to +1. I don’t even need to make my own paramQuantitie. All I have to do is to change it’s displayMultiplier (either as 1.f, 2.f, 5.f or 10.f).

paramQuantities[A_SCALE_PARAM]->displayMultiplier = attRngFactor;

1 Like