Cubase 5 crashes with Juce Demo Vst with 4 inputs, 2 outputs

Users have reported problems with my 4 input, 2 output vst plugin made with Juce 1.46 in Cubase 5.0.0 on win.

To replicate the problem I made the Juce demo project have:

#define JucePlugin_MaxNumInputChannels 4
#define JucePlugin_MaxNumOutputChannels 2
#define JucePlugin_PreferredChannelConfigurations { 4, 2 }

bool DemoJuceFilter::isInputChannelStereoPair (int index) const
{
return true;
}

bool DemoJuceFilter::isOutputChannelStereoPair (int index) const
{
return true;
}

I add The Demo filter to a Cubase 5 “Quadro” group track and send some audio to it and then close cubase and I get a funny crash in the ntdll.dll every time which is saying:

Detected memory leaks!
Dumping objects ->
c:\documents and settings\andy\my documents\dev\trunk\thirdparty\juce\juce_amalgamated.h(20090) : {36953} normal block at 0x12751878, 24 bytes long.
Data: <4AB > 34 41 42 12 CD CD CD CD CD CD CD CD CD CD CD CD
c:\documents and settings\andy\my documents\dev\trunk\thirdparty\juce\juce_amalgamated.h(20090) : {36952} normal block at 0x12753B90, 24 bytes long.
Data: <4AB > 34 41 42 12 00 00 00 00 00 00 00 00 00 00 00 00
Object dump complete.
‘Cubase5.exe’: Unloaded ‘C:\Audio\VstPlugins\juce_vst.dll’
‘Cubase5.exe’: Unloaded ‘C:\WINDOWS\system32\opengl32.dll’
‘Cubase5.exe’: Unloaded 'C:\WINDOWS\system32\glu32.dll’
HEAP[Cubase5.exe]: Heap block at 0EA4C120 modified at 0EA4C130 past requested size of 8
Windows has triggered a breakpoint in Cubase5.exe.

This may be due to a corruption of the heap, which indicates a bug in Cubase5.exe or any of the DLLs it has loaded.

This may also be due to the user pressing F12 while Cubase5.exe has focus.

The output window may have more diagnostic information.

Any ideas?

Andrew Simper

I remember hitting a bug some time ago where cubase crashed if you had a 5.1 track but didn’t tell it exactly the right speaker arrangement. If you’re still using 1.46 code then you might need to look at the latest version and see what changed there…

I’m not using a 5.1 track. It’s a quadro track with 2 stereo pairs. I have no “speaker arrangement”, I just declare via the vst spec 4 inputs and 2 outputs. I don’t know where speaker arrangments come into it.

Andrew Simper

I’m talking about the code in the vst wrapper that responds when the host asks it what its speaker arrangement is. There was a bug where cubase crashed if the track had more than 2 channels but the plugin didn’t respond to this request. Have a search in juce_VSTWrapper.cpp for setSpeakerArrangement and check that you’ve got the most up to date version of that method.

Hey Jules,

Does a 4 in 2 output juce demo plugin work for you on the latest code base in Cubase 5 when you instert it on a quadro bus? If so I’m happy to update to the latest version.

(edit: I’m downloading the head now from svn and will try it out)

Andrew Simper

I just tried having a stereo / mono only speaker arrangement as suggested in the other thread and everything is working just fine. Well there are some odd things going on when I tried to debug the release build, but that might just be steinberg’s copy protection doing funny stuff to the debugger.

So, for a 4 in, 2 output vst returning true to a stereo speaker arrangement only seems to work. I will now experiment with mono speaker arrangements as well.

Andrew Simper

Ok I have worked out a way that seems to work fine in Cubase 5 the code is below:

from the file JucePluginCharacteristics.h:
    #define JucePlugin_PreferredChannelConfigurations   {1, 1}, {2, 1}, {2, 2}, {4, 2}

from the file Juce/extras/audio plugins/wrapper/formats/VST/juce_VstWrapper.cpp:
    bool setSpeakerArrangement
    (
        VstSpeakerArrangement* pluginInput,
        VstSpeakerArrangement* pluginOutput
    )
    {
#ifdef USE_ORIGINAL_JUCE_CODE
        // this is the original juce code below and the original comment:
        // if this method isn't implemented, nuendo4 + cubase4 crash when you've got multiple channels..
        numInChans = pluginInput->numChannels;
        numOutChans = pluginOutput->numChannels;

        filter->setPlayConfigDetails
        (
            numInChans,
            numOutChans,
            filter->getSampleRate(),
            filter->getBlockSize()
        );

        return true;
#else
        // this is the new code that uses the channel configurations to work out what is valid
        int ioconfig[][2] = {JucePlugin_PreferredChannelConfigurations};
        int ioconfiglen = sizeof (ioconfig)/(2*sizeof (int));
        for (int j=0; j<ioconfiglen; j++)
        {
            if 
            (
                (
                    ((ioconfig[j][1] == 2) && (pluginOutput->type == kSpeakerArrStereo)) ||
                    ((ioconfig[j][1] == 1) && (pluginOutput->type == kSpeakerArrMono))
                ) &&
                (
                    (pluginInput->numChannels  == ioconfig[j][0]) &&
                    (pluginOutput->numChannels == ioconfig[j][1])
                )
            )
            {
                numInChans = pluginInput->numChannels;
                numOutChans = pluginOutput->numChannels;

                filter->setPlayConfigDetails
                (
                    numInChans,
                    numOutChans,
                    filter->getSampleRate(),
                    filter->getBlockSize()
                );

                return true;
            }
        }
        return false;
#endif
    }

The above code is not ideal since the what you really need is something like:

const char* ioconfigstring = “1-1; 1,1-1; 2-2; 2,2-2”;

where the - splits inputs and outputs, and the , splits busses. This same system could then be used to name the versions of the plugin if needs be via the waves type plugin enumeration mechanism, or even possibly just copying the same .dll to multiple names and having the plugin check itself to see what channel config to use:

The Glue 1-1.dll
The Glue 1,1-1.dll
The Glue 2-2.dll
The Glue 2,2-2.dll

Andrew Simper

Thanks, I’ll take a look at those changes. Did you notice the stuff in the very latest version:

[code] bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput,
VstSpeakerArrangement* pluginOutput)
{
if (numInChans != pluginInput->numChannels
|| numOutChans != pluginOutput->numChannels)
{
setNumInputs (pluginInput->numChannels);
setNumOutputs (pluginOutput->numChannels);
ioChanged();
}

    numInChans = pluginInput->numChannels;
    numOutChans = pluginOutput->numChannels;

    filter->setPlayConfigDetails (numInChans, numOutChans,
                                  filter->getSampleRate(),
                                  filter->getBlockSize());

    return true;
}

[/code]

…I think the calls to setNumInputs and ioChanged might be important to add.

Hi Jules,

as i mentiond in the other thread the setNumInputs/Outputs isn’t perfect (as i first thought), cause as discribed in the VST-specification this should be the number of maximun input/outchannels the plugin can handle and not the current. There will be crashes too if more of one instance of the same plugin are opend.

Edit: but the crazy thing is even when the plugin has a 2/2 configuration, cubase will ask to if it can handle 6/6, and if we than say “NO” cubase will crash too.

What i did is to check if the plugin is running under Cubase/Nuendo and the always provide 6 ore more channels (cause my Plugin can handle all different input/output configurations), and then Cubase can set dynamically the i/o channel configuraion by setSpeakerArrangement (without resetting setNumInputs/Outputs ).

Alle other hosts will get always a 2/2 Configuration, maybe i will provide an additional 6/6 plugin dll.

The code I posted above has been tested in Cubase 5 on several systems and seems to work just fine. I have the maximum number of inputs at 4 and maximum outputs at 2 and my channel config list is: {1, 1}, {2, 1}, {2, 2}, {4, 2}. I addition I am using the output count as the indicated by the list to determine if the plugin has a mono or stereo speaker arrangment, though there will need to be additional code if > 2 outputs are required.

Andrew Simper

Also it seems that Cubase does not support the {2, 1} config since it only ever tries {2, 2} which I accept as being just the regular stereo version instead of a mono version with external sidechain. In the end the user gets full stereo sidechain support via the {4, 2} setup so I don’t mind too much.

Andrew Simper

Ok, I’ve now officially lost track of all the facts in this thread! Maybe if you can all post your latest code, I can try to come up with the best overall solution!

My current production code is as above: http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?p=20812&sid=a3af6ee72a8ca0de49094266c80d0950#20812

Please give me a call if you want to have a quick talk about how to best handle all this.

Andrew Simper

I have the latest code tested now, and it’s working pretty solidly for me:


        // once all the below is done you can use this code in your process function
        int numin = getNumInputChannels ();
        int numout = getNumOutputChannels ();
        if (numout == 1)
        {
            // do mono processing stuff possibly depending on numin
        }
        else
        {
            // do stereo processing stuff possibly depending on numin
        }


        // in the constructor of the filter base class and always keep numInChans and numOutChans the maximum your plugin can handle
        speakerIn = kSpeakerArrEmpty;
        speakerOut = kSpeakerArrEmpty;
        speakerInChans = 0;
        speakerOutChans = 0;
        numInChans = JucePlugin_MaxNumInputChannels;
        numOutChans = JucePlugin_MaxNumOutputChannels;


        bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput, VstSpeakerArrangement* pluginOutput)
        {
            // this is the new code that uses the channel configurations to work out what is valid
            int ioconfig[][2] = {JucePlugin_PreferredChannelConfigurations};
            int ioconfiglen = sizeof (ioconfig)/(2*sizeof (int));
            for (int j=0; j<ioconfiglen; j++)
            {
                bool config_mono   = (ioconfig[j][1] == 1) && (pluginOutput->type == kSpeakerArrMono);
                bool config_stereo = (ioconfig[j][1] == 2) && (pluginOutput->type == kSpeakerArrStereo);
                bool in_count_matches  = (ioconfig[j][0] == pluginInput->numChannels);
                bool out_count_matches = (ioconfig[j][1] == pluginOutput->numChannels);

                if ((config_mono || config_stereo) && in_count_matches && out_count_matches)
                {
                    speakerIn = pluginInput->type;
                    speakerOut = pluginOutput->type;
                    speakerInChans = pluginInput->numChannels;
                    speakerOutChans = pluginOutput->numChannels;
                    
                    filter->setPlayConfigDetails
                    (
                        speakerInChans,
                        speakerOutChans,
                        filter->getSampleRate(),
                        filter->getBlockSize()
                    );
                    
                    CYTRL ("VstWrapper::setSpeakerArrangement speakerIn=" << speakerIn << " speakerOut=" << speakerOut << " speakerInChans=" << speakerInChans << " speakerOutChans=" << speakerOutChans);
                    
                    return true;
                }
            }
            return false;
        }


    bool getInputProperties (VstInt32 index, VstPinProperties* properties)
    {
        CYTRL ("JuceVSTWrapper::getInputProperties index=" << index);
        
        if (filter == 0 || index >= JucePlugin_MaxNumInputChannels)
            //if (filter == 0 || index >= filter->getNumInputChannels())
            return false;
        
        const String name (filter->getInputChannelName ((int) index));
        
        name.copyToBuffer (properties->label, kVstMaxLabelLen - 1);
        name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1);
        
        if (speakerIn != kSpeakerArrEmpty)
        {
            properties->flags = kVstPinUseSpeaker;
            properties->arrangementType = speakerIn;
        }
        else
        {
            properties->flags = kVstPinIsActive;
            
            if (filter->isInputChannelStereoPair ((int) index))
                properties->flags |= kVstPinIsStereo;
            
            properties->arrangementType = 0;
        }
        return true;
    }
    
    bool getOutputProperties (VstInt32 index, VstPinProperties* properties)
    {
        CYTRL ("JuceVSTWrapper::getOutputProperties index=" << index);
        
        if (filter == 0 || index >= JucePlugin_MaxNumOutputChannels)
            //if (filter == 0 || index >= filter->getNumOutputChannels())
            return false;
        
        const String name (filter->getOutputChannelName ((int) index));
        
        name.copyToBuffer (properties->label, kVstMaxLabelLen - 1);
        name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1);
        
        if (speakerOut != kSpeakerArrEmpty)
        {
            properties->flags = kVstPinUseSpeaker;
            properties->arrangementType = speakerOut;
        }
        else
        {
            properties->flags = kVstPinIsActive;
            
            if (filter->isOutputChannelStereoPair ((int) index))
                properties->flags |= kVstPinIsStereo;
            
            properties->arrangementType = 0;
        }
        return true;
    }

Cool, thanks Andy, I’ll take a look through that and see what I can do…

getting this error when trying to compile the new code (revision 722) for the VST wrapper on windows:

juce_vst_wrapper.cpp(1006) : error C2440: '=' : cannot convert from 'VstInt32' to 'VstSpeakerArrangementType'
        Conversion to enumeration type requires an explicit cast (static_cast, C-style cast or function-style cast)

And indeed I can not find a definition for the type VstSpeakerArrangementType… is something missing?

VstSpeakerArrangementType is an enum in the header aeffectx.h in the vst sdk. The header defines “type” in VstSpeakerArrangement and “arrangementType” in VstPinProperties as VstInt32.

Andrew Simper

Ok, but still some casting is needed in order for Visual Studio not to complain about stuffing a VstInt32 into that enum:

if ((configMono || configStereo) && inCountMatches && outCountMatches)
            {
                speakerIn = (VstSpeakerArrangementType)pluginInput->type;
                speakerOut = (VstSpeakerArrangementType)pluginOutput->type;
                speakerInChans = pluginInput->numChannels;
                speakerOutChans = pluginOutput->numChannels;

                filter->setPlayConfigDetails (speakerInChans, speakerOutChans,
                                              filter->getSampleRate(),
                                              filter->getBlockSize());
                return true;
            }

Do you agree?

Sorry, I didn’t try compiling on windows. Thanks, I’ll add those casts.