Comboboxes don't always update


#1

About 25% of the time when I select an item in a ComboBox the value doesn’t change. I’m using Juce 2.0.38, and so far I’ve tried Audition and Cubase on Windows 7, and it happens with both. I found one post describing what appears to be the same problem, but in that case the bug went away after upgrading to Juce 2.0.

http://www.rawmaterialsoftware.com/viewtopic.php?f=8&t=6188

Anyone else seen this, or have any ideas for a work around?

Thanks,
Chris


#2

Presumably this is only in certain plugin hosts? I’ve certainly never seen it happen in an app.

If the hosts are doing something involving window focus/grabbing mouse-clicks etc then there’s not really much we could do about it. Have you tried in a more controllable environment like the juce demo host?


#3

Thanks for the reply. I could not reproduce the bug using the JuceDemo app, but I haven’t tried converting my code to a standalone app. I’m not too surprised that it doesn’t happen with the demo app, since it appears to work a bit differently (e.g., doesn’t use setParameterNotifyingHost). I was also able to reproduce the bug as an AAX plug-in in Pro Tools.

I tried creating a simple test case using the Juce Demo PlugIn. I added the following code and I was still able to reproduce the problem. I tried to follow the method used by the sliders as closely as possible, so that this implementation would be by “book” and as simple as possible.

Any other ideas?

[code]private:
ComboBox comboBox1;
enum { cNumComboItems=4 };

//Put in constructor
//ComboBox #1
addAndMakeVisible (&comboBox1);
comboBox1.setBounds (10, 25, 120, 20);
comboBox1.addListener (this);
comboBox1.addItem (“One”, 1);
comboBox1.addItem (“Two”, 2);
comboBox1.addItem (“Three”, 3);
comboBox1.addItem (“Four”, 4);
comboBox1.setSelectedItemIndex (0, dontSendNotification);

void JuceDemoPluginAudioProcessorEditor::timerCallback()
{
JuceDemoPluginAudioProcessor* ourProcessor = getProcessor();

comboBox1.setSelectedItemIndex(ourProcessor->getParameter(JuceDemoPluginAudioProcessor::gainParam)*(cNumComboItems-1), dontSendNotification);
}

void JuceDemoPluginAudioProcessorEditor::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
{
if (comboBoxThatHasChanged == &comboBox1)
{
int index = comboBoxThatHasChanged->getSelectedItemIndex();
getProcessor()->setParameterNotifyingHost (JuceDemoPluginAudioProcessor::gainParam, float(index)/(cNumComboItems-1));
}
}[/code]


#4

I actually suggested trying the juce plugin host, not the juce demo. The thing you need to find out is whether it’s something that’s host-specific, or whether it happens in all hosts. Using the juce host app means you have full access to the host as well as the plugin, so have more chance of tracking down that’s happening.


#5

Ok, gotcha. I tried the Juce Plugin Host and the problem DOES happen. Also, I have one other piece of information. The problem goes away if I comment out the “setSelectedItemIndex” line in timerCallback. But I guess that means that parameter updates from automation won’t update the GUI, so of course it’s not really a solution, but it seems like an important clue.


#6

Ah. Well yes, looking at your code, of course it’ll go wrong sometimes if you have a timer continuously setting the value while your menu is trying to change it!


#7

Then it seems to me that the Juce Demo PlugIn has this problem with all of its controls. It’s just that for sliders you don’t notice the problem so much because the values are continuous. Does that sound correct to you?

Anyhow, I would like to get a recommendation on the best way to handle this. It would be great if you could update that demo plugin, so that it does the “right” thing. I can get it to work by just removing the timer callback code, but then it won’t handle control changes via automation.

I also have some questions about using a timer to handle control drawing updates. I expected that this would work by the plug-in getting idle time (e.g., effEditIdle in VST), as opposed to a timer. Is there any particular reason you chose to implement it this way? Also, I was wondering if the timer has an independent thread or is serviced during the the idle time of the plug-in host? From poking around in the debugger it looks like the timer callback is executed in the main thread, so it should basically be the same as getting idle time, but I figure you can answer that definitively.

Any wisdom you can share is greatly appreciated.

Thanks,
Chris


#8

Hi Chris - one solution is to use a public flag in your AudioProcessor that is set to true whenever there is a change in a parameter which the combo box is dependent on. In your case this is gainParam and you can set this flag in JuceDemoPluginAudioProcessor::setParameter().

Then in the JuceDemoPluginAudioProcessorEditor::timerCallback() you only update the selected item index if the flag is set. Note that you’ll need to the clear the flag right away (you’ll need to do this from within the editor of course, but you can get away with not locking the operation).

-Andrew


#9

Thanks Andrew. I tried your suggestion and it seems to work, although I wonder if it will work in all cases, such as multiple fast changes from the user and/or automation. It would be nice to have a more “elegant” solution that handles any type of control and does it behind the scenes. I’ve used numerous plug-in formats and I don’t remember having to do that sort thing.


#10

OK, have you read the documentation on setParameterNotifyingHost()? I’m not clear on this, but it maybe up to the host to not send automation data while a parameter change gesture is occurring (makes sense to me but may be wishful thinking).

You can implement the parameter change gesture stuff for sliders like this:

[code]// xxxParameterChangeGesture stuff here is used to notify host when user is holding control - this can help host manage automation
void JuceDemoPluginAudioProcessorEditor::sliderDragStarted (Slider* slider)
{
int index = slider->getProperties().getWithDefault(Identifier(“paramIndex”), -1);
if (index!=-1) { getProcessor()->beginParameterChangeGesture(index); }
}
void JuceDemoPluginAudioProcessorEditor::sliderDragEnded (Slider* slider)
{
int index = slider->getProperties().getWithDefault(Identifier(“paramIndex”), -1);
if (index!=-1) { getProcessor()->endParameterChangeGesture(index); }

}[/code]
Note that I set parameter index as a property for each of my sliders so I can identify which parameter they correspond to.

For ComboBox you might be able to try using focusGained & focusLost instead of sliderDragStarted & sliderDragEnded. Not sure how that will go.

-Andrew


#11

Thanks for the help. My understanding is that the begin/endParameterChangeGesture calls will only have an effect when recording automation. Pro Tools for example has a touch automation mode where automation data will only be written when the user is adjusting the control. But at any rate this is good thing to support.


#12

I'm having the same issue with the normal "updateParametersFromFilter" method. Same implementation as in the demo plugin. I noticed this in Reaper 32bit Windows. The combo box does not change its values as expected after i automated one or more plugin parameter. Reaper sends a lot of setParemters() all the time and it looks that they overwrite the value i selected on the UI most of the time. 

Is the solution Andrew recommend the way to go or are there better ways to handle this? Any feedback is welcome.

 

Thanks.