[solved] ParameterChangeGesture assertion throws after JUCE update


#1

Hey all,

Since updating to the latest JUCE, a plug-in that was previously working is now throwing assertions whenever a GUI element is moved, with the comment next to the assertion being “called with an out-of-range parameter index!” (line 222 of AudioProcessor.cpp). The same error is thrown with line 244. (ending the gesture).

There are two things I did that lead to this starting to happen- I updated to the latest JUCE, and rebuilt the plugin host. I unfortunately no longer have the prior host.

Is this perhaps due to how I’m handling my AudioProcessorValueTreeState? I’ve included what should be the relevant code below, but I’m at a loss:

In the processor-

const int ISWTestPluginAudioProcessor::NUMPROCESSORPARAMS = 3;
String ISWTestPluginAudioProcessor::processorParamArray[] = {"drygain", "wetgain", "stereomode"};

ISWTestPluginAudioProcessor::ISWTestPluginAudioProcessor()
{
    mUndoManager = new UndoManager();
    mState = new AudioProcessorValueTreeState(*this, mUndoManager);

    initParams();
    
    mState->state = ValueTree("ISWTest");
}
ISWTestPluginAudioProcessor::~ISWTestPluginAudioProcessor()
{
    //ScopedPointer objects take care of deletion
    mUndoManager = nullptr;
    mState = nullptr;
}
void ISWTestPluginAudioProcessor::initParams()
{
    //I/O processor parameters
    mState->createAndAddParameter(processorParamArray[0], "Dry Gain", "Dry Gain", NormalisableRange<float>(0.0, 4.0, 0.0, 1.2), 0.75, nullptr, nullptr);
    mState->createAndAddParameter(processorParamArray[1], "Wet Gain", "Wet Gain", NormalisableRange<float>(0.0, 4.0, 0.0, 1.2), 0.25, nullptr, nullptr);
    mState->createAndAddParameter(processorParamArray[2], "Stereo Mode", "Stereo Mode", NormalisableRange<float>(0, 3, 1), 0, nullptr, nullptr);

    //Add appropriate listeners for each parameter
    for(int i=0; i<NUMPROCESSORPARAMS; i++)
    {
        mState->addParameterListener(processorParamArray[i], this);
        AudioProcessorParameter* tempForInit = mState->getParameter(processorParamArray[i]);
        tempForInit->setValue(tempForInit->getValue()); //setValue so that listener is updated
    }
}

void ISWTestPluginAudioProcessor::parameterChanged(const String &parameterID, float newValue)
{
    if(parameterID == "stereomode")
    {
        stereoMode = int(newValue);
    }
    else if(parameterID == "drygain")
    {
        dryGain = newValue;
    }
    else if(parameterID == "wetgain")
    {
        wetGain = newValue;
    }
    else
    {
        //cout used here for troubleshooting- not lockfree!!!!
        //should never occur in finished product; replace with exception/assertion
        std::cout << "Unknown processor param change: " << parameterID << std::endl;
    }
}

And then in the Editor-

ISWTestPluginAudioProcessorEditor::ISWTestPluginAudioProcessorEditor (ISWTestPluginAudioProcessor& p)
    : AudioProcessorEditor (&p), processor (p)
{
    gui = ISWGUI::getInstance();
    
    //Processor Controls
    sliderStereoMode = gui->addKnob(Colour(0,0,0), Colour(0,0,0), this, float_Pi*5.0/4.0, float_Pi*11.0/4.0, true);
    sliderDryGain = gui->addKnob(Colour(0,0,0), Colour(0,0,0), this, float_Pi*5.0/4.0, float_Pi*11.0/4.0, true);
    sliderWetGain = gui->addKnob(Colour(0,0,0), Colour(0,0,0), this, float_Pi*5.0/4.0, float_Pi*11.0/4.0, true);
    
    //Make all Slider objects visible
    for(int i=0; i<gui->getNumSliders(); i++)
    {
        addAndMakeVisible(gui->getSlider(i));
    }
    
    //use SliderAttachment objects to connect a Slider and a parameter
    attachmentDryGain = new AudioProcessorValueTreeState::SliderAttachment(p.getValueTreeState(), ISWTestPluginAudioProcessor::processorParamArray[0], *sliderDryGain);
    attachmentWetGain = new AudioProcessorValueTreeState::SliderAttachment(p.getValueTreeState(), ISWTestPluginAudioProcessor::processorParamArray[1], *sliderWetGain);
    attachmentStereoMode = new AudioProcessorValueTreeState::SliderAttachment(p.getValueTreeState(), ISWTestPluginAudioProcessor::processorParamArray[2], *sliderStereoMode);
    
    //Skewing, suffixes etc
    sliderWetGain->setSkewFactorFromMidPoint(0.5);
    sliderDryGain->setSkewFactorFromMidPoint(0.5);

    //window size- must be set last
    setSize (400, 150);
}

ISWTestPluginAudioProcessorEditor::~ISWTestPluginAudioProcessorEditor()
{
    //ScopedPointer objects take care of deletion when set to null
    attachmentDryGain = nullptr;
    attachmentWetGain = nullptr;
    attachmentStereoMode = nullptr;

    //Takes care of slider deletion with internal vector of ScopedPointer objects
    gui->clearGUI();
}

Any ideas as to what might be causing my issue / how to fix it?


JUCE Demo Plugin VST3 crashes when using Address Sanitizer
#2

Hi TristineWild,

I tried recreating your plugin here and loaded it into Reaper to send it some automation data but it worked fine and didn’t throw any errors. I don’t have the code for your ISWGUI class though so created the plugin Sliders in the regular way instead of going through your ISWGUI::addKnob() function so perhaps that is where your problem lies?

Cheers,
Ed


#3

Thank you for doing so! Much appreciated.

The actual plugin code has much more than I shared here- I only shared would I thought was relevant, but I could be missing something.

The ISWGUI code isn’t doing anything I’d thought would cause this issue-here’s what addKnob does-

Slider* ISWGUI::addKnob(Colour outColour, Colour fillColour, Component* windowForPopup, float startAngleRad, float endAngleRad, bool stopAtEnd)
{
    Slider* newKnob = new Slider;
    
    newKnob->setSliderStyle (Slider::Rotary);
    newKnob->setRotaryParameters(startAngleRad, endAngleRad, stopAtEnd);
    newKnob->setColour(Slider::rotarySliderOutlineColourId, outColour);
    newKnob->setColour(Slider::rotarySliderFillColourId, fillColour);
    newKnob->setTextBoxStyle(Slider::NoTextBox, false, 90, 0);
    newKnob->setPopupDisplayEnabled(true, windowForPopup);
    
    sliders.push_back(newKnob);
    return newKnob;
}

Where ‘sliders’ is a vector of ScopedPointer’s.

I can try not using that proprietary class and see if it fixes things… otherwise, my only idea of what to do is to recreate the plugin piece-by-piece until I discover what’s causing the issue :-/


#4

std::vector should really only be used with primitive types and not with ScopedPointers as the push_back method can move and copy around the ScopedPointer. Try using something like an OwnedArray instead of a vector and that should solve your issues.

Let me know how it goes!
Ed


#5

Thanks for letting me know for future reference.

I ditched ISWGUI/vectors entirely; now every parameter has an attached Slider object that is a member of the Editor… I’m still getting the same bug :-/


#6

OK, that’s strange. The plugin that I created from your code snippets doesn’t seem to throw any errors so without seeing more code I’m afraid I can’t help much more.


#7

Thanks nonetheless. I can’t think of a better way to debug than just recrafting it from scratch until it breaks… guess I’ll give that a go.


#8

It certainly reproduces for me - first using my plugin, and than using the example given here by a forum member for a correct use(?) of AudioProcessorValueTreeState:

I get jassertfalse; // called with an out-of-range parameter index!
in juce_AudioProcessor.cpp

Everything works perfectly (at least it seems), but it is so annoying while debugging.
I use updated Xcode on mac OSX El Capitan and JUCE 4.2.3.

Also reproduces using this example:


#9

Sorry for forgetting this information, but I too am on Mac OS X El Capitan (10.11.4) using Xcode 7.3.1 with JUCE 4.2.3.

I checked and on Windows 10 with VS 2012, I don’t have this issue.


#10

Still can’t reproduce this even using the plugin example you posted. Can you post a stack trace?


#11

Here it is:

`(lldb) thread backtrace

  • thread #1: tid = 0x800732, 0x0000000106d4c43b Plugin Host`juce::AudioProcessor::beginParameterChangeGesture(this=0x00007fd2baf5bcc0, parameterIndex=3165055) + 315 at juce_AudioProcessor.cpp:222, name = ‘Juce Message Thread’, queue = ‘com.apple.main-thread’, stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
    • frame #0: 0x0000000106d4c43b Plugin Hostjuce::AudioProcessor::beginParameterChangeGesture(this=0x00007fd2baf5bcc0, parameterIndex=3165055) + 315 at juce_AudioProcessor.cpp:222 frame #1: 0x0000000106d759b5 Plugin Hostjuce::AudioUnitPluginInstance::eventCallback(this=0x00007fd2baf5bcc0, event=0x00007fd2bad11f78, newValue=0) + 277 at juce_AudioUnitPluginFormat.mm:1100
      frame #2: 0x0000000106d748d5 Plugin Hostjuce::AudioUnitPluginInstance::eventListenerCallback(userRef=0x00007fd2baf5bcc0, (null)=0x0000000000000000, event=0x00007fd2bad11f78, (null)=2079950764971830, value=0) + 117 at juce_AudioUnitPluginFormat.mm:1123 frame #3: 0x00007fff96cf1af7 AudioToolboxAUEventListener::DispatchMessages(std::__1::vector<AUEventListenerBase::Message, std::__1::allocatorAUEventListenerBase::Message > const&) + 153
      frame #4: 0x00007fff96cf1a25 AudioToolboxAUEventListener::MessagesAreAvailable() + 83 frame #5: 0x00007fff9544eb94 CoreFoundationCFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION + 20
      frame #6: 0x00007fff9544e823 CoreFoundation__CFRunLoopDoTimer + 1075 frame #7: 0x00007fff9544e37a CoreFoundation__CFRunLoopDoTimers + 298
      frame #8: 0x00007fff95445871 CoreFoundation__CFRunLoopRun + 1841 frame #9: 0x00007fff95444ed8 CoreFoundationCFRunLoopRunSpecific + 296
      frame #10: 0x00007fff8d4e9935 HIToolboxRunCurrentEventLoopInMode + 235 frame #11: 0x00007fff8d4e976f HIToolboxReceiveNextEventCommon + 432
      frame #12: 0x00007fff8d4e95af HIToolbox_BlockUntilNextEventMatchingListInModeWithFilter + 71 frame #13: 0x00007fff93bfddf6 AppKit_DPSNextEvent + 1067
      frame #14: 0x00007fff93bfd226 AppKit-[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 454 frame #15: 0x00007fff93bf1d80 AppKit-[NSApplication run] + 682
      frame #16: 0x0000000106e94453 Plugin Hostjuce::MessageManager::runDispatchLoop(this=0x00007fd2bac17ba0) + 147 at juce_mac_MessageManager.mm:248 frame #17: 0x0000000106e94345 Plugin Hostjuce::JUCEApplicationBase::main() + 389 at juce_ApplicationBase.cpp:240
      frame #18: 0x0000000106e9415c Plugin Hostjuce::JUCEApplicationBase::main(argc=1, argv=0x00007fff58f66b68) + 60 at juce_ApplicationBase.cpp:218 frame #19: 0x0000000106caa7d3 Plugin Hostmain(argc=1, argv=0x00007fff58f66b68) + 51 at HostStartup.cpp:133
      frame #20: 0x00007fff958365ad libdyld.dylibstart + 1 frame #21: 0x00007fff958365ad libdyld.dylibstart + 1

Sorry for the formatting but the code includes your special character for preformatted text and I don’t know of any escape character.

I am using this example:

System Version: OS X 10.11.5 (15F34)
Kernel Version: Darwin 15.5.0


#12

According to your stack trace you are on the last tagged release. This bug has already been fixed with this commit. Please always use the latest tip on master or develop when reporting bugs.


#13

Oh, thank you- this fixes it. I hadn’t realized that the release I grabbed from updating JUCE wouldn’t be the latest commit, I’ll be sure to remember to grab that in the future.


#14

Same for me here, thank for the fix.
I will check with the latest tip before reporting a bug again.