I made a plug-in, but it makes weird noise

#include "PluginProcessor.h"
#include "PluginEditor.h"

AudioPluginAudioProcessor::AudioPluginAudioProcessor()
     : AudioProcessor(BusesProperties()
#if !JucePlugin_IsMidiEffect
#if !JucePlugin_IsSynth
                      .withInput("Input", juce::AudioChannelSet::stereo(), true)
#endif
                      .withOutput("Output", juce::AudioChannelSet::stereo(), true)
#endif
                      ),
                      parameters(*this, nullptr, juce::Identifier("Parameters"),
                      {
                          std::make_unique<juce::AudioParameterFloat>("shroom", "Shroom", 0.0f, 1.0f, 0.0f)
                      })
{
    shroomParameter = dynamic_cast<juce::AudioParameterFloat*>(parameters.getParameter("shroom"));
}

AudioPluginAudioProcessor::~AudioPluginAudioProcessor() {}

void AudioPluginAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
{
    juce::dsp::ProcessSpec spec;
    spec.sampleRate = sampleRate;
    spec.maximumBlockSize = samplesPerBlock;
    spec.numChannels = getTotalNumOutputChannels();

    compressor.prepare(spec);
    eqFilterLow.prepare(spec);
    eqFilterHigh.prepare(spec);
    reverbParams.roomSize = 0.5f;
    reverb.setParameters(reverbParams);

    updateDspParameters();
}

void AudioPluginAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer&)
{
    juce::ScopedNoDenormals noDenormals;
    auto totalNumInputChannels  = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();

    if (totalNumInputChannels == 1 && totalNumOutputChannels == 2)
    {
        for (int sample = 0; sample < buffer.getNumSamples(); ++sample)
        {
            auto monoSample = buffer.getSample(0, sample);
            buffer.setSample(0, sample, monoSample);
            buffer.setSample(1, sample, monoSample);
        }
    }

    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear(i, 0, buffer.getNumSamples());

    updateDspParameters();

    juce::dsp::AudioBlock<float> block(buffer);
    for (size_t chan = 0; chan < block.getNumChannels(); ++chan)
    {
        auto channelBlock = block.getSingleChannelBlock(chan);
        juce::dsp::ProcessContextReplacing<float> context(channelBlock);
        compressor.process(context);
        eqFilterLow.process(context);
        eqFilterHigh.process(context);
        reverb.process(context);
    }
}

void AudioPluginAudioProcessor::releaseResources() {}

void AudioPluginAudioProcessor::getStateInformation(juce::MemoryBlock& destData)
{
    auto state = parameters.copyState();
    std::unique_ptr<juce::XmlElement> xml(state.createXml());
    copyXmlToBinary(*xml, destData);
}

void AudioPluginAudioProcessor::setStateInformation(const void* data, int sizeInBytes)
{
    std::unique_ptr<juce::XmlElement> xmlState(getXmlFromBinary(data, sizeInBytes));
    if (xmlState != nullptr && xmlState->hasTagName(parameters.state.getType()))
    {
        parameters.replaceState(juce::ValueTree::fromXml(*xmlState));
    }
}

juce::AudioProcessorEditor* AudioPluginAudioProcessor::createEditor()
{
    return new AudioPluginAudioProcessorEditor(*this);
}

bool AudioPluginAudioProcessor::hasEditor() const
{
    return true;
}

const juce::String AudioPluginAudioProcessor::getName() const
{
    return JucePlugin_Name;
}

bool AudioPluginAudioProcessor::acceptsMidi() const
{
#if JucePlugin_WantsMidiInput
    return true;
#else
    return false;
#endif
}

bool AudioPluginAudioProcessor::producesMidi() const
{
#if JucePlugin_ProducesMidiOutput
    return true;
#else
    return false;
#endif
}

bool AudioPluginAudioProcessor::isMidiEffect() const
{
#if JucePlugin_IsMidiEffect
    return true;
#else
    return false;
#endif
}

double AudioPluginAudioProcessor::getTailLengthSeconds() const
{
    return 0.0;
}

int AudioPluginAudioProcessor::getNumPrograms()
{
    return 1;
}

int AudioPluginAudioProcessor::getCurrentProgram()
{
    return 0;
}

void AudioPluginAudioProcessor::setCurrentProgram(int index)
{
}

const juce::String AudioPluginAudioProcessor::getProgramName(int index)
{
    return {};
}

void AudioPluginAudioProcessor::changeProgramName(int index, const juce::String& newName)
{
}

void AudioPluginAudioProcessor::updateDspParameters()
{
    float shroomValue = *shroomParameter;

    compressor.setThreshold(juce::jmap(shroomValue, 0.0f, 1.0f, -20.0f, -30.0f));
    compressor.setRatio(juce::jmap(shroomValue, 0.0f, 1.0f, 1.5f, 8.0f));
    compressor.setAttack(20.0f);
    compressor.setRelease(100.0f);

    auto eqCoefficientsLow = juce::dsp::IIR::Coefficients<float>::makePeakFilter(getSampleRate(), 330.0f, 0.671f, juce::Decibels::decibelsToGain(juce::jmap(shroomValue, 0.0f, 1.0f, 0.0f, -7.0f)));
    eqFilterLow.coefficients = *eqCoefficientsLow;

    auto eqCoefficientsHigh = juce::dsp::IIR::Coefficients<float>::makePeakFilter(getSampleRate(), 6000.0f, 0.263f, juce::Decibels::decibelsToGain(juce::jmap(shroomValue, 0.0f, 1.0f, 0.0f, 10.0f)));
    eqFilterHigh.coefficients = *eqCoefficientsHigh;

    reverbParams.roomSize = juce::jmap(shroomValue, 0.0f, 1.0f, 0.5f, 0.9f);
    reverbParams.damping = 1.0f;
    reverbParams.wetLevel = juce::jmap(shroomValue, 0.0f, 1.0f, 0.0f, 0.05f);
    reverbParams.dryLevel = 1.0f - reverbParams.wetLevel;
    reverbParams.width = 1.0f;
    reverbParams.freezeMode = 0.0f;

    reverb.setParameters(reverbParams);
}

juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
    return new AudioPluginAudioProcessor();
}

This is my code… It has a comp, equalizer, and a reverberation function! But when I tried this plug-in, I got weird noise… What’s the reason? I’m attaching the Dry Wet file!

juce::dsp::IIR::Coefficients<float>::makePeakFilter

AFAIK the above function is not real-time safe. Use juce::dsp::IIR::ArrayCoefficients<float> instead.

BTW, you may also upload your header file so that we will make fewer guesses.

1 Like

The compressor, filters, etc have been configured to run on two channels. However, you pass in a single channel block. The compressor etc do not know which channel this block represents and so it uses the state of the first channel to process both channels.

1 Like

with issues like this it would make sense to comment out most of the dsp code to find out which thing specifically fails to work. meaningful breakpoints can help too. find out which variables have an unexpected value at some point

1 Like

I’ve reviewed all of the answers and revised them hard, but they haven’t been solved. I found out that noise like crackles occurs when using a compressor. But even if all the parameters are set to zero, the balance between left and right becomes weird just by hanging the plug-in… I share all my codes

first, pluginprocessor.cpp

#include "PluginProcessor.h"
#include "PluginEditor.h"

AudioPluginAudioProcessor::AudioPluginAudioProcessor()
    : AudioProcessor(BusesProperties()
#if !JucePlugin_IsMidiEffect
#if !JucePlugin_IsSynth
                      .withInput("Input", juce::AudioChannelSet::stereo(), true)
#endif
                      .withOutput("Output", juce::AudioChannelSet::stereo(), true)
#endif
                      ),
                      parameters(*this, nullptr, "Parameters", {
                          std::make_unique<juce::AudioParameterFloat>("shroom", "Shroom", 0.0f, 1.0f, 0.5f)
                      }) {
    shroomParameter = dynamic_cast<juce::AudioParameterFloat*>(parameters.getParameter("shroom"));
}

AudioPluginAudioProcessor::~AudioPluginAudioProcessor() {}

void AudioPluginAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) {
    juce::dsp::ProcessSpec spec;
    spec.sampleRate = sampleRate;
    spec.maximumBlockSize = samplesPerBlock;
    spec.numChannels = getTotalNumOutputChannels();

    for (auto& comp : compressors) comp.prepare(spec);
    for (auto& filter : eqFilterLow) filter.prepare(spec);
    for (auto& filter : eqFilterHigh) filter.prepare(spec);
    reverb.prepare(spec);

    updateDspParameters();
}

void AudioPluginAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer&) {
    juce::ScopedNoDenormals noDenormals;
    auto totalNumInputChannels = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();

    for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i) {
        buffer.clear(i, 0, buffer.getNumSamples());
    }

    updateDspParameters();

    juce::dsp::AudioBlock<float> block(buffer);
    for (size_t chan = 0; chan < block.getNumChannels(); ++chan) {
        auto channelBlock = block.getSingleChannelBlock(chan);
        juce::dsp::ProcessContextReplacing<float> context(channelBlock);

        compressors[chan].process(context);
        eqFilterLow[chan].process(context);
        eqFilterHigh[chan].process(context);
        
        if (chan == 0) { 
            juce::dsp::ProcessContextReplacing<float> reverbContext(channelBlock);
            reverb.process(reverbContext);
        }
    }
}

void AudioPluginAudioProcessor::releaseResources() {}

void AudioPluginAudioProcessor::getStateInformation(juce::MemoryBlock& destData) {}

void AudioPluginAudioProcessor::setStateInformation(const void* data, int sizeInBytes) {}

juce::AudioProcessorEditor* AudioPluginAudioProcessor::createEditor() {
    return new AudioPluginAudioProcessorEditor(*this);
}

bool AudioPluginAudioProcessor::hasEditor() const {
    return true;
}

const juce::String AudioPluginAudioProcessor::getName() const {
    return JucePlugin_Name;
}

bool AudioPluginAudioProcessor::acceptsMidi() const {
#if JucePlugin_WantsMidiInput
    return true;
#else
    return false;
#endif
}

bool AudioPluginAudioProcessor::producesMidi() const {
#if JucePlugin_ProducesMidiOutput
    return true;
#else
    return false;
#endif
}

bool AudioPluginAudioProcessor::isMidiEffect() const {
#if JucePlugin_IsMidiEffect
    return true;
#else
    return false;
#endif
}

double AudioPluginAudioProcessor::getTailLengthSeconds() const {
    return 0.0;
}

int AudioPluginAudioProcessor::getNumPrograms() {
    return 1; // Required number of programs
}

int AudioPluginAudioProcessor::getCurrentProgram() {
    return 0; // Current program number
}

void AudioPluginAudioProcessor::setCurrentProgram (int index) {
    // Set current program (not used in this template)
}

const juce::String AudioPluginAudioProcessor::getProgramName (int index) {
    // Return program name (not used in this template)
    return {};
}

void AudioPluginAudioProcessor::changeProgramName (int index, const juce::String& newName) {
    // Change program name (not used in this template)
}

void AudioPluginAudioProcessor::updateDspParameters() {
    float shroomValue = *shroomParameter;

    // comp set
    for (auto& comp : compressors) {
        comp.setThreshold(juce::jmap(shroomValue, 0.0f, 1.0f, 0.0f, 0.0f));
        comp.setRatio(juce::jmap(shroomValue, 0.0f, 1.0f, 1.0f, 1.0f));
        comp.setAttack(20.0f);
        comp.setRelease(100.0f);
    }

    // Eq filter set
    for (size_t i = 0; i < eqFilterLow.size(); ++i) {
        auto& lowFilter = eqFilterLow[i];
        auto& highFilter = eqFilterHigh[i];

        auto eqCoefficientsLow = juce::dsp::IIR::Coefficients<float>::makePeakFilter(getSampleRate(), 330.0f, 0.671f, juce::Decibels::decibelsToGain(juce::jmap(shroomValue, 0.0f, 1.0f, 0.0f, 10.0f)));
        lowFilter.coefficients = *eqCoefficientsLow;

        auto eqCoefficientsHigh = juce::dsp::IIR::Coefficients<float>::makePeakFilter(getSampleRate(), 6000.0f, 0.263f, juce::Decibels::decibelsToGain(juce::jmap(shroomValue, 0.0f, 1.0f, 0.0f, 10.0f)));
        highFilter.coefficients = *eqCoefficientsHigh;
    }

    // reverb set
    reverbParams.roomSize = juce::jmap(shroomValue, 0.0f, 1.0f, 0.5f, 0.9f);
    reverbParams.damping = 1.0f;
    reverbParams.wetLevel = juce::jmap(shroomValue, 0.0f, 1.0f, 0.0f, 0.0f); 
    reverbParams.dryLevel = 1.0f - reverbParams.wetLevel;
    reverbParams.width = 1.0f;
    reverbParams.freezeMode = 0.0f;

    reverb.setParameters(reverbParams);
}


juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
    return new AudioPluginAudioProcessor();
}

and pluginprocesso.h

#pragma once

#include <JuceHeader.h>
#include <array>

class AudioPluginAudioProcessor : public juce::AudioProcessor {
public:
    AudioPluginAudioProcessor();
    ~AudioPluginAudioProcessor() override;

    void prepareToPlay(double sampleRate, int samplesPerBlock) override;
    void releaseResources() override;
    void processBlock(juce::AudioBuffer<float>&, juce::MidiBuffer&) override;

    juce::AudioProcessorEditor* createEditor() override;
    bool hasEditor() const override;

    const juce::String getName() const override;

    bool acceptsMidi() const override;
    bool producesMidi() const override;
    bool isMidiEffect() const override;
    double getTailLengthSeconds() const override;

    int getNumPrograms() override;
    int getCurrentProgram() override;
    void setCurrentProgram(int index) override;
    const juce::String getProgramName(int index) override;
    void changeProgramName(int index, const juce::String& newName) override;

    void getStateInformation(juce::MemoryBlock& destData) override;
    void setStateInformation(const void* data, int sizeInBytes) override;

    // Parameters
    juce::AudioParameterFloat* shroomParameter;
    juce::AudioProcessorValueTreeState parameters;

private:
    // DSP Processors
    std::array<juce::dsp::Compressor<float>, 2> compressors;
    std::array<juce::dsp::IIR::Filter<float>, 2> eqFilterLow;
    std::array<juce::dsp::IIR::Filter<float>, 2> eqFilterHigh;
    juce::dsp::Reverb reverb;
    juce::dsp::Reverb::Parameters reverbParams;

    void updateDspParameters();

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AudioPluginAudioProcessor)
};

You are (re-)initializing your subprocessors in each call to processBlock (), so there is no continuity in handling the input stream.

You are calling your “updateDspParameters” in both prepareToPlay and processBlock.

At least in prepare one would expect something named like, and intended as “prepareSubProcessors” or “initDspParameters”. Not a place to update something.

And as said, you are initializing/resetting your subprocessors in updateDspParameters, where you probably intend to only handle potential changes to them.

1 Like

Thank you so much!! All the noise is gone! Also, after deleting the Reverb processor, the left and right balance is better… There must be something about Reverb that I don’t know…! Unfortunately for Reverb, I was able to make the plug-in that I thought was possible. Thank you all for your answers!