Distorted oscillator sound


I’m working on making a dub siren plugin loosely based on the AudioProcessorValueTreeState tutorial and the AudioProcessorGraph tutorial.

I currently have one oscillator in the graph with the frequency controlled by a slider. However, it sounds as if the oscillator’s output is being modulated by something - rather than a pure sine wave I get a wobbling sound. If I put the frequency right down to 1Hz rather than hearing nothing I hear a distorted oscillation with the volume going up and down at 1Hz. The output at, say, 600Hz will sound different if I move the slider to a different value and then bring it back to 600Hz.

Below is what is hopefully only the relevant bits of code (I realise the frequency range is too high for a real LFO but I don’t think that’s relevant). As you can see they are fairly similar to the tutorials so I am at a loss what to look at next. Both tutorials build and sound fine.

I thought that the problem might be making the LFO a subclass of AudioProcessorValueTreeState::Listener, but commenting out the relevant bits of code made no difference.

Possibly relevant is that I get a lot of the following error in the console:

2018-06-30 17:52:05.153012+0100 AudioPluginHost[21997:4770486] dynamic_cast error 1: Both of the following type_info's should have public visibility. At least one of them is hidden. N4juce23AudioProcessorParameterE, N4juce28AudioProcessorValueTreeState9ParameterE.

Removing the call to createAndAddParameters in the constructor removes this error but I don’t see why it should cause problems.

I would be grateful for any suggestions.

// LFO.h ================

class LFO : public ProcessorBase, public AudioProcessorValueTreeState::Listener
    const String getName() const override { return "LFO"; }
    void prepareToPlay(double sampleRate, int samplesPerBlock) override;
    void processBlock(AudioSampleBuffer& buffer, MidiBuffer& midiMessages) override;
    void reset() override;
    void parameterChanged(const String& parameterID, float newValue) override;
    dsp::Oscillator<float> oscillator;

// LFO.cpp ==============

    oscillator.initialise([] (float x) { return std::sin(x); });

void LFO::prepareToPlay(double sampleRate, int samplesPerBlock)
    dsp::ProcessSpec spec { sampleRate, static_cast<uint32>(samplesPerBlock) };

void LFO::processBlock(AudioSampleBuffer &buffer, juce::MidiBuffer &midiMessages)
    dsp::AudioBlock<float> block(buffer);
    dsp::ProcessContextReplacing<float> context(block);

void LFO::reset()

void LFO::parameterChanged(const String& parameterID, float newValue)
    if (parameterID == "lfo_freq") {

// PluginProcessor.cpp ========

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

#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                       .withOutput ("Output", AudioChannelSet::stereo(), true)
        mainProcessor(new AudioProcessorGraph()),
        parameters(*this, nullptr)
    parameters.createAndAddParameter("lfo_freq", "LFO Freq", String(), NormalisableRange<float>(1.0f, 10000.0f), 440.0f, nullptr, nullptr);
    parameters.state = ValueTree(Identifier("LFOFreq"));



void DubSirenAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
    if (lfoNode == nullptr) {
                                            sampleRate, samplesPerBlock);

        mainProcessor->prepareToPlay(sampleRate, samplesPerBlock);

void DubSirenAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
    for (int i = getTotalNumInputChannels(); i < getTotalNumOutputChannels(); i++)
        buffer.clear(i, 0, buffer.getNumSamples());

    mainProcessor->processBlock(buffer, midiMessages);

void DubSirenAudioProcessor::initialiseGraph()

    audioOutputNode = mainProcessor->addNode(new AudioGraphIOProcessor(AudioGraphIOProcessor::audioOutputNode));
    midiInputNode = mainProcessor->addNode(new AudioGraphIOProcessor(AudioGraphIOProcessor::midiInputNode));
    midiOutputNode = mainProcessor->addNode(new AudioGraphIOProcessor(AudioGraphIOProcessor::midiOutputNode));


void DubSirenAudioProcessor::connectAudioNodes()
    lfoNode = mainProcessor->addNode(new LFO());

    parameters.addParameterListener("lfo_freq", static_cast<LFO*>(lfoNode->getProcessor()));

    for (int channel = 0; channel < 2; channel++)
            { lfoNode->nodeID, channel },
            { audioOutputNode->nodeID, channel }

void DubSirenAudioProcessor::connectMidiNodes()
        { midiInputNode->nodeID, AudioProcessorGraph::midiChannelIndex},
        { midiOutputNode->nodeID, AudioProcessorGraph::midiChannelIndex}

// PluginEditor.cpp =======

DubSirenAudioProcessorEditor::DubSirenAudioProcessorEditor (DubSirenAudioProcessor& p, AudioProcessorValueTreeState& vts)
    : AudioProcessorEditor (p), processor (p), valueTreeState(vts)
    setSize (400, 300);

    lfoFreqLabel.setText("LFO Freq", dontSendNotification);
    lfoFreqAttachment.reset(new SliderAttachment(valueTreeState, "lfo_freq", lfoFreq));