How do you access an MPE Synthesiser from the Plugin Editor (ie. to debug variable values out into display)

I am trying to get access to my MPE Synthesiser from the Plugin Editor. My goal is to try to access some variables from the voices of the MPE Synthesiser from the Plugin Editor so that I can display their values in the GUI.

I thought the best way was to run a function once during each processBlock in the processor that triggers the Editor to run look the voices and get the pertinent variables to update them in the GUI.

My main relevant structural elements are:

PluginProcessor.h/cpp

*/
class AudioPlugInAudioProcessor
:   public AudioProcessor,
    public AudioProcessorValueTreeState::Listener
{

private:
    MPESynthesiserInherited mMpeSynth;

PluginEditor.h/cpp

class AudioPlugInAudioProcessorEditor
	: public AudioProcessorEditor,
	public Button::Listener
{...

private:
    // This reference is provided as a quick way for your editor to
    // access the processor object that created it.
    AudioPlugInAudioProcessor& processor;

Here’s what I’m trying to do:

PluginProcessor.h/cpp

/**standard processBlock */
void AudioPlugInAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
{
	const ScopedLock renderLock(lock);
    ScopedNoDenormals noDenormals;
	buffer.clear();
	mMpeSynth.renderNextBlockCustom(buffer, midiMessages, 0, buffer.getNumSamples());

	//UPDATE GUI DEBUG HERE
	AudioPlugInAudioProcessorEditor* activeEditor = (AudioPlugInAudioProcessorEditor*)getActiveEditor();
	activeEditor->updateDebugWindow();
}

/**return MPE Synth */
MPESynthesiserInherited* AudioPlugInAudioProcessor::getMPESynthPtr() { 
	return &mMpeSynth;
}

PluginEditor.cpp

void AudioPlugInAudioProcessorEditor::updateDebugWindow() {

	MPESynthesiserInherited* mpeSynthPtr = processor.getMPESynthPtr();
	int numTotalVoices = mpeSynthPtr->getNumVoices();
    //access the voices and get the variables so can display them on GUI
	...
	

So in other words, as I understand it, AudioPlugInAudioProcessor automatically creates a PluginEditor which I can then access from the processor via getActiveEditor(). This seems to work okay, because I am able to successfully trigger the Editor’s updateDebugWindow() in the processor from the processBlock.

However, the updateDebugWindow function in the editor is not able to access the MPESynth to get the data I want from it. I keep getting “Exception thrown: read access violation.
this was nullptr.” at the line MPESynthesiserInherited* mpeSynthPtr = processor.getMPESynthPtr();

I am not sure why this is.

I am not the best at transferring and accessing data between classes like this. Is there something obvious I am doing wrong? Is there a more appropriate way to get some variables out of my MPESynth & its voices for displaying in the GUI?

Thanks for any help. Given my weakness in this domain, if you can be specific it will likely help. ie. Please talk to me like I know nothing because it’s likely not far off. :stuck_out_tongue:

Thanks

If you need to access some data held in the processor from within the editor, ideally you would create a function within your processor to return said data. I don’t see any reason to be passing pointers to your whole synth back and forth…

IMHO the ideal way to implement this, from the point of view of your pluginEditor.cpp, would be a call as simple as this:

int numTotalVoices = processor.getNumVoices();

To implement this function in your pluginProcessor.h, I would do this:

int getNumVoices() const { return mMpeSynth.getNumVoices(); };

If you need data in the editor that’s held in an individual voice of the synthesiser, then implement a function in your MPESynthesiserInherited class that returns the data, so that the top-level function in your processor is:

returnTypeWhatever getSomeData() const { return mMpeSynth.getSomeData(); };

and then inside your MPESynthesiserInherited class, that function might look like

returnTypeWhatever getSomeData() const { return voice->getSomeData(); };

… so there would again be a function within the MPESynthVoice subclass to return this data.

Hopefully this makes sense.

also, don’t do this!!

The processBlock() should be just for rendering the audio output, so that it can happen as quickly as possible.

I would make your editor inherit from the Timer class, and implement a TimerCallback method. This way, the message thread can update its own GUI instead of clogging up the audio callback with doing GUI stuff.

in your PluginEditor.h:

class AudioPlugInAudioProcessorEditor: public AudioProcessorEditor,
	                                   public Button::Listener,
                                       public Timer

public:

void timerCallback() override;

In your PluginEditor.cpp:
add this line to the body of your constructor:

Timer::startTimerHz(60); // this will give you a framerate of 60 FPS on your graphics updates

and add this line to your destructor:

Timer::stopTimer();

Then implement this method:

void AudioPlugInAudioProcessorEditor::timerCallback()
{
    updateDebugWindow(); // you can keep activities like "updating the debug window" grouped into their own functions and just call them from your timer callback
};
1 Like

Thanks Ben. That’s very logical. I tried it. However it’s still giving me the same error strangely in the editor.

So I tried:

MPESynthesiser:

int returnNumVoicesTemp() {
		return 2;
	}

PluginProcessor:

int returnTempVoices() {
		return mMpeSynth.returnNumVoicesTemp();
	}

PluginEditor:

void AudioPlugInAudioProcessorEditor::updateDebugWindow() {
	int tempInt = processor.returnTempVoices();
...

And again at this level of processor.returnTempVoices(); it tells me “Exception thrown: read access violation. this was nullptr.”

My Synthesiser can access its voices, my PluginProcessor can access my synthesiser, but my PluginEditor can’t get anything I need from the processor.

Any ideas why my Editor cannot get these basic things? Both approaches (my original and your suggestion) seem to be triggering the same error.

Thanks.

Did you implement this using a timer callback?

If you’re still doing weird stuff with trying to call getActiveEditor() from the processBlock, that could be why

1 Like

within the processBlock, getActiveEditor() can sometimes return a nullptr if there is no active editor.

So my guess is that your exception is being thrown on the line

activeEditor->updateDebugWindow();

within your processBlock, because it’s trying to dereference a nullptr.

1 Like

Oh sorry Ben. I missed that reply of yours. Yes I was still doing it with the process block so that was obviously the wrong way and the reason.

I tried your Timer method and it works perfectly now (even with my original pointer method to access the synth).

Thanks for chatting and replying so quickly. Thank you also for being so clear about how to implement the Timer method as well as that made it easy. Very very helpful. Appreciated.

:slight_smile:

1 Like

You’re welcome!

1 Like

you certainly can do this, if you need to retrieve lots of different kinds of data in different places in your editor…

If you’re certain that the lifetime of the MPEsynth object is the same as the lifetime of your processor itself (ie won’t get deleted while your plugin is still running), then you could store a reference to your MPEsynth object in your editor and initialize it with a constructor argument…

(this is exactly the same way that the reference to the audioProcessor is automatically created & stored in the editor)

in PluginEditor.h:


class AudioPlugInAudioProcessorEditor: 
{
public:
    MPESynthesiserInherited& activeMPEsynth; 

    AudioPlugInAudioProcessorEditor(AudioPlugInAudioProcessor& p, MPESynthesiserInherited& s);
}

in PluginEditor.cpp:

AudioPlugInAudioProcessorEditor::AudioPlugInAudioProcessorEditor(AudioPlugInAudioProcessor& p, MPESynthesiserInherited& s):
    processor(p), activeMPEsynth(s)
{
    // ...body of your constructor...
}

then, in pluginProcessor.cpp, find the function createEditor() and edit it like so:

juce::AudioProcessorEditor* AudioPlugInAudioProcessor::createEditor()
{
    return new AudioPlugInAudioProcessor(*this, mMpeSynth);
};

This way, your editor will automatically have the synth reference available for you to use and you don’t have to do any kind of pointer-getting, and you also wouldn’t have to access the processor directly at all. Now your updateDebugWindow() function can look like this:

void AudioPlugInAudioProcessorEditor::updateDebugWindow() 
{
    int numTotalVoices = activeMPEsynth.getNumVoices();
}