Missing events on MIDI out from VST3 plugin


#1

Hi,

I’m a newbie to JUCE and I’ve been trying to develop a MIDI plugin to transform some of the incoming events and let others pass through. Unfortunately, it seems that only Note On and Note Off messages pass through, all other message types seem to be implicitly filtered out. I must be doing something wrong but I can’t figure it out. I simplified my code to the bare minimum so that it only counts incoming events by type. Here is the main parts of the processor code:

//==============================================================================
MidiTestAudioProcessor::MidiTestAudioProcessor()
	:
#ifndef JucePlugin_PreferredChannelConfigurations
     AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", AudioChannelSet::stereo(), true)
                     #endif
                     ),
#endif
	parameters(
		*this,
		nullptr,
		Identifier("MidiTest"),
		{
			std::make_unique<AudioParameterInt>("allMidiMessageCount", "allMidiMessageCount", 0, 15, 0),
			std::make_unique<AudioParameterInt>("noteOnCount", "noteOnCount", 0, 15, 0),
			std::make_unique<AudioParameterInt>("noteOffCount", "noteOffCount", 0, 15, 0),
			std::make_unique<AudioParameterInt>("programChangeCount", "programChangeCount", 0, 15, 0),
			std::make_unique<AudioParameterInt>("ccCount", "ccCount", 0, 15, 0),
			std::make_unique<AudioParameterInt>("otherCount", "otherCount", 0, 15, 0),
		}
	)
{
	allMidiMessageCountParameter = static_cast<AudioParameterInt*>(parameters.getParameter("allMidiMessageCount"));
	++parameterCount;
	noteOnCountParameter = static_cast<AudioParameterInt*>(parameters.getParameter("noteOnCount"));
	++parameterCount;
	noteOffCountParameter = static_cast<AudioParameterInt*>(parameters.getParameter("noteOffCount"));
	++parameterCount;
	programChangeCountParameter = static_cast<AudioParameterInt*>(parameters.getParameter("programChangeCount"));
	++parameterCount;
	ccCountParameter = static_cast<AudioParameterInt*>(parameters.getParameter("ccCount"));
	++parameterCount;
	otherCountParameter = static_cast<AudioParameterInt*>(parameters.getParameter("otherCount"));
	++parameterCount;
}

MidiTestAudioProcessor::~MidiTestAudioProcessor()
{
}

void MidiTestAudioProcessor::processBlock (AudioBuffer<float>&, MidiBuffer& midiBuffer)
    {
    	if (!midiBuffer.getNumEvents())
    		return;

	int allMidiMessageCount = 0;
	int noteOnCount = 0;
	int noteOffCount = 0;
	int programChangeCount = 0;
	int ccCount = 0;
	int otherCount = 0;

	MidiMessage midiMessage;
	int samplePosition;

	for (MidiBuffer::Iterator iterator(midiBuffer); iterator.getNextEvent(midiMessage, samplePosition);)
	{
		++allMidiMessageCount;
		if (midiMessage.isNoteOn())
			++noteOnCount;
		else if (midiMessage.isNoteOff())
			++noteOffCount;
		else if (midiMessage.isProgramChange())
			++programChangeCount;
		else if (midiMessage.isController())
			++ccCount;
		else
			++otherCount;
	}

	allMidiMessageCountParameter->beginChangeGesture();
	allMidiMessageCountParameter->setValueNotifyingHost(allMidiMessageCountParameter->convertTo0to1(static_cast<float>(allMidiMessageCount)));
	allMidiMessageCountParameter->endChangeGesture();

	noteOnCountParameter->beginChangeGesture();
	noteOnCountParameter->setValueNotifyingHost(noteOnCountParameter->convertTo0to1(static_cast<float>(noteOnCount)));
	noteOnCountParameter->endChangeGesture();

	noteOffCountParameter->beginChangeGesture();
	noteOffCountParameter->setValueNotifyingHost(noteOffCountParameter->convertTo0to1(static_cast<float>(noteOffCount)));
	noteOffCountParameter->endChangeGesture();

	programChangeCountParameter->beginChangeGesture();
	programChangeCountParameter->setValueNotifyingHost(programChangeCountParameter->convertTo0to1(static_cast<float>(programChangeCount)));
	programChangeCountParameter->endChangeGesture();

	ccCountParameter->beginChangeGesture();
	ccCountParameter->setValueNotifyingHost(ccCountParameter->convertTo0to1(static_cast<float>(ccCount)));
	ccCountParameter->endChangeGesture();

	otherCountParameter->beginChangeGesture();
	otherCountParameter->setValueNotifyingHost(otherCountParameter->convertTo0to1(static_cast<float>(otherCount)));
	otherCountParameter->endChangeGesture();
}

The main part of the jucer file looks like:

<JUCERPROJECT id="Vmc7LZ" name="MidiTest" projectType="audioplug" jucerVersion="5.4.1" pluginFormats="buildVST3" pluginCharacteristicsValue="pluginProducesMidiOut,pluginWantsMidiIn" pluginVST3Category="Fx,Instrument,Tools" cppLanguageStandard="latest" bundleIdentifier="com.PbrSoft.MidiTest" companyName="PbrSoft" pluginManufacturer="PbrSoft">

I’m compiling the VST3 of the plugin using MS Visual Studio on Windows 7 SP1, the running it on Cubase 7.5 (64 bits) set up like this:

MidiTest plugin loaded as a Rack instrument

Midi track 01
	Input: Midi controller port
	Output: MidiTest plugin
	Midi plugin: Midi Monitor (to show incoming messages)
Midi track 02
	Input: MidiTest plugin
	Output: output midi port
	Midi plugin: Midi Monitor (to show output from MidiTest plugin)

I also noticed that Program Changes messages are never included in the MidiBuffer passed to processBlock(), most probably because they are filtered out before during the plugin preset management logic. Is there a way to tell JUCE to skip preset management logic and to include Program Changes messages in the MidiBuffer passed to processBlock()?

Thanks,

Paul


#2

VST3 added support for MIDI CC in/out like just a few weeks ago. I don’t think it’s currently supported in JUCE’s VST3 wrapper yet. I don’t think Program Change messages are passed to the callback in VST3 either, Steinberg believes that those are the responsibility of the host to manage.

Keep in mind that since it’s such a new feature you may have issues finding hosts who support it at all.


#3

Thanks for the quick reply. Could you please tell me where to find where to find the VST3 specification you mentioned in your reply?

Thanks again!


#4

https://github.com/steinbergmedia/vst3sdk. Clone with the --recursive flag, the documentation isn’t available online. The interface is IMidiLearn for CC in, and the LegacyMIDICCOutEvent struct for writing CC out events to the event bus.