Plugin crash when trying to reference AudioBuffer

It sounds like you were on the right track by storing a processor reference in your component class, like the plugin editor class does. (This is what MutineerAudioProcessor& processor; in your header is doing, the & denotes that it is a reference).

When you got the “no default constructor exists for class WaveformOutput” error, this is because you changed the constructor of your WaveformOutput class to take an argument where before it took none. So you just need to pass the processor instance to your WaveformOutput object in the initializer list of the plugin editor, and I think you’ll be good to go:

class PluginEditor : public juce::AudioProcessorEditor
{
public:
    PluginEditor (MutineerAudioProcessor& p)
        : waveformOutput (p) /* passes the processor to the WaveformOutput constructor */
    {
    }

private:
    WaveformOutput waveformOutput;
}
1 Like

Thank you very much for that guidance. Now in your opinion, what would be the reasons to do it like I tried and you corrected, other than more “proper”, less “ugly”. I mean would there be a memory advantage? Or more to the point, by storing the buffer memory differently, would it make my GUI graph plot component any faster because it accesses the memory closer to itself?

I’m not totally sure which approaches you’re comparing. Are you asking why you would store the buffer as a class member instead of using a global variable?

If so, it has nothing to do with memory optimization or performance, but is rather about having code that is easy to understand and easy to use, while making it as hard as possible to misuse! Global variables provide more opportunities to “shoot yourself in the foot” compared to making something a class member, so I prefer to avoid globals if at all possible.

I was comparing the “processor reference” approach you commented on, and my “horrible” way of doing it with a global variable. It is my goal to eventually take the time to better learn C++, right now however it is way to much fun to keep create unique sounds using DSP with what I know and for me obviously works, and I am here referring to my synthesizer Mutineer.

As I am currently refactoring my synth to be rid of global variables, except for a handful that are truly global across multiple plugin instances, I finally took a moment to figure out how to access data across a few classes using a pointer. Now you “youngsters” were probably spoon fed with pointers, however for an old timer like me, who back in 1981’s first programming experience was assembly language, then Basic, it was a bit confusing.

Anyways so I needed to copy audio buffer data into a shared buffer, which I could access in a plot component part of PluginEditor. Here is how I solved it, in case somebody will find it useful. Note I am fully aware that it could perhaps have better.

File PlotData.h;

// Shared plot Data; Data gain, Windows Width, Data Ready Flag, and Sample Buffer
// Below buffer size, height, and width are just default, as there are set on plot 
// component's resized.
class PlotData {
public:
    PlotData ()
    {
        outputPlotBuffer.setSize (2, 200, false, true, false);
    }

    float plotHalfHeight = 100;	// Used in PluginProcessor as gain for audio data  
                                // before being used by WaveformOutput plot function.
    int plotWidthInt = 200;		// Width of plot window
    int readSampleData = 0;		// 1 = Editor On, 2 = Get Plot Data, 4 = Plot Data, 
                                // 8 = Output focus

    AudioBuffer<float> outputPlotBuffer;
};

File PluginProcessor.h

...
public:
...
  PlotData plotData;
...

File PluginEditor.cpp in the constructor, before I addAndMakeVisible my WaveformOutput component, I pass it a reference to the plotData object.

waveformOutput.passPlotDataPtr (&processor.plotData);

File WaveformOutput.cpp;

void WaveformOutput::passPlotDataPtr (PlotData* ptr)
{
	plotDataPtr = ptr;
}

void WaveformOutput::timerCallback ()
{
	if (plotDataPtr->readSampleData & 4) repaint ();
}

void WaveformOutput::paint (Graphics& g)
{
  ...
  // Plotting a scheme here...

  // At end of plotting, I set plotDataPtr->readSampleData to "Get Plot Data"
}

void WaveformOutput::resized ()
{
    ...
    plotDataPtr->plotWidthInt = plotWidth;

	plotDataPtr->plotHalfHeight = float ((getHeight () - 2) / 2);

	plotDataPtr->outputPlotBuffer.setSize (2, getWidth (), false, true, false);
    ...
}

Then in PluginProcessor.cpp at end of processBlock, I check the plotData readSampleData flag and if the editor is open.

If it is and there is audio data, set flag to “get data” and “output focus”, then copy audio buffer to plotdata buffer, numSamples = plot width, and gain = half plot height. I then set readSampleData flag to “plot data” which via a Value listenable variable in pluginEditor start the timer containing a repaint() in my WaveformOutput.cpp component.

If there is no more audio data, I set the Value listenable variable so that the WaveformOutput.cpp’s timer stops.

File PluginProcessor.cpp;

float magnitude = buffer.getMagnitude (0, buffer.getNumSamples ());
	
	// Transfer audio buffer to visual plot buffer
	if (plotData.readSampleData & 1)
	{
		if (magnitude > 0.001f)
		{
			plotData.readSampleData |= 10;

			plotData.outputPlotBuffer.copyFrom (0, 0, buffer.getReadPointer (0), 
                plotData.plotWidthInt, plotData.plotHalfHeight);
			plotData.outputPlotBuffer.copyFrom (1, 0, buffer.getReadPointer (1), 
                plotData.plotWidthInt, plotData.plotHalfHeight);

			// Set flag to Plot data and start output timer in WaveformOutput.cpp
			plotData.readSampleData |= 4;

			startRealTimeOutputPlot.setValue (true);
		}
		else // Stop output timer in WaveformOutput.cpp
		{
			startRealTimeOutputPlot.setValue (false);
		}
	}