Juce Demo Plugin crash Ableton Live

OSX, Master branch, JuceDemoPlugin VST crash latest Ableton Live when loaded on a side chain.

Can be reproduced every time:

  1. On a Mac, open latest Live 9.7.1. Fresh project.
  2. On the “B track”, add the JuceDemoPlugin VST.
  3. On the “1 MIDI track”, add “Sounds/Voices/Vovosyn.adg” from Lives standard sounds (it happens with other sounds as well).
  4. On track 1, set “MIDI From” to the B track where JuceDemoPlugin sits.
  5. Now send some audio to the “B track”, by enabling “in” on track 3 and move up the “send B” slider on track 3.
    6 .Crash!

I have not tried yet on Windows.

Bump! Please try to reproduce this, juce crew.

Interesting, I can only seem to re-produce something similar (for me the plugin editor also has to be open) when debugging with Xcode. Also, it seem that this bug also makes Xcode hang (I need to force quit xcode). Could this be a weird situation with Ableton and the Xcode debugger? Were you able to reproduce this when you are not debugging?

Thank you for looking into this!

It certainly happens every time here, also without Xcode running, and without the plugin editor open. Tested on two different Macs.

Further experiments - when i flip step 4 & 5 in the process to this:

1-3. same as above.
4. Now send some audio to the “B track”, by enabling “in” on track 3 and move up the “send B” slider on track 3.
5. On track 1, set “MIDI From” to the B track where JuceDemoPlugin sits.
6 .Live Crash, but sometimes it first start to paint random black boxes or colours in the Live UI!

Something must be writing in the wrong memory. Perhaps due to how the Juce Demo Plugin agree on shared data/channels/buses? Seems related to the midi output of the Juce Demo Plugin.

I’m using the Live 9.7.1 in demo mode (disabled save/load) if that could make a difference.

Yes I agree this seems to be related to MIDI not audio. I sometimes get a crash in ::memmove and I can see that the memory accessed has midi data in it. However, I can’t analyse further as Xcode just hangs completely…

I also cant see anyting from the audio thread in XCode when debugging through Live.

It was certainly not the problem with earler Juce versions. So, im guessing it has to do with the latest multibus refractorings somehow. One option is to go back in git history and see where it breaks.

And, maybe you can forward the issue to Ableton? (i’m thinking you have a better hotline than us small devs). They can easier debug it.

Its kind of serious - it prevents us to release plugin updates.

OK after a lot of debugging I don’t think this is a JUCE bug. I think this will occur with any audio effect plug-in with midi in & outs.

I created the most simplest audio effect without any JUCE code (see source code below) and it crashes Ableton in exactly the same way.

We’ll report this to Ableton. Thanks for reporting.

#include "public.sdk/source/vst2.x/audioeffectx.h"

class VST2MidiOutput : public AudioEffectX
{
public:
    VST2MidiOutput (audioMasterCallback audioMaster)
        : AudioEffectX (audioMaster, 1, 1),
          gain (0.1f)
    {
        setUniqueID ('crSh');
        setNumInputs (2);
        setNumOutputs (2);
        canProcessReplacing (true);
        setProgram (0);
    }
    
    void getParameterName (VstInt32 index, char* label) override
    {
        if (index == 0) strcpy (label, "Gain");
        else AudioEffectX::getParameterName (index, label);
    }
    
    bool getEffectName (char* name) override    { strcpy (name, "VST2MidiOutput"); return true; }
    bool getVendorString (char* text) override  { strcpy (text, "ROLI Ltd.");      return true; }
    bool getProductString (char* text) override { strcpy (text, "VST2MidiOutput"); return true; }
    VstInt32 canDo (char* text) override
    {
        if (strcmp (text, "sendVstEvents") == 0 || strcmp (text, "sendVstMidiEvent") == 0) return 1;
        if (strcmp (text, "receiveVstEvents") == 0 || strcmp (text, "receiveVstMidiEvent") == 0) return 1;
        
        return AudioEffectX::canDo (text);
    }
    
    void setParameter (VstInt32 index, float value) override   { if (index == 0) gain = value; }
    float getParameter (VstInt32 index) override               { return (index == 0 ? gain : 0.0f); }
    
    void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames) override
    {
        for (int ch = 0; ch < cEffect.numInputs; ++ch)
        {
            if (inputs[ch] != outputs[ch])
                memcpy (outputs[ch], inputs[ch], sizeof (float) * sampleFrames);
            
            for (int i = 0; i < sampleFrames; ++i)
                outputs[ch][i] *= gain;
        }
        
        for (int ch = cEffect.numInputs; ch < cEffect.numOutputs; ++ch)
            memset (outputs[ch], 0, sizeof(float) * sampleFrames);
    }
    
    VstInt32 processEvents (VstEvents* events) override
    {
        return 1;
    }
    
private:
    float gain;
};

AudioEffect* createEffectInstance (audioMasterCallback audioMaster)
{
    return new VST2MidiOutput (audioMaster);
}
4 Likes

Fabian, thank you so much for this effort! Thats very comforting.