ASPiK SDK
Cache the ICustomView Pointers

With the PlugingGUI code modified to decode, create and register the custom views, we can add the last part to this project - picking up and saving the registered custom view interface pointers, and then using them to pump audio data into the views. We'll use the knob view to show how to talk to the objects.

In the plugincore.h file we declare some pointers to store the registered ICustomView interfaces. Remember that ASPiK guarantees that these pointers will never go out of scope or become invalid after registration (the plugin shell objects handle this chore). In addition, the core object never needs (or is allowed) to delete these custom view interface pointers, so there is no added maintenance. You just register the pointers and use them - that's it. The pointers are added along with the rest of the user code in the declaration of the PluginCore object. We declare three pointers and one lock free ring buffer which will be used to store audio samples prior to their shipment out to the custom views.

class PluginCore : public PluginBase
{
  // SNIPPPED code...
  // — BEGIN USER VARIABLES AND FUNCTIONS -----------------------------------— //
  // Add your variables and methods here
  // — custom view declarations
ICustomView* waveView = nullptr;
ICustomView* spectrumView = nullptr;
ICustomView* knobView = nullptr;

  // — lock free ring buffer
moodycamel::ReaderWriterQueue<float, 512> customViewDataQueue;

}

The next step is to pick up these pointers when the native plugin shell registers them with the plugin core object. This is done in the plugincore.cpp file inside of the PluginCore::processMessage( ) which handles GUI events from the native plugin shell (don't worry, this is thread-safe). There are numerous messages that are decoded in this function, but we only need to deal with a couple of them:

PLUGINGUI_REGISTER_CUSTOMVIEW: this message is sent once per custom view, each time the GUI is opened. Once you have stored a custom view interface pointer, you don't need to ever re-copy or re-store it. However this function WILL be called when the GUI is opened so you can use it (in part) to know a bit about the lifecycle of the GUI.

PLUGINGUI_TIMERPING: this message is sent on every GUI update interval (50 msec) and is called from the GUI thread. This is where we will feed audio samples into the custom views and call the methods to update (repaint) these windows. Since this function is called from the GUI thread, we need that lock-free ring buffer on our plugin side to hold audio data from the audio processing thread.

To pick up and store the interface pointers, you modify the code for the PLUGINGUI_REGISTER_CUSTOMVIEW to decode the incoming name string and store the pointer. This code is just for the two custom audio viewers; we'll address the custom knob later. User the example below to see how the pointers are passed into the message system - make sure you understand this if you want to modify it for your own custom messaging or other uses.

bool PluginCore::processMessage(MessageInfo& messageInfo)
{
// code snipped out
case PLUGINGUI_REGISTER_CUSTOMVIEW:
{
 // — decode name string
if (messageInfo.inMessageString.compare("CustomWaveView") == 0)
 {
  // — (1) get the custom view interface via incoming message data*
  if (waveView != static_cast<ICustomView*>(messageInfo.inMessageData))
   waveView = static_cast<ICustomView*>(messageInfo.inMessageData);

  if (!waveView) return false;

  // — registered!
return true;
  }

if (messageInfo.inMessageString.compare("CustomSpectrumView") == 0)
 {
  // — (1) get the custom view interface via incoming message data*
  if (spectrumView != static_cast<ICustomView*>(messageInfo.inMessageData))
   spectrumView = static_cast<ICustomView*>(messageInfo.inMessageData);

 if (!spectrumView) return false;

 // — registered!
return true;
 }