Slider values greater than 1 overwritten in RTAS plug


#1

Hi,

I could use a little help with a bug I’m experiencing with an RTAS plug that uses Juce sliders. When a slider value changes, my filter’s SetParameter() function is called twice, first when my UI component is called and subsequently calls getFilter()->setParameterNotifyingHost() from sliderValueChanged(), and then from UpdateControlValue() via the Pro Tools process classes. I’m surprised to see the second call happen, but regardless, here’s what goes wrong. The first call to SetParameter has the correct values, and for my app they are normally 0 to 1000. However any values over 1 result in the second call to SetParameter() getting passed a value of 0x7FFFFFFF. The call stack shows that the bad value is there as early as PI_UpdateControlValue which is called from the Pro Tools lib. In JucePlugInProcess::UpdateControlValue, the call to longToFloat() converts it to a 1.

Anybody care to take a guess as to what’s going on here? I’ll keep digging but if this is obvious to anyone, please send me a note.

Thanks,

Steve


#2

I’ve reproduced this condition in the RTAS_Mac demo code by changing one line of code in the constructor for DemoEditorComponent. If you increase the range of the slider values to go from 0 to 25 instead of 0 to 1, you always get the bug described in my first post.

DemoEditorComponent::DemoEditorComponent (DemoJuceFilter* const ownerFilter) : AudioProcessorEditor (ownerFilter)
{
// create our gain slider…
addAndMakeVisible (gainSlider = new Slider (T(“gain”)));
gainSlider->addListener (this);

// my change: slider range up to 25.0
gainSlider->setRange (0.0, 25.0, 0.01);
gainSlider->setTooltip (T("changes the volume of the audio that runs through the plugin.."));

If you then run this plug in Pro Tools, you will get the usual two calls to setParameter(0, the first one from Juce is correct and the second one will pass in a value of 1.

What am I missing?

Steve


#3

No takers?

If you run the juce_RTASDemo (I run it on the Mac), there is a slider for the gain. The range for that slider is set in the constructor for DemoEditorComponent with the line

     gainSlider->setRange (0.0, 1.0, 0.01);

How would I change the slider so that it allows values up to, say 25? I tried this:

gainSlider->setRange (0.0, 25.0, 0.01);

But what I find happens is that there are two calls to DemoJuceFilter::setParameter(). The first one has the correct value. It’s called from Juce as a result of handling the value change. The second call appears to come from the Pro Tools process classes’ UpdateControlValue() methods. These end up calling into the Juce_RTASWrapper’s UpdateControlValue. If the value entered or clicked is > 1, Pro Tools sends 0x7FFFFFFF, which Juce converts to 1 in longToFloat().

How do I get the slider to allow values greater than 1? I’ve looked all over the code to see if there is another range being set somehow, or if there is some overflow condition, but so far no luck. Any suggestions welcome!

Steve


#4

Hi, sorry - I didn’t notice the original post.

The range is supposed to be limited to 0->1, so that things will work with the lowest-common-denominator plugin formats. (VST works with 0->1 floating points, RTAS is a fixed-size 24-bit int, etc, so there’s no way to just allow an unlimited range float to be sent to all hosts). The idea is that you’d scale your UI values up and down in your get/set parameter callbacks so that the host only ever sees 0->1. I seem to remember some people posting helper classes to make that job easier…


#5

Thanks for the reply, Jules. Limiting the range makes sense, although it’s not obvious to me from looking at the code, since setRange() doesn’t apply any limit…

It looks like the limiting is happening here:

static long floatToLong (const float n) throw()
{

return roundDoubleToInt (jlimit (-(double) 0x80000000,
                                 (double) 0x7fffffff,
                                 n * (double) 0xffffffff - (double) 0x80000000));

}

This is in the RTAS wrapper and called from jucePlugInProcess::audioProcessorParameterChanged(). If n > 1.0, the upper limit is applied. Is it the intention of floatToLong() to only convert floats that are <= 1?

Steve


#6

Yes, it’s doing exactly what it’s supposed to do. RTAS stores its parameters as ints, so the only way to store a 0-1 value in it is to scale it up to the full integer range.


#7

BTW the range limit is explained in the comments for the AudioProcessor parameter methods.


#8

OK, scaling the values in set/getParameter() is straightforward. But what about the value displayed in the slider’s text box? That is based on Slider::currentValue which is not scaled. Wouldn’t I need a slider with a similar scaling factor that gets applied in updateText()?


#9

I think you might be getting yourself confused… Your slider can use any range you want, you’d only have to scale the values when you set or get them as parameters.


#10

No doubt I’m confusing myself. :?

Yes, if I set the range for values over 1, the slider itself works fine. The problem is that when the user enters anything over 1.0, the call to SetControlValue() results in my filter’s setParameter() method getting called with a value of 1. So, setParameter() gets called twice per slider value change. The first one has the value entered and the second one has a 1. Where exactly would I be scaling?

Steve


#11

Oh, I think I see the misunderstanding now - are you talking about the user entering a value >1 in the ProTools GUI? I assumed you were talking about them typing in the slider’s text box…


#12

As far as I know, the only way the user can specify the parameter value would be dragging the slider or entering in the slider’s text box. I set the range of the slider to 0-25, say, they can drag the slider to some value over 1, or enter it in the value box, and I will get my two calls to setParameter. If they slide to or enter 14.2 setParameter will be called with a 14.2 and then again right after that with a 1. When you say Pro Tools GUI… all the interaction is within the plug-in window owned by Juce.


#13

Ok, then you are just missing the point… The slider isn’t magically connected to setParameter - it’s your code that calls setParameter when the slider changes, so if your slider is chucking out numbers in the range 0 to 100, you’d use something like setParameter (mySliderVal / 100). Right?


#14

Ah. The code I have is based on your audio plug-in demo code, which doesn’t call setParameter directly, but instead calls setParameterNotifyingHost():

void DemoEditorComponent::sliderValueChanged (Slider*)
{
getFilter()->setParameterNotifyingHost (0, (float) gainSlider->getValue());
}

So the answer is to change that to this:

void DemoEditorComponent::sliderValueChanged (Slider*)
{
getFilter()->setParameterNotifyingHost (0, (float) gainSlider->getValue()/100.0);
}

…which works. So, so obvious now. :roll:

Thanks for the help, jules!


#15

By the way, it’s great that set/getParameter() documentation mentions the 0->1 range. I would consider highlighting that in the host notification code itself, possibly with an assert. It’s not clear to a newbie that float parameter can’t exceed 1. Maybe setParameterNotifyingHost(), e.g. should be labeled with a warning about that. Just a thought.


#16

Yes, an assert might be a good idea!


#17

Resurrecting an old thread here:

I just ran into this unexpected behavior in my first RTAS plugin. Unexpected, because it behaves quite differently from the VST version of my plugin. From my understanding of things (derived from programming a lot of VST plugins), VST expects its parameters to be in the range 0 to 1. I have not translated my Juce GUI sliders to be in the 0 to 1 range, yet my Juce VST plugins work great, even with numbers like 70, 1000.0, and so on.

So the question is either:

  • Why does the RTAS Juce wrapper behave differently from the VST Juce wrapper, or

  • Why is the VST wrapper working at all?

Thanks,

Sean Costello


#18

If I remember correctly, VST passes floats directly to the host, but RTAS communicates with 32-bit ints, so the values are rescaled to fit that, meaning that it has to limit the values to 0->1.


#19

So, let me see if I understand things correctly:

  • VST uses floats. The VST 2.4 plugin standard usually uses floats in the range 0 to 1. Presumably the Juce plugin sends and receives values larger than 1, but most hosts don’t perform any sort of range checking on the floats, which is why I haven’t encountered any errors with my Juce plugins so far.

  • RTAS uses 32-bit ints, representing 0 to 1. Pro Tools presumably clips things to the maximum value of the int, to prevent wraparound.

Do most VST hosts limit their automation to 0->1 values?

Sean Costello


#20

Hi,

The clipping is not perfomed by protools, but rather in the juce RTAS wrapper.

Salvator