Strange touch automation behavior


#1

Many of my AU soft synth's knobs have ranges outside of 0 - 1. For example my Delay Spread knob goes from 0 to 100. Automation expects values within 0 - 1 so I:

Convert to 0 - 1 in my custom slider class:

double MySlider::getValue()

{
    float currentValue = Slider::getValue();
    float convertedValue = fabs((currentValue - getMinimum()) / (getMaximum() - getMinimum()));
    return convertedValue;
}

Send in the value:

void SynthComponent::sliderValueChanged (Slider* sliderThatWasMoved)
{
    MySlider* tmpSlider = static_cast<MySlider*>(sliderThatWasMoved);
    int thisID = tmpSlider->getID();
    PrImerAudioProcessor* pAProc = static_cast <PrimerAudioProcessor*> (pluginEditor->getAudioProcessor());
    float newValue = tmpSlider->getValue();
    pAProc->setParameterNotifyingHost(thisID, newValue);
}

 

Convert it back to its original range and do any secondary changes in setParameter before sending it into my synth:

void PrimerAudioProcessor::setParameter (int index, float newValue)

{
    // convert it back to original range
    float reconvertedValue = newValue * fabs(Par::controlRanges[index][1] - Par::controlRanges[index][0]) + Par::controlRanges[index][0];

    if (index == DELAYSPREADR)
    {
        // tweak it one more time into a value the synth expects
        reconvertedValue = reconvertedValue / 1000.0;
    }

    else if //// do other conversions for other controls....

    synth.addToParList(index, reconvertedValue);

}

This works out fine EXCEPT when using touch automation. For some odd reason that second tweak:

reconvertedValue = reconvertedValue / 1000.0;

actually shows up in the automation! So when I leave it in, the automation barely moves off of 0, because it's showing tiny values. If I delete it, the automation works perfectly, showing values from 0 - 1, but the synth of course isn't getting the values it expects.

Why would the automation be effected by what I do in setParameter? Isn't setParameterNotifiyingHost responsible for effecting automation? 

FYI - my beginParameterChangeGesture is in the custom slider's startedDragging() method, and endParameterChangeGesture is in the Slider's stoppedDraggin() method. I've tested this on Mac in both Logic and Live.


#2

Doing some further tests I tried commenting out all of the code within setParameters(). When I do, no changes get registered into touch or latch automation. But if I add the following line back in:

synth.addToParList(index, reconvertedValue);

It starts to register again (albeit inaccurately). "synth" is an instance of Synthesizer.

I thought setParameterNotifyingHost was the only method that effected automation. Why would my call to my own Synthesizer object within setParameter() have any effect on the automation?


#3

OK, so I tested this with JuceDemoPlugin and the same problem occurs. I did the following:

1. Set both sliders' range to 0 -> 10 (instead of 0 -> 1)

2. In sliderValueChanged I multipled the slider's value by 0.1 before sendParameterNotifyingHost in order to convert it to 0 -> 1

3. In setParameter I reconverted it back to original 0 -> 10 range by multipling it by 10..0.

When using touch/latch automation it goes crazy, recording really inaccurate readings. 

If I need to use Sliders that don't have a 0 -> 1 range, how can I get them to work with Juce's setParamaterNotifyingHost, setParameter, and gesture methods properly?


#4

Nothin?


#5

Sorry - can't face ploughing through all that detail. If you can boil it down to a couple of sentences..?


#6

Sure. My synth has several Sliders whose ranges are outside of 0 -> 1, and the touch/latch automation goes crazy trying to track movement on these sliders. I tried converting to 0 -> 1 before sending in parameters, and then converting back to the original range afterward, but that didn't help. So I tested it out on the JuceDemoPlugin and I'm running into the same problem. Here' what I did to test it in the JuceDemoPlugin:

1. Set both sliders' range to 0 -> 10 (instead of 0 -> 1)

2. In sliderValueChanged I multipled the slider's value by 0.1 before sendParameterNotifyingHost in order to convert it to 0 -> 1

3. In setParameter I reconverted it back to original 0 -> 10 range by multipling it by 10..0.

But no success. Any ideas?

 

 

 


#7

Here it is even shorter: Using the JuceDemoPlugin, trying to get sliders with ranges outside of 0->1 to track correctly in touch/latch automation, but it's not working. 


#8

Really don't know!


#9

Damn. So is it bad/unusal to use sliders outside of the 0-1 range?


#10

If you have some values (from a slider, or any other source of data) and correctly scale them to the appropriate range for a parameter, then it'll work. If it doesn't work, then you're not scaling your values correctly. I've no idea what you're doing wrong, but trying to overload the Slider class and mess with its values is bound to break something.


#11

OK thanks, I'll look at that. But one thing I still don't undertsand is why the autmoation value is effected by processing I do in the setParameter() method. Here's a simple example:

void PrimerAudioProcessor::setParameter (int index, float newValue)

{

    float convertedValue = newValue * 0.1;

    synth.addToParList (index, convertedValue); // send into the synth, process, etc.

}

Whatever "convertedValue" is, the automation records, NOT "newValue". Isn't that strange? Isn't it only supposed to track the "newValue" that's sent in, and not what is done to it after the fact?


#12

Hi Hanley,

setParameter() is for the host to tell your plugin processor that a parameter is changed. If automation is recording the "convertedValue" then whatever you're doing in setParameter is triggering your code to send that value back to the host somehow.

What I do is have a parameter class which contains an automation value (0..1) and a GUI value (whatever range makes sense ofr the user). The class contains all the conversion methods I need. There's also a native value which I use for DSP, but that's not relevant here.

Main points on flow of parameter changes:

  • setParameter() updates the automation value of my parameter
    <ul>
    	<li><span>The parameter&nbsp;internally updates the GUI value for later use</span></li>
    </ul>
    </li>
    <li>In the GUI, sliderValueChanged() converts takes the GUI value from the slider, converts it to the automation value and then calls setParameterNotifyingHost()
    <ul>
    	<li>I don't update the automation value, because setParameterNotifyingHost() calls setParameter() and that will update the automation value for me</li>
    </ul>
    </li>
    <li>I use a timerCallback in the GUI to check the processor for parameter changes
    <ul>
    	<li>This pulls the GUI value from the parameter and sends it to the slider</li>
    	<li>IMPORTANT - make sure you set dontSendNotification in the slider's setValue call</li>
    </ul>
    </li>
    

Hope this helps...


#13

Thanks for the tips Andrew! That does help me understand it a bit better. But I must have something screwed up somewhere. I ran a little test and commented out every line of code in setParameter() so it's just an empty method. When I do that, the automation just records "0" every time I move a knob. That's not normal is it?


#14
double MySlider::getValue()

That line is wrong on so many levels: you've overloaded a non-virtual method of Slider. You probably shouldn't even be inheriting from Slider, there's rarely a good reason to do that.


#15

Alright, so I added a new Slider, no inheritance just a plain Slider, and the same thing happens. The automation records the "reconvertedValue" in getParameter(), not the "newValue" sent into setParameterNotifyingHost(). I'm assuming that's very unusual?


#16

Well, setParameterNotifyingHost() changes the parameter in your plugin processor and tells the host about it - this is initiated from the plugin side.

When the host is initiating contact with the plugin, the host calls getParameter() and expects a value in the 0..1 range.


#17

OK, so I figured out the problem. What I didn't understand was that the automation was getting its values from the getParameter() method. My getParameter() method was returning values from my Synth object, which is why any time I changed the values in setParameter and sent them into my synth, that new changed value was showing up in the automation. Thanks for you help in understanding how it all works. 


#18

No worries. I'm glad you figured it out!