VST3 (midi) and JUCE

As this post is almost a year old, could anyone (ideally someone from JUCE’s team) tell us if there is any plan to solve MIDI usage with VST3 in JUCE ?

Looking around the Internet MIDI and VST3 seem to be a vast problem, not at all JUCE specific, but it’s a real pain, meaning going back to VST2 format (and losing the ease of use of JUCE’s Plugin Host during dev), but also losing a lot of time trying to understand the problem before reading posts as this.

With a simple test, I discovered that Process Block seems not even to be running if there is nothing else than MIDI handling (even a simple text message handling will not do, to the opposite of VST2).

Thank you by advance for your answers!

There is not much JUCE can do about poor midi support in VST3. Steinberg screwed that up with VST3. They tried to patch it up a bit a few years ago with that legacyOut feature-add, but as noted, not all hosts are aware of that or supporting that. There are other problems with VST3 midi also that I won’t get into now. Suffice it to say that Steinberg does not believe that VST plugins should be used for midi plugins. They don’t even feel VST2 should have been used for that and they say publicly that people who make VST2 midi plugins are simply exploiting the fact that it can be done but in their view its not what VST is intended for and make no promises about it. Their view is that VST is an audio plugin standard, not midi.

The only real support for MIDI in VST3, according to their philosophy, is for accepting midi data for instrument plugins. But midi out, they see not point, pur4pose or reason to even talk about it. they don’t view that as being “proper” use of VST. I’m not making this up, that is their official viewpoint.

In VST2, many people have gotten away with making midi plugins because of the way the API works, you get the midi buffer to play with inside your plugin. IN VST3, they have reduced that midi buffer to only notes. So you can play with notes-only in a VST3 plugin, but when you start talking about all other midi event types, such as CC, PitchBend, etc… those are not in the midi buffer at all…and Steinberg does not feel it should be. They feel that all of those things should be converted by the host into “parameters” and that the plugin can access those parameters, in a similar way as it would access automation parameters; and then use that information however you want in your plugin to effect the audio, but outputting any of that midi is not the intention for VST plugins according to Steinberg and they refuse to support it.

They came out with the legacyCCOut thing relatively recently as a way to get CC messages out because people were screaming about it and somehow someone must have gotten past their defiant attitude enough to convince them to support it, so that added the ability for a plugin to output CC, but the host has to call that special callback function in order to do it. if that host doesn’t do it, then you can’t get CC’s out of a VST3 plugin.

So bottom line, if you have a license for VST2, I would not bother messing around with VST3 midi. Its way too broken and Steinberg doesn’t wish to fix it, as I said, they don’t view midi processing as the purpose of VST.

If you don’t have a VST2 license, well then officially, you can’t really make a VST midi plugin that works reliably today. Simple as that. Sorry to bear the bad news, but that is all how it is today in 2020.

1 Like

All that being said, I do wish JUCE would at least support multiple midi input ports for receiving midi to more than 16 midi channels, as is possible with VST3. Then it would be possible to create a multi-port VST3 instrument. VST3 is definitely capable of that. JUCE does not support that though.

But any kind of midi thruput in VST3…forget it. Not with JUCE and not directly with VST3 sdk either.

1 Like

This is simply not true . Here is a list of MIDI processing VST3 plugins I own and they work. Without glitches.

reMidi
Playbeat
Riffer Generator
Thesys
Phrasebox
Orb Composer
Scaler
Instachord
Cthulhu
Midi Madnes
AutoTheory
LiquidNotes
MidiQ

I*d say it is rather JUCE that does not care - for their own Arp Example does not work on VST3

Everything i said is absolutely true!

If you limit your midi processing to note events only then it should be fine in vst3, which still supports that even though steinberg doesn’t really officially support it

This is also not true . Go To the top and see my initial post - and: JUCE Arp example is pretty simple and straightforward and MIDI only - but it does not work on VST3

I don’t know why they don’t fix that, but you just need to add an audio input and then it works:

    Arpeggiator()
    
    : AudioProcessor (BusesProperties().withInput("Input", AudioChannelSet::mono(), true)) // seem to need for sampleRate
    //    : AudioProcessor(BusesProperties()) // add no audio buses at all - Original, doesn't work
    
    {
        addParameter (speed = new AudioParameterFloat ("speed", "Arpeggiator Speed", 0.0, 1.0, 0.5));
    }

processBlock() will not be called with a valid number of samples unless there is an audio input.

4 Likes

I can’t think of a reason why the midi arp example should not work on vst3 if it’s only notes. Please provide more details about why and how it doesn’t work. I agree with you that juce should support as much of vst3 as possible, Notwithstanding the fact that vst3 cannot do everything with midi that vst2 can do. But still be forewarned, steinberg does not support or condone the use of either vst format for midi plugins! If juce arp is not working then get to the bottom of exactly why not. Most complaints about vst3 midi are related to non-note related problems.

Also does the arp example work when used inside the juce plugin host?

In my view steinberg does not condone or officially support vst midi plugin development. That means there is no Garauntee that all hosts will look for notes coming out of a vst3 plugin though that is likely to be ok if the midi buffer is passed by reference in and out of the plugin. Because it’s typically passed by reference then a plugin can manipulate the contents (notes only) and the changes will be seen by the host. But if the host copies the buffer there is no garauntee that the host will copy notes from output because steinberg doesn’t officially endorse or support that!!

Various hacks have been used by some hosts to handle cc and other types of events since vst3 abandoned them entirely. But not all hosts are doing that and it the same way so honestly I think if you need to process more then notes you should stick with vst2

Thnx I’ll try that

<< I can’t think of a reason why the midi arp example should not work on vst3 if it’s only notes. Please provide more details about why and how it doesn’t work.>>
Well, you code ? No, easier : You compile ? Fire up compiler, compile and try .
What are you talking about ? Yes . It is a shame for amateurs - but I listed plugins of pros - and these work . I just wonder IF they used JUCE …

As Stephen pointed out a solution for you to try I guess the discussion is over. The juce team ought to fix the arp example to avoid confusion.

As I said, steinberg views vst as an audio sdk and whatever it is able to do with midi is only considered as being related to feeding software instrument plugins with data to produce audio. All midi-only plugins are happy accidents that steinberg does not endorse nor support.

In this case you have to make sure the vst3 plugin thinks it is processing audio in order for the callback to happen properly. Then you can sneak in there and manipulate the midi buffer as you wish to do, but ONLY note events will be there.

Juce is generally handling vst3 midi correctly per the vst3 specification. The vst3 spec is the limiting factor. Except juce is not supporting multiple midi ports which I wish it would

Makes sense …

can you make some midi plugin tutorials? would be cool to see some different applications of midi in vst3 :slight_smile:

FWIW: just did a quick test with the example plugin ArpeggiatorPluginDemo.h and this is my conclusion (JUCE 5.4.5):

  1. The line stephenk mentioned above is necessary.

  2. For the Plugin characteristics flags I had only “Plugin MIDI Input”, “Plugin MIDI Output” and “MIDI Effect Plugin” selected, the rest not.

  3. I tested in Cubase 10.5 by inserting the plugin on an audio track, and selecting the plugin as MIDI input for an instrument track (and then making sure either “Record enable” or “Monitor” is enabled for the instrument track).

  4. When I used the code that is present in the example’s processBlock, it did NOT work. So I replaced it with some very crude and primitive test code that just sends a note on and note off and that did work:

    void processBlock(AudioBuffer<float>& buffer, MidiBuffer& midi) override
    {
     // the audio buffer in a midi effect will have zero channels!
     jassert (buffer.getNumChannels() == 0);
    
     // however we use the buffer to get timing information
     auto numSamples = buffer.getNumSamples();
    
     // get note duration
     auto noteDuration = static_cast<int> (std::ceil(rate * 0.25f * (0.1f + (1.0f - (*speed)))));
    
     if (0) // set to 1 to use JUCE's code
     {
         MidiMessage msg;
         int ignore;
    
         for (MidiBuffer::Iterator it(midi); it.getNextEvent(msg, ignore);)
         {
             if (msg.isNoteOn())  notes.add(msg.getNoteNumber());
             else if (msg.isNoteOff()) notes.removeValue(msg.getNoteNumber());
         }
    
         midi.clear();
    
         if ((time + numSamples) >= noteDuration)
         {
             auto offset = jmax(0, jmin((int)(noteDuration - time), numSamples - 1));
    
             if (lastNoteValue > 0)
             {
                 midi.addEvent(MidiMessage::noteOff(1, lastNoteValue), offset);
                 lastNoteValue = -1;
             }
    
             if (notes.size() > 0)
             {
                 currentNote = (currentNote + 1) % notes.size();
                 lastNoteValue = notes[currentNote];
                 midi.addEvent(MidiMessage::noteOn(1, lastNoteValue, (uint8)127), offset);
             }
         }
     }
     else // some horribly jittery primitive test code
     {
         midi.clear();
    
         if ((time + numSamples) >= noteDuration)
         {
             midi.addEvent(MidiMessage::noteOn(1, 65, (uint8)127), 0);
             midi.addEvent(MidiMessage::noteOff(1, 65), numSamples / 2);
         }
     }
    
     time = (time + numSamples) % noteDuration;
    }
    

I was in a hurry, so I didn’t try to understand / check the example code, but at least that new test code above showed that VST3 can send out note on/off messages, even though the example code doesn’t seem to work. I didn’t test any other events than note on/off, given that there are known issues with that apparently.

1 Like

I made a tutorial with TheAudioProgrammer on how to create a midi vst3 plugin (that only processes notes though) right here:

Code can be found here:

P.S. some of the plugins mentioned in this thread, like Xfer Records Cthulhu, are actually VST2. Not sure about the rest.

2 Likes

Great . So problem solved … now i fired up JUCE Arp Example did this swapWith and … does not do … so I githubbed and found this :

But this guy uses the exact same code ( besides some minor changes )
he got rid of auto noteDuration = static_cast (std::ceil(rate * 0.25f * 0.1f));
and devised a slightly different version
and as an VST3 i t w o r k s … now … back to the top … which was the Q: why does code work for AU and VST2 but NOT for VST3

1 Like

Thank you all for your answers.

My project is mainly a MIDI translator from CC coming from a physical controller to multiple logical occurrences, depending on the user interaction.

I went back to VST2.

I am new to Juce and am in the process of developing a MIDI plugin. The base works as long as the host is playing, great so far. But I have seen plugins (e.g. Cthulu) that also output MIDI (notes) when the host is stopped. Since my DAW (Ableton Live) no longer calls processBlock in this case, how can I continue to output MIDI notes in VST3, e.g. using a HighResolutionTimer?

@bobo Ableton Live (like most other hosts except for Logic) doesn’t support the concept of MIDI FX.

Instead, define your app as a synth with MIDI Out, and your process block will get called.

For Logic to see it as a MIDI Effect, add kAudioUnitType_MIDIProcessor as your AU plugin type.

Hello Eyal,
I followed your tutorial and now I also get the answer from you in no time, thank you very much!
By the way, I also listened to your music, I really love it! Don’t forget to keep making music with all your programming :wink:

2 Likes