VU Meter to fast (glitchy no envelope follower) and repainting all graphics


#1

Hello audio developers!

I have a feeling that making the VU meter is a way of weeding out the idiots who are in way over their heads. As it could be built into the framework easily. I’m one of those idiots, already painted the meter upside down :upside_down_face:, but I’m a persistent one. (first c++ project).

I have a simple VU Meter that’s semi working. Only I’m a bit puzzled at how to do the envelope follower because now it’s unusable, glitchy and innacurate. Where can I find info on this?

I also want to only repaint the part of the VU meter that get’s changed instead of the whole AudioProcessorEditor::paint. But unshure of how to do this. Right now I call the repaint() function from inside my AudioProcessorEditor::timerCallback(). But I want to call another function for example: void LevelMeter::paint(Graphics& g). And I have no clue how to actually call it…

Code:
PluginEditor.cpp

void G2mAudioProcessorEditor::paint (Graphics& g)
{
// (Our component is opaque, so we must completely fill the background with a solid colour)
g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));

g.setColour (Colours::white);
g.setFont (15.0f);

g.drawRect(10, 5, 55, 233, 1);
g.setColour(Colours::green);
g.fillRect(11, 5, 53, 233);
g.setColour(getLookAndFeel().findColour(ResizableWindow::backgroundColourId));
int heightInt = (int)lastInputLvl * (-2.33);
g.drawText(String(heightInt), 10, 249, 237, 15, true);
g.fillRect(11, 5, 53, heightInt);
}

TimerCallback

void G2mAudioProcessorEditor::timerCallback()
{

if (processor.inputLvl != lastInputLvl)

{
lastInputLvl = processor.inputLvl;
repaint();

}

if (processor.outputLvl != lastOutputLvl)

{
lastOutputLvl = processor.outputLvl;
repaint();
}
}

PluginProcessor.cpp

for (int channel = 0; channel < totalNumInputChannels; ++channel)
{
auto* channelData = buffer.getWritePointer (channel);

// ..do something to the data...
  for (int sample = 0; sample < buffer.getNumSamples(); ++sample)
  {
  	inputLvl = Decibels::gainToDecibels(channelData[sample]);

  	channelData[sample] = buffer.getSample(channel, sample) * rawVolume;

  	outputLvl = Decibels::gainToDecibels(channelData[sample]);


  }

}

Thanks for reading :slight_smile:


#2

Hi
Just some quick suggestions, this is from the top of my head, so maybe not 100% correct, just look at the documentation.
When calling repaint in your timer, you can pass in a Rectangle this is the area that has changed. You need to figure out the area yourself, based on how your meter looks.

Also in you audio code, you are getting the levels of each sample, remember they go from -1 to 1, I’m guessing it will look crazy and random.
Take a look at AudioBuffer::getMagnitude instead, it will find the highest absolute level in your buffer (or any range).
and then do the db converting in the timer.
So the idea is that you only get the highest value in your audio loop.
And then you can apply a release multiplier in your timer, to make the meter fall.

As a side note, this is not technically a VU meter, it will be a crude peak meter.

Hope this helps some
Nikolai


#3

It’s really not very easy at all! Communicating effectively between the audio thread and the GUI is not a solved problem - different approaches will be better for different things.

Here’s a start: