Notifying Controller of Events

What is the recommended way to notify the Controller of MIDI events from the Processor class ?

For example with every note on event, I want to update the UI to show the name of the pressed key in a label. How can I go about achieving this ?

Is there any code example in the samples or else where where one can see this in action ?
I saw vuPPM code in Again but that handles parameter changes. I am looking for ways to handle events.
I looked at the keyboard implementation hoping to see it highlight note on events on the keyboard in a different color but it does not seem to be aware of external MIDI events

1 Like

You can use the iNotify interface to send messages between them, here’s one way I’ve done it to send a peak level to the controller:

			Steinberg::Vst::IMessage* message = allocateMessage();
			if (message)
				{
				message->setMessageID("peakAudioLevel");
				message->getAttributes()->setFloat("peakValue", level);
				sendMessage(message);
				}

then you need a receiver in the receiving end (controller)

tresult controllername::notify(Steinberg::Vst::IMessage* message)
{
string mID = message->getMessageID();
if (mID == "peakAudioLevel")
          {
           double audioLevel;
           if (message->getAttributes()->getFloat("peakValue", audioLevel)  == kResultTrue)
                  {
                             //do something
                   }
           }
message->release();
return kResultOk;
}

Hope this helps

1 Like

The only “catch” is that the message sending (on the RT side) must be done on the different thread.

Source

If you should need to exchange more data than just parameter changes, such as tempo, sample rate, FFT, Pitch Analysis, or any other data resulting from your processing, you can use the IMessage interface (see AGain example). However, you need to be careful and send the data from a ‘timer’ thread and not directly from the process function, for example, when sending from a ‘process’ call.

1 Like

thanks a lot. Very helpful insights :slight_smile:

1 Like

So does this imply that the simply implementing iNotify interface is not the solution and that I need to manually spawn a new thread using std::thread and then join at the end ? Can you please share some example on this ?

1 Like

In my case yes I just spawn a thread with

std::thread sendThread{ [&](double lev)
		{
			Steinberg::Vst::IMessage* message = allocateMessage();
			if (message)
				{
				double lev2 = lev;
				message->setMessageID("peakAudioLevel");
				message->getAttributes()->setFloat("peakValue", lev2);
				sendMessage(message);

				}
		}, (double)level};
	sendThread.detach();

but it does work without, it’s just not recommended as handling the message may take too long and thus interrupt processing.

1 Like

Wow thanks for the lightning-fast reply and clear cut explanation !!

1 Like

Thanks. I’ve found there’s not much help with this SDK available and so I’m trying to do my part if I can. But I’m no expert. I’ve come to really appreciate the depth of documentation one gets from the likes of Microsoft. With VST3 I find myself constantly trying to figure out how to invent the wheel😬

This forum is disappointingly inactive but maybe people just give up due to the silence.

By the way you also need this in your controller.h and processor.h

	Steinberg::tresult PLUGIN_API notify(Vst::IMessage* message) SMTG_OVERRIDE;

Just for completeness/anyone else reading this thread.

1 Like

Ah yes, I totally relate to that. With scant documentation progressing with my first attempt at some serious plugin work is slower than I would have liked it to go .

I almost forgot about this thread. Then after posting and not getting any replies, I started working on some other aspects of my plugin hoping to get back at this at some later point of time.

Thanks again.

1 Like

@spoonman2 May I ask how/where you spawn that sendThread?

I have tried similar approach creating a std::thread, detach it and sleep for some milliseconds for every callback but I get failing tests from the validator so it ends up with a build error for me

1 Like

Sure, in my case I just have a function called in processor.cpp which then runs the above code. Not sure if this will help in your case?

So

void PD10_FirstGoProcessor::sendPeakAudioLevel(Vst::Sample32 level)
{
	std::thread sendThread{ [&](double lev)
		{
			Steinberg::Vst::IMessage* message = allocateMessage();
			if (message)
				{
				double lev2 = lev;
				message->setMessageID("peakAudioLevel");
				message->getAttributes()->setFloat("peakValue", lev2);
				sendMessage(message);

				}
		}, (double)level};
	sendThread.detach();
}

which in my case is called after the audio processing of the chunk is done from inside the ::process call. This earlier code also worked:

void PD10_FirstGoProcessor::sendPeakWarning()
{
	Steinberg::Vst::IMessage* message = allocateMessage();
	if (message)
	{
		message->setMessageID("peakWarning");
		message->getAttributes()->setFloat("peakValue", 1.0);
		sendMessage(message);

		std::thread tmrThread{ [=]
			{
					cancelPeakWarning();
			} };
		tmrThread.detach();
		
	}

}

void PD10_FirstGoProcessor::cancelPeakWarning()
{
	std::this_thread::sleep_for(std::chrono::milliseconds(100));

	if (AHFoo.peakFlag == false)
	{
		Steinberg::Vst::IMessage* message = allocateMessage();
		if (message)
		{
			message->setMessageID("cancelPeakWarning");
			message->getAttributes()->setFloat("peakValue", 0.0);
			sendMessage(message);
		}
	}

}

Which created a thread for a later function to send a message cancelling the peak audio warning. Any use to you?

Thanks man, I got it working now!

I was trying to create the thread in another function/thread in the Processor class. Which does not make any sense for what I want to do. Your reply inspired me to put the thread creation inside the process function call and it worked immediately

/Erik

1 Like

Glad to have helped :slight_smile:

I’m afraid, this is not the solution. You should not create a thread inside the process function. To better understand what is allowed inside the process function read this nice blog post about it.

I suggest you use read-only parameters for this. This kind of parameters are perfect for this. You don’t have to worry about threading issues and as a bonus parameters are synced to the audio.

@Arne_Scheffler this only works if the amount of data you need to communicate is a) small b) can be represented as a value between [0, 1] (which is what vst3 parameters are limited to). That would obviously work for just sending a “peak value”.

If the controller and processor are on the same computer you can misuse a read-only parameter to transmit ordinary 64bits to the controller. But sure if you want to be prepared for the case that the controller is not on the same machine as the processor than you’re right.

The next SDK update contains a solution for sending data (even big amount of data) from the realtime context to the controller in an easy and safe way.

2 Likes

Oh wow. Can’t wait!

Sounds awesome!! Will there be any example plugin that utilizes that new solution that we can look at?

Wait and see :wink:

1 Like