This project has moved and is read-only. For the latest updates, please go here.

PluginCommandStub.ProcessEvents real time

Feb 11, 2011 at 12:17 AM
Edited Feb 11, 2011 at 12:19 AM

Hi,

Great work obiwanjacobi this has project been very useful, but I am currently having a problem wuth the _plugin.PluginCommandStub.ProcessEvents method that I'd like some feedback on.

OPTION A
Essentially when played in 'real time' (pushing midi events through as they are received from a keyboard) it is not playing all the notes that should be heard - specifically it is missing notes that are parts of a chord. So if pass through C4, E4 and G4 sometimes you only hear one of the notes.

All note-on and note-off messages are being passed to the process events function individually as follows:

 evt = new Jacobi.Vst.Core.VstMidiEvent(0, 0, 0, new byte[] { 144, (byte)e.Message.Data1, velocity }, 0, 0);
 _plugin.PluginCommandStub.ProcessEvents(new VstMidiEvent[] { evt });

I have run debugging code in this method and all events are hitting this part of the code.

OPTION B
However, if I group the events over a short space of time (determined by the buffer) in a VstMidiEvent array when they are received from the keyboard and then pass the whole array to the VST instrument at the same time as requesting the next bytes from the instrument, I do hear all of the notes, but this is slightly reducing the sound quality.

This works as follows:

FOR EACH ON/OFF MIDI EVENT HEARD (in 'real time'):
evt = new Jacobi.Vst.Core.VstMidiEvent(0, 0, 0, new byte[] { 144, (byte)e.Message.Data1, velocity }, 0, 0);
lock (midiEvents)
{
 midiEvents.Add(evt);
}

THEN AT THE SAME TIME AS REQUESTING THE AUDIO:
lock (midiEvents)
{
    _plugin.PluginCommandStub.ProcessEvents((VstMidiEvent[])midiEvents.ToArray(typeof(VstMidiEvent)));          
    midiEvents.Clear();
}
float[] vstData = AudioHelper.getVSTAudio(_plugin, inManager, outManager);


IDEALLY
I would ideally like the first option to work as it should produce slightly smoother playback. Please could you let me know if there is an issue with passing through individual events in 'real time' to the ProcessEvents method or if it should work smoothly and there is something I am missing?

Thanks :)

Feb 11, 2011 at 6:35 AM

Thanx!

So you're building a VST Host application and you want to pass a plugin some midi events, right.

Well, from what I understand the idea of ProcessEvents is that it is called right before calling Process (audio). I think all plugins are build on the premise.
So I can understand that plugins do not handle multiple calls to ProcessEvents very smoothly - they're probably not designed to handle that.

The idea is that an instrument receives the midi information just before it is asked to render the audio for those events - for the specific time slice (audiobuffer) that is being 'played'. So in a real-time scenario you -as a host- have to collect all midi events and push them in small batches for the current time slice using ProcessEvents. Directly after that you call Process to render the audio.

That is how I understand the VST specs. Because rendering audio is always in batches (size of audio-buffer) the midi events have to match it. For better performance you could try to use smaller buffers - assuming you are able to provide and process them fast enough...

Hope it helps.
Marc

Feb 11, 2011 at 6:43 AM

I have read somewhere that some plugins, (including reaktor specifically) expect the host to buffer all midi events and send them with processEvents just before callling processReplacing. To increase plugin compatibility, even if you don't have any midi event buffered you should still call processEvents just before calling processReplacing. What's your audio latency? I think buffering events with a 512 samples latency should provide pretty smooth playback.

Feb 11, 2011 at 6:48 AM

Well, it seems odd to me to call processEvents on a plugin that doesn't support midi..???

Perhaps you should ask this question on kvraudio forum? There a lot of devs there that have more experience that me ;-).

Feb 12, 2011 at 12:22 AM

Just to clarify, I was not suggesting sending midi event to a plugin who doesn't support them. I meant that if a plugin supports midi event (CanDo) it might help to send an empty/dummy midi message before calling processReplacing if you don't have real midi event scheduled. The reason is that some plugins do some operations in processEvents that helps processReplacing run smoothly.

Feb 21, 2011 at 2:59 AM

Thanks for your responses to this. I've now reverted it back to grouping the midi events and requesting the audio at the same time. It's working well and we can work with buffer sizes etc for tweaking.