Conversion function called hundreds of times with no reason in 5.4.1


#1

Hi!
I’m working on Mac OSX 10.11.6, with Xcode 8.2.1. I am reporting here a bug that I mentioned in a different thread, but was possibly not considered. I am using a custom conversion function in a NormalisableRange, and for some reasons, this function is called hundreds of times with no interaction from the user. I reduced the source code to the simplest possible, using a single slider, and a single parameter:

    parameters.createAndAddParameter (
          "param",       // parameterID
          "Param",       // parameter name
          "",           // parameter label (suffix)
          NormalisableRange<float> (
               0.0f,
               100.0f,
               [](float start, float end, float v) {
                       cntcv01toVal++;
                       return start + (end - start) * v; 
               },
               [](float start, float end, float v) {
                      cntcvValTo01++;
                      return (v - start) / (end - start);
               }
          ),    // range
         0.0f,         // default value
         [] (float p) { cntdblToStr++; return dbEdit(p, 3); },
         [] (String str) { cntstrToDbl++; return strToDbl(str);}
    );

The various functions I use do trivial things, but count the number of times they are called, and the count is printed in the plugin destructor.

As a test, I just launch the plugin in Xcode, and immediately close it with no other interaction.
I have compiled the plug-in with JUCE 5.3.2 and the latest develop branch of 5.4.1. Here are the traces:

JUCE v5.3.2
**** OrangejuceAudioProcessor 1.0.0 ->
**** OrangejuceAudioProcessor<-
**** OrangejuceAudioProcessorEditor->
**** OrangejuceAudioProcessorEditor<-
**** ~OrangejuceAudioProcessorEditor*
**** ~OrangejuceAudioProcessor*
---- Counters:    cntdblToStr=0    cntstrToDbl=0
----             cntcv01toVal=1    cntcvValTo01=1



JUCE v5.4.1
**** OrangejuceAudioProcessor 1.0.0 ->
**** OrangejuceAudioProcessor<-
**** OrangejuceAudioProcessorEditor->
**** OrangejuceAudioProcessorEditor<-
**** ~OrangejuceAudioProcessorEditor*
**** ~OrangejuceAudioProcessor*
---- Counters:    cntdblToStr=1    cntstrToDbl=0
----             cntcv01toVal=5    cntcvValTo01=272

As you can see, with the same code and the same interaction, one conversion function is called 272 times in JUCE 5.4.1, and only once in JUCE 5.3.2. There is clearly a problem, that most people may not have noticed because computers are so fast nowdays…

I attach here the whole source code, so you may try to reproduce the problem:
Orange-JUCE-Simple.zip (61.4 KB)

Thanks.


#2

If you’ve provided a 0->1 conversion function in your parameter’s NormalisableRange, then it’ll be called each time the slider attachment repaints itself - the paint method gets the various slider positions and passes them to the LookAndFeel here, the positions are calculated using getLinearSliderPos() which will uses the range’s conversion method here. This is the correct behaviour and shouldn’t cause any performance problems as the it’s very unlikely that you’re doing anything very time consuming in the conversion method. If you are doing enough work for it to show up in a performance test, then you’ve got bigger problems.

I believe the reason that this wasn’t happening in earlier versions of JUCE is due to a bug in the SliderAttachment constructor. You can see here that there is a check whether the parameter’s range is using non-default values for skew or interval and it won’t use the conversion functions if this is true, but that line should be:

if (range.interval != 0 || range.skew != 1)

as the skew default is 1, not 0. Therefore the 0->1 conversion doesn’t get called in the slider’s paint method and you end up with an incorrect slider position. To demonstrate this, change the 0->1 conversion method in your createAndAddParameter() call to just return 1 all the time. The expected behaviour is that the slider should always be 1 and never move, but this isn’t the case as the conversion method is never called.