Best way to print values on Interface?

Hi,

for fast checking value, I usually print it on interface. This way:

labelToDisplay = std::to_string(filterGain); // this on audio code processBlock function; labelToDisplay is a AudioPluginAudioProcessor variable

...

void AudioPluginAudioProcessorEditor::paint(juce::Graphics &g) // this on PluginEditor
{
	g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));

	g.setColour(juce::Colours::white);
	g.setFont(15.0f);
	std::string value = "label: " + audioProcessor.labelToDisplay;
	g.drawFittedText(value, getLocalBounds(), juce::Justification::centred, 1);

	repaint();
}

but it become laggy/flashing, probably filled with other values during audio processing.

What’s the best way on doing this in JUCE?

don’t call repaint in paint but use a timer

Is Timer a class? Interface? Approch? Any fancy example?

It’s a juce class that you can inherit from, it works like this…

class MyClass : private juce::Timer
{
public:
    MyClass() { startTimerHz (30); }
    ~MyClass() { stopTimer(); }
    void timerCallback() override { // call repaint here }
}

https://docs.juce.com/master/classTimer.html

1 Like

It doesn’t work using this way (as you suggested):

class TimerRepaint : public juce::Component, private juce::Timer
{
public:
	TimerRepaint() { startTimerHz(30); }
	~TimerRepaint() { stopTimer(); }
	void timerCallback() override
	{
		repaint();
	}
};

It repaints nothing (I need to close/reopen the plugin GUI to refresh data).

Should I pass to the TimerRepaint class a reference of the AudioPluginAudioProcessorEditor? (which I prefer to avoid, keeping separations between roles and objects…)

you need to heritate your own class not use the one anthony provided :slight_smile:

1 Like

Done :slight_smile: It works.

Still, I still see “glitch” on the label I print on the GUI, such as “weird” symbols printed for few ms. Even it that labelToDisplay is valued only in the processBlock’s audio function. What’s wrong?

It’s likely a thread race, the string is partway through being updated when the repaint occurs.

It would be better not constructing the string in the processor, but just storing the value in an atomic and then pull that in and construct the string in paint.

1 Like

What happens if I don’t call stopTimer() in my destructor?

Will add that going forward…

If the object is created and destroyed on the Message thread it should be fine, if it’s not, there is a risk that a callback occurs during destruction, after (or during) the destruction of the derived class but before the destruction of the Timer base class. If this happens you’re in undefined behaviour territory! In general I would suggest it’s good practice to always call stopTimer() in the destructor of the derived class.

There is a jassert in the Timer destructor to try and catch misuse, unfortunately what I sometimes see is something like this…

class MyClass : private juce::Timer
{
public:
    MyClass() { startTimer (1); }
    void timerCallback() override 
    {
        stopTimer();
        // do something on the message thread
    }
}

The issue here is that the timer will have been stopped in MOST cases, but there is a rare chance of a bug, in this case it might happen during a scan of a plugin, potentially causing a hard to track bug that causes a plugin to get black listed.

2 Likes