Generating MIDI messages in a VST plugin?

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

Hello, KVR! Long time, no post.

I'm having trouble with generating MIDI messages in my VST plugin (I use C++). I have the following processEvents() function implemented that takes an input note from the host and gives it right back.

Code: Select all

long MIDIGen::processEvents(VstEvents* ev){
	for (long i=0; i<ev->numEvents; i++){
		if ((ev->events[i])->type!=kVstMidiType)
			continue;

		event=(VstMidiEvent*)ev->events[i];
		
		midiDataChar=event->midiData;
		long status=midiDataChar[0]&0xf0;

		if (status==0x90||status==0x80){
			ev->events[i]=(VstEvent*)event;
			sendVstEventsToHost(ev);
		}
		event++;
	}
	return 1;
}
This is working perfectly! However, how do I get the plugin to generate a MIDI message without needing an input? For testing purposes, I have a "Power" control in my plugin and want a middle-C note to be created when the control is at or above 50%. I have what follows in my process()/processReplacing() function ("genNote" is VstMidiEvent struct, "test" is VstEvents).

Code: Select all

if (fPower>=0.5f){
	genNote[0].type=0;
	genNote[0].midiData[0]=90;
	genNote[0].midiData[1]=60;
	genNote[0].midiData[2]=127;
	genNote[0].midiData[3]=0;
	genNote[0].reserved1=99;
	genNote[0].deltaFrames=-99;
	genNote[0].noteLength=100;
	genNote[0].noteOffset=0;

	test->events[0]=(VstEvent*)genNote;
	sendVstEventsToHost(test);
}
In my host, when the power is at or above 50%, the plugin crashes! I'm certain that the "genNote[0].midiData[0]=90;" statement is incorrect. What is the correct status value supposed to be? Is "genNote[0].type" supposed to be 0? Help me!

Thnx for reading!

Post

swound wrote:In my host, when the power is at or above 50%, the plugin crashes!
It is hard to say what might causing the crash without seeing the rest of the code ... here are some investigative questions that come to mind:

Have you pinpointed the location of the crash? Is it before the call to sendVstEventsToHost() or after? Is the memory for your data structures (genNote, test, test->events[]) allocated and available for use? What is the value of test->events.numEvents?

Post

swound wrote:

Code: Select all

	genNote[0].deltaFrames=-99;
Also, I don't recall, but is deltaFrames allowed to be negative?

Post

swound wrote:

Code: Select all

long MIDIGen::processEvents(VstEvents* ev){
	for (long i=0; i<ev->numEvents; i++){
		if ((ev->events[i])->type!=kVstMidiType)
			continue;

		event=(VstMidiEvent*)ev->events[i];
		
		midiDataChar=event->midiData;
		long status=midiDataChar[0]&0xf0;

		if (status==0x90||status==0x80){
			ev->events[i]=(VstEvent*)event;
			sendVstEventsToHost(ev);
		}
		event++;
	}
	return 1;
}
This is working perfectly! However, how do I get the plugin to generate a MIDI message without needing an input? For testing purposes, I have a "Power" control in my plugin and want a middle-C note to be created when the control is at or above 50%. I have what follows in my process()/processReplacing() function ("genNote" is VstMidiEvent struct, "test" is VstEvents).

Code: Select all

if (fPower>=0.5f){
	genNote[0].type=0;
	genNote[0].midiData[0]=90;
	genNote[0].midiData[1]=60;
	genNote[0].midiData[2]=127;
	genNote[0].midiData[3]=0;
	genNote[0].reserved1=99;
	genNote[0].deltaFrames=-99;
	genNote[0].noteLength=100;
	genNote[0].noteOffset=0;

	test->events[0]=(VstEvent*)genNote;
	sendVstEventsToHost(test);
}
In my host, when the power is at or above 50%, the plugin crashes! I'm certain that the "genNote[0].midiData[0]=90;" statement is incorrect. What is the correct status value supposed to be? Is "genNote[0].type" supposed to be 0? Help me!
Some of your answers are in the sample working code. Compare the values in your NoteOn/NoteOff check in the working sample code against the status value you are setting. (hint: decimal vs hex). Same for the genNote[0].type value. Compare to the value used in the sample code ..

Post

this. and how often is processReplacing() called from your VST host? Assuming fs=44100 and numSamples~100 processReplacing will be called > 400 times/second creating lots of midi messages.

Post

OK, I've returned with an update: the plugin no longer crashes, but still doesn't work correctly.

After some debugging, I've found the root of the problem. So, "ev" and "test" are both VstEvents. When ev is called in the plugin (which is the host-generated VstEvents), the debugger shows a value of 0x03143420 {numEvents=1 reserved=0 events=0x03143428}, but when test is called (the plugin-generated VstEvents), the value is reported as 0x00000000 {numEvents=??? reserved=??? events=0x00000008} (comparing the VstMidiEvents "event" and "genNote" yields similar results). Does this mean that memory for test and genNote isn't being allocated? In the constructor, I have "genNote=new VstMidiEvent; test=new VstEvents;" Is this not the correct allocation method?

Post

swound wrote:OK, I've returned with an update: the plugin no longer crashes, but still doesn't work correctly.

After some debugging, I've found the root of the problem. So, "ev" and "test" are both VstEvents. When ev is called in the plugin (which is the host-generated VstEvents), the debugger shows a value of 0x03143420 {numEvents=1 reserved=0 events=0x03143428}, but when test is called (the plugin-generated VstEvents), the value is reported as 0x00000000 {numEvents=??? reserved=??? events=0x00000008} (comparing the VstMidiEvents "event" and "genNote" yields similar results). Does this mean that memory for test and genNote isn't being allocated? In the constructor, I have "genNote=new VstMidiEvent; test=new VstEvents;" Is this not the correct allocation method?
It looks like the test and genNote pointers are getting nulled somehow between the time they are initialized and the time they are being used. Hard to say how that might occur without the full code context. Are you also allocating the array of test->events[] somewhere?

FYI .. Here is a thread that talks about allocating the VstEvents structure: http://www.kvraudio.com/forum/viewtopic.php?t=214049

Post

Whoa, nevermind, I thought it wasn't working but just tried it again and it is! COOL!

In case anyone else is having similar trouble with this sort of thing, here's some C++ code for a VST plugin that turns on a middle-C MIDI note at full velocity and then turns it off, at half-second intervals (assuming you're at a 44.1 kHz sample rate):

Code: Select all

genMidiNote=new VstMidiEvent;
noteEvent=new VstEvents;

// initialize values
countDown=44100;
genMidiNote->type=kVstMidiType;
genMidiNote->byteSize=24;
genMidiNote->deltaFrames=0;
genMidiNote->noteLength=0;
genMidiNote->noteOffset=0;
genMidiNote->midiData[1]=60; // middle c
genMidiNote->midiData[3]=0;
genMidiNote->detune=0;
genMidiNote->reserved1=0;
genMidiNote->reserved2=0;

Code: Select all

while(--sampleFrames>=0){
	countDown--;
		
	if (countDown==22050){
		noteEvent->numEvents=1;
		genMidiNote->midiData[0]=0x90; // status byte: turn on midi note in channel 1
		genMidiNote->midiData[2]=127; // full velocity
		noteEvent->events[0]=(VstEvent*)genMidiNote;
		sendVstEventsToHost(noteEvent);
	}

	if (countDown==0){
		noteEvent->numEvents=1;
		genMidiNote->midiData[0]=0x80; // status byte: turn off midi note in channel 1
		genMidiNote->midiData[2]=0; // no velocity
		noteEvent->events[0]=(VstEvent*)genMidiNote;
		sendVstEventsToHost(noteEvent);
		countDown=44100;
	}
}
Happy audio-ing! :phones:

Post

In the code in your first post, in processEvents() you modify the VstEvents* that was given to you by the host. This is asking for trouble.
The VST specification doesn't say that you can't, but typically, hosts will expect you to live this data alone (this method should really have been defined with a const VstEvents* in the spec)

Post Reply

Return to “DSP and Plugin Development”