Newbie using JUCE for VST needs a hand


#1

Hi guys, I need to do some (I think) pretty simple VST work for a project and after a bit of messing around with JUCE, I thought it would be a good way to avoid having to deal with plugins directly.

I’m not aiming to write a full-fledged host or anything; all I need to do is put some midi events through a VST instrument and get the result for later use, but I am having a problem after getting quite close.

Some code thus far; this is the entirety of the test program I am writing:

	juce::AudioPluginFormatManager::getInstance()->addDefaultFormats();

	juce::OwnedArray <juce::PluginDescription> typesFound;
	juce::KnownPluginList *list = new juce::KnownPluginList();
	juce::File *file = new juce::File("{pathRemoved}4Front Piano Module.dll");
	if(file->exists())	
	{
		if(list->scanAndAddFile(*file, true, typesFound))
		{
			const juce::PluginDescription *des = list->getTypeForFile(*file);		

			juce::VSTPluginFormat *format = new juce::VSTPluginFormat();

			juce::AudioPluginInstance *plugin = format->createInstanceFromDescription(*des);

			if(plugin->acceptsMidi())
			{
				float midiDataGoesInHere[1];
				midiDataGoesInHere[0] = 10;
				float* start = midiDataGoesInHere;

				juce::AudioSampleBuffer auBuff(&start, 1, 1);

				juce::MidiBuffer midiBuff;
				midiBuff.addEvent(juce::MidiMessage::noteOn(0, 50, (float)10), 0);

				plugin->prepareToPlay(441000, 512);
				plugin->processBlock(auBuff, midiBuff);
			}
		}
	}

Stepping through, I get to the following lines in processBlock:

for (i = effect->numOutputs; --i >= 0;)
                buffer.copyFrom (i, 0, outs[i], numSamples);

copyFrom then fails at

memcpy (channels [destChannel] + destStartSample,
                source,
                sizeof (float) * numSamples);

with the error:
An unhandled exception of type ‘System.AccessViolationException’ occurred in Audio2.exe

Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

Being a C# programmer in reality and this being my first foray into C++ in quite some time, I cannot figure out exactly what this memory error is. Perhaps the junk test data I am passing in is just inadequate? This particularly plugin (http://www.yohng.com/piano.html) has two outputs in case that is relevant.

Also, possibly not related, but I am not sure why VST instruments wants both MIDI input and float input?

Alsoooo, possibly bug in the JUCE code and possibly me not understanding something:
VSTPluginInstance::processBlock, the line ensureMidiEventSize (eventIndex), should it not be ensureMidiEventSize (eventIndex+1)?

Any help or suggestions greatly appreciated.


#2

So, that possible bug was just me being an idiot I’m reasonable sure, nevermind that.

Ok, I have a new, very slightly modified code snippet here:

juce::AudioPluginFormatManager::getInstance()->addDefaultFormats();
	juce::OwnedArray <juce::PluginDescription> typesFound;
	juce::KnownPluginList *list = new juce::KnownPluginList();
	juce::File *file = new juce::File("C:\\zeroseven\\AudioExperiment\\AudioExperiment\\refDLLs\\4Front Piano Module.dll");
	if(file->exists())	
	{
		if(list->scanAndAddFile(*file, true, typesFound))
		{
			const juce::PluginDescription *des = list->getTypeForFile(*file);		

			juce::VSTPluginFormat *format = new juce::VSTPluginFormat();

			juce::AudioPluginInstance *plugin = format->createInstanceFromDescription(*des);

			if(plugin->acceptsMidi())
			{
				float midiDataGoesInHere[2];
				midiDataGoesInHere[0] = (float)0.01556;
				midiDataGoesInHere[1] = (float)0.01556;;
				float* start = midiDataGoesInHere;

				juce::AudioSampleBuffer auBuff(&start, 2, 1);

				juce::MidiBuffer midiBuff;
				midiBuff.addEvent(juce::MidiMessage::noteOn(0, 32, (float)127), 0);

				plugin->prepareToPlay(441000, 512);
				plugin->processBlock(auBuff, midiBuff);
			}
		}
	}

Instead of crashing, I just get values of 0.000 in auBuff. I strongly suspect now I’m just making a managed coders error of some sort. Anyone have an idea?


#3

Well, you can’t just create a plugin object and blast data through it - they expect to get idle callbacks, and to be running in an environment where there’s an event loop running. They might have their own threads that need time to warm up. There’s probably other startup code needed too.

And giving it 2 samples to fill and expecting it to put something sensible in there is pretty optimistic! These things expect to be continuously called with big blocks to fill, and might not even start pumping out real data until a few samples down the line!


#4

I can understand your first couple of points, in particular callbacks which I remember seeing; I thought the AudioPluginInstance handled that itself automatically. I will go through the JUCE host sample again.

However in that same sample host application, you can send events through a plugin one at a time using the piano control. The plugins I am interested are using are VST intruments only, and I was under the impression they would be able, in general, to translate MIDI input (whether it be a single note or a stream of them) into something sounding more like a real effect.


#5

Well yes, that’s exactly what they do. But I’m not sure what results you expected to see in your 2-sample audio buffer?


#6

Expected magic to happen.

I guess I will go back up a level and try to get some more meaningful sample data before continuing. I was going to use C# MIDI toolkit (http://www.codeproject.com/KB/audio-video/MIDIToolkit.aspx) to retreive input from an external keyboard device to then pass down to a VST wrapper written in C++; I suppose I am more likely to get places if I have accomplished that first.


#7

So that toolkit is actually pretty easy to use, upon each key press of the external MIDI device I get a NoteOn channel message and each time a key is released a NoteOff channel message, including the channel, data1 and data2 of the MIDI event.
However, I still only get a single event for each press, which is what I expected. Now since the external keyboard has the ability to translate these events into something that sounds like a piano, guitar, or any of its other settings, I would assume this is enough data to feed through a VST intrument.
I guess my question is, how do I translate this event into samples to feed into a VST module through JUCE? Or even if I was to talk to a VST module directly. I had another look at the pluginhost example in JUCE but could not set it up correctly for this purpose.


#8

You do realise that juce has a whole bunch of classes to read the incoming events from external devices, and to get that data into the right format to send to a plugin, right? The idea of doing the same thing with a different toolkit written in a different language sounds like lunacy…


#9

I have realised that today, and not had the opportunity to understand it all yet, as I’ve been immersed in C# for too long. I guess my plan will be to take the juce host sample and strip it down to the bare bones of what I need.


#10

Hope you’re enjoying discovering things! Yes, using the host example as a starting point is definitely the best plan.