Sending RMS value of processedblock audio to a linearSlider?

Hi there,

I’m working on an educational compressor plugin and I have setup a LinearBarVertical slider that I want to utilize as a visual for the RMS value passing through the plugin.

I have created a sample to RMS function, but I’m lost on how I can get the value from the processBlock function, pass it through my sample to RMS function, and then display it in the LinearBarVertical Slider.

If anyone can point towards the correct Documentation or step me through this problem, I’d really appreciate it.

I appreciate any help.

I’m not sure why you’d want to use a slider to visualize the RMS value of your plugin…wouldn’t some other type of component that’s meant for visualization serve you better instead of a slider?

Either way, in your processBlock, you can pass a simple float to a member variable inside your editor. Then, usually on a timer, have the editor look at that value and use it to adjust the component you’re using to visualize it.

Something like:

void processBlock()
{
// process your audio and calc RMS
    float currentRMS = // your calculation
// then give that value to the editor
    if(editor != nullptr)
        editor->currentRMS  = currentRMS;
}

In your editor…

Editor()
{
    startTimerHz(30);
}
void timerCallback() override
{
    myLinearSlider.setValue(currentRMS, dontSendNotification);
}

float currentRMS = 0.0f;

Is there a component you recommend? I’ve only had a couple of months working with very minimal things in JUCE. So, I’m pretty new. I appreciate your help!

Yeah, it’s a shame that JUCE doesn’t have some kind of built-in meter component. Here’s a very quick one:

class SimpleMeter : public Component
{
public:
    SimpleMeter()
    {
       level = 0.0f;
    }
    ~SimpleMeter(){}

    void paint(Graphics& g) override
    {
        g.fillAll(Colours::black);
    
        // flip it vertically for better readability
        g.addTransform(AffineTransform::verticalFlip((float)getHeight()));
       
        g.setColour(Colours::red);
        // scaled for 0.0 to 1.0 based on the height of the meter
        g.fillRect(0.0f, 0.0f, (float)getWidth(), (float)getHeight() * level);
    }

    void setLevel(float newLevel)
    {
        level = jlimit(0.0f, 1.0f, newLevel);
        repaint();
    }

private:
    float level;
};

Wow, I didn’t expect that! Thanks for all the work and guidance you’ve given and done for me.

You might also want to look for “SimpleDeviceManagerInputLevelMeter”, which is a class used internally. We should probably create a public-facing one too!

1 Like

dRowAudio: http://drowaudio.co.uk

It has a good demo of how to create a meter.

Rail

I appreciate it. I’ll be looking into that right now!

Appreciate it. I looked on the website but I do not see any “demo” section, blog, or forum section. Can you tell me what I’m missing?

Go to:

http://drowaudio.co.uk/tools.php

which has links to the repository

Rail

My version of the meters component: https://github.com/ffAudio/ff_meters
Adds a measuring class in the processor LevelMeterSource, which does the measuring and windowing, so that the measurements don’t depend on the buffer size and that they move smoothly. And a Component to use in the Editor that listens to the LevelMeterSource. That way you don’t call the Editor from the Processor, since I would not recommend doing that.

This is due to how editors are handled differently in every host.
The rule of thumb is, that the processor shouldn’t rely in any form on the processor.

@pizzafilms: since you are checking editor inside processBlock (AudioThread!), you might be unlucky and the editor is destroyed (MessageThread) in that moment, when you are accessing the currentRMS member.

2 Likes

I’m not sure what you mean, @daniel.

Are you saying that it’s better for the editor to check the value of a processor’s member variable than if a processor stores a value into an editor’s member variable?

If you put it like that, yes. But that aspect is a design decision, so you can argue which way you prefer.

What you cannot argue, is that you set something in the editor from processBlock. The processBlock happens on the AudioThread, that is running unsynchronised from the messageThread. So you cannot know, if the editor is being destroyed, while you are executing the statement inside your if (editor) block.
You can access the editor from the processor under certain restrictions:

  • you make sure the MessageThread is not interfering, a) making your editor.currentRMS atomic and b) hold a MessageManagerLock (which is a no-go inside processBlock() )
  • you are calling from the MessageThread yourself, e.g. as result from a Timer (which shows, why it makes more sense to have that Timer in the Editor) or using MessageManager::callAsync (also a bad idea inside the processBlock)

It is a good thing to spend time thinking, which operations in the AudioProcessor are executed from which thread, as this is the place, where the two time dimensions meet (audio thread and message thread).

I hope this makes the problem understandable.

1 Like

Now that I think about it, of course, you’re correct. I guess that I thought that setting a simple float would be acceptable, and I really didn’t consider that once an editor was created, that it could be destroyed by the DAW. Any DAWs in particular that do that?

Thanks.

…basically every, when you close the editor window? or didn’t I understand the question? :wink:

Setting the value just happens too often to risk the chance…

Interesting…

I’ve been holding onto a raw pointer to the editor in createEditor() and using it without issue…that I know of. But, you’re right, the editor could get destroyed in the if(editor){} block. Thanks for pointing that out.

Interesting indeed… sure, some hosts might leak the editor or destroy it only when the whole DAW is closed. But that’s definitely not the normal case.
I didn’t do a research, when it becomes a problem, because for me it was always obvious not to keep the editor pointer.

2 Likes