Is there any special way to do that, or is it safe to pass data directly, ie. would this be a problem for some plugin formats?
In order to facilitate distributed plugins (such as web audio modules) and to transfer audio data/peak data safely from the high priority real-time audio thread iPlug2 includes a lock free SPSC (single producer-single consumer) queue class IPlugQueue. A helper class ISender sets up a queue for different types of data you might want to send to an IControl.
You create an instance of a particular variation of ISender as a member in your plugin class:
Then in ProcessBlock you can push data into the Sender’s queue, specifying the target control’s tag and channel offset of the data you want to send:
Then in OnIdle() (which you must override in your plug-in), you can call ISender::TransmitData() which will send the data to the control (on the main thread).
Thanks Oli! I will check this out.
I followed the IPlugControls example and figured out that I will need to add this to my custom control:
void OnMsgFromDelegate(int msgTag, int dataSize, const void* pData) override
{
if (!IsDisabled() && msgTag == ISender<>::kUpdateMessage)
{
IByteStream stream(pData, dataSize);
int pos = 0;
pos = stream.Get(&mBuf, pos);
SetDirty(false);
}
}
private:
ISenderData<2, std::array<float, 128>> mBuf;
It works nicely, but this is not what I need, unfortunately. I need to pass a continuous stream of audio to my custom control. In the iPlug1 that would be simple, just call control function from ProcessBlock, but I am not sure how to do that here. Should I do the same and lock the mutex? And if I do that what plugin formats would I break?
Does e.g. IScopeControl not do what you want?
It’s only if you want to build a “distributed” plugin that you absolutely need to use the messages system. Web audio modules need to be distributed, since audio processing is isolated in the audio worklet global scope. VST3 can be either distributed (separate vst3 processor and controller) or “Single Component Effect”. In the future LV2 may be distributed.
So if you don’t need those formats, you can still “get a pointer” to the IControl from the UI and share data from process block in a thread-safe way. That may require using a mutex, or some other mechanism, depending on what you need to do.
IVScopeControl doesn’t do what I want.
OK, that clears up the situation for plugin formats.
Theoretically, if I set IBufferSender QUEUE_SIZE and MAXBUF to some big value like 65536, I would get continuous buffer with 60fps graphics?
not really sure what you mean
MAXBUF is the number of samples to buffer before pushing it onto the queue. If you set that really high there could be some latency on your visualisation. If it is too low then you can end up sending too many messages and it might use too much CPU. If you’re pushing lots of data onto the queue very quickly it might not get popped off fast enough, so thats where QUEUE_SIZE comes in. I have to think about QUEUE_SIZE a bit, maybe the default of 64 is too high.
Thanks. That explains how things work. I thought it works in a different way.
So,
ProcessBlock is called on audio thread
OnIdle is called on GUI thread
OnMsgFromDelegate should be called on GUI thread
How wrong would it be to call TransmitData inside ProcessBlock instead of OnIdle?
very wrong! that is not the way it is designed. You don’t want to end up calling into the GUI/controls on the audio thread
OK, got it. Thanks Oli!
what about if I wanted a scope plotting, for example, lots of network data - stuff that isn’t in the ProcessBlock. Could I use the messaging system to visualise (or in the future possibly even sonify) network data in a thread safe way?
The ISender should work also if you need to pass data from a networking thread to UI controls.