Input / Output meters not working correctly

I would like to have independent input and output meters. Unlike this post where he doesn’t need independent meters How to create volume meter for input volume and output volume

WHAT I’VE DONE SO FAR
My VST3 Plugin is based on the work done here Tutorial: Control audio levels using decibels

WHAT’S NOT WORKING
Although the values from the slider are correctly being passed to the processBlock callback, there is no audible change in the levels when I update the buffer samples.

Also, when I turn the slider all the way down (in this case -100), I’m still seeing sound levels on the meters when I would suspect I should be getting no sound.

CODE IN PROCESS BLOCK
void IotestAudioProcessor::processBlock (juce::AudioBuffer& buffer, juce::MidiBuffer& midiMessages)
{
juce::ScopedNoDenormals noDenormals;
auto totalNumInputChannels = getTotalNumInputChannels();
auto totalNumOutputChannels = getTotalNumOutputChannels();

const auto numSamples = buffer.getNumSamples();
const auto numChannels = buffer.getNumChannels();




// In case we have more outputs than inputs, this code clears any output
// channels that didn't contain input data, (because these aren't
// guaranteed to be empty - they may contain garbage).
// This is here to avoid people getting screaming feedback
// when they first compile a plugin, but obviously you don't need to keep
// this code if your algorithm always overwrites all the output channels.
for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
    buffer.clear (i, 0, buffer.getNumSamples());



inputMeterSource.measureBlock(buffer);

for (int channel = 0; channel < numChannels; ++channel)
{
    auto* buf = buffer.getWritePointer(channel, buffer.getSample(channel, 0));

    for (int sample = 0; sample < numSamples; sample++)
    {

        if (lastInput != inputLevel)
        {
            lastInput = inputLevel;


            buf[sample] *= inputLevel * 6;
            
        }

        if (lastOutput != outputLevel)
        {
            lastOutput = outputLevel;


            buf[sample] *= outputLevel * 6;

        }
    }
   



    outputMeterSource.measureBlock(buffer);



}

}

At least this isn’t right :

auto* buf = buffer.getWritePointer(channel, buffer.getSample(channel, 0));

What you probably meant to do :

auto* buf = buffer.getWritePointer(channel);

I’ll make the correction. Thank you!

Also if you are doing a gain changer, I don’t think you should have any conditionals in the code. I don’t really understand what you are doing.

I don’t understand what I’m doing either :slightly_smiling_face:

I’m trying to apply gain to the Input an Output separately. I just assumed that if the Input Level changes, then the Input meter should change. My code may be confusing simply because I’m not clear.

In brief:
I have a UI with two sliders. One slider controls the Input Level, and the other slider controls the output level.

I have two meters; one to display the input level, and the other to display the output level.

When I adjust one slider, I would hope to see the resulting change in the appropriate meter.

Here is a snapshot of my meters. You’ll notice that I have my levels all the way down.

According to the tutorial, -100 is barely audible. Perhaps I shouldn’t be using the information from there. If the meter is turned all the way down on the Output knob (the Blue knob), then there should be no output registering on the meter.

image

1 Like

You may want to take a look at buffer.applyGainRamp() and buffer.getMagnitude() both of which may significantly simplify your code.

We were all beginners once. Good luck!

Thank you!

I’ll give those a go. This Audio world is a bit confusing right now :smiley:

If you are simply trying the change the signal level, there’s really no point in changing both the input and output levels. If you have a processing like distortion in the middle of the signal chain, then it could make some sense.

Yes I intend to have a process like an EQ or a distortion or a dynamic processor in between the 2 meters/2 gain controls.

What you have explained so far, looks like this to me :

graphviz

It doesn’t really make much sense to me, but you could program that anyway. (Or maybe I understood you wrong, you should probably try explaining the desired signal routing again.)

Thanks. That’s pretty much what I “think” I’ve done so far.

I’m likely not updating one of the controls properly.

Tonight, I used REAPER. I was able set things up so I could see the Output and Input meters.

USE CASE

Using Reaper, I was able to lower the Output Level so that I could hear nothing from my headphones.

However, if you looked at the Input meter (my Mic), you could see the reading fluctuate because I still had the input level up. My mic was picking up the ambient noise as well as my voice.

Once I raised the output level (again for my head set), I could hear what was coming in through my mic.

I would like to be able to recreate this functionality using JUCE

Changing the gain in a processing pipeline will make no difference where it is applied (except for the display of your meters), as long as all steps behave linearly.

In a guitar amp the reason to “drive” the preamp and the power amp separately is, because in certain amplifications they work non-linear. There is also a saturation effect, so the amplification will become less the higher the input signal goes. Originally the designers struggled to get linear behaviour, the process is called biasing. In popular culture, this non-linearity is considered to sound great, so the bias was intentionally set to non linear settings, called overdrive etc.

In a mathematical function, where you just multiply linearly, you cannot get this effect. You will ahve to artificially model the (originally wrong) behaviour of analogue amplifiers, or come up with other operations, see digital distortions.

A good resource is @IvanC’s classic talk about distortion 50 shades of distortion

1 Like

I’ll take a look at that article. I need to do much more studying … a lot more.

It’s a good thing, math is involved. That’s one thing I can understand well :slight_smile:

I’ve found my answer.

The OverdriveDemo example which may be found in the Projucer application does what I’d like.

I’m able to control the Input and Output separately. Of course, my needs were much simpler than what was offered in the OverdriveDemo project.

While some of the techniques are still more voodoo to me than not, it was a nice intro into the world of DSP.