Incomplete type error when declaring multiple processors

Hi I made a little project with two oscillators each playing in a different processor. It works perfectly. Now when I try to do the same in a big project with a custom OscillatorProcessor it gives me the errors:

In file included from ../../Source/PluginProcessor.cpp:9:
../../Source/PluginProcessor.h:135:25: error: field ‘proc0’ has incomplete type ‘OscillatorProcessor’
  135 |     OscillatorProcessor proc0 {0};
      |                         ^~~~~
In file included from ../../Source/PluginProcessor.h:12,
                 from ../../Source/PluginProcessor.cpp:9:
../../Source/OscillatorProcessor.h:18:7: note: forward declaration of ‘class OscillatorProcessor’
   18 | class OscillatorProcessor  : public ProcessorBase


#include "OscillatorProcessor.h"
[...]
private: 
    OscillatorProcessor proc0 {0};
    OscillatorProcessor proc1 {1};

I declared it in exactly the same way in my practice project and it just works the only thing that’s different is the OscillatorProcessor.h

OscillatorProcessor.h :

/*
  ==============================================================================

    oscillator.h
    Created: 31 Jul 2020 10:21:05am
    Author:  eye

  ==============================================================================
*/

#pragma once

#include <JuceHeader.h>
#include "ProcessorBase.h"
#include "SynthSound.h"
#include "SynthVoice.h"

class OscillatorProcessor  : public ProcessorBase
{
public:

  OscillatorProcessor(int osc_id)
  {
    id = osc_id;
    synth.clearVoices();

    for (int i = 0; i < 5; i++)
        synth.addVoice(new SynthVoice());

    synth.clearSounds();
    synth.addSound(new SynthSound());
  }

  void prepareToPlay (double sampleRate, int samplesPerBlock) override
  {
    lastSampleRate = sampleRate;
    synth.setCurrentPlaybackSampleRate(lastSampleRate);
  }

  void processBlock (juce::AudioSampleBuffer& buffer, juce::MidiBuffer&) override
  {
    for (int i = 0; i < 5; i++)
    {
        //if myVoice sucessfully casts as a SynthVoice*, get the voice and set the params
        if ((voice = dynamic_cast<SynthVoice*>(synth.getVoice(i))))
        {
          voice->setSampleRate(lastSampleRate);
          voice->setWavetable(wavetable, id);
          voice->setADSRParameters(att, dec, sus, rel);
          voice->setGain(gain);
          voice->setTableRange(first_sample, last_sample);
          voice->setTuning(tune);
        }
        synth.renderNextBlock(buffer, midiMessages, 0, buffer.getNumSamples());
  }

  void setWavetable(float (*waveform)[1080])
  {
    wavetable = waveform;
  }

  void setParameters (std::atomic<float>* attack, std::atomic<float>* decay,
                      std::atomic<float>* sustain, std::atomic<float>* release,
                      std::atomic<float>* gain_value, std::atomic<float>* tuning
                      std::atomic<float>* start_sample ,std::atomic<float>* stop_sample)
  {
    att = attack;
    dec = decay;
    sus = sustain;
    rel = release;

    gain = gain_value;
    tune = tuning;

    first_sample = start_sample;
    last_sample = stop_sample;

  }

  void reset() override
  {

  }

private:
    double lastSampleRate;
    Synthesiser synth;
    SynthVoice* voice;

    std::atomic<float>* att, dec, sus, rel;
    float gain;
    float first_sample, last_sample;
    float tuning;
    int id;

    float (*wavetable)[1080];

}; 

ProcessorBase.h:
/*
==============================================================================

    ProcessorBase.h
    Created: 30 Jul 2020 7:25:15pm
    Author:  eye

  ==============================================================================
*/

#pragma once

#include <JuceHeader.h>

class ProcessorBase  : public juce::AudioProcessor
{
public:
    //==============================================================================
    ProcessorBase()  {}

    //==============================================================================
    void prepareToPlay (double, int) override {}
    void releaseResources() override {}
    void processBlock (juce::AudioSampleBuffer&, juce::MidiBuffer&) override {}

    //==============================================================================
    juce::AudioProcessorEditor* createEditor() override          { return nullptr; }
    bool hasEditor() const override                              { return false; }

    //==============================================================================
    const juce::String getName() const override                  { return {}; }
    bool acceptsMidi() const override                            { return false; }
    bool producesMidi() const override                           { return false; }
    double getTailLengthSeconds() const override                 { return 0; }

    //==============================================================================
    int getNumPrograms() override                                { return 0; }
    int getCurrentProgram() override                             { return 0; }
    void setCurrentProgram (int) override                        {}
    const juce::String getProgramName (int) override             { return {}; }
    void changeProgramName (int, const juce::String&) override   {}

    //==============================================================================
    void getStateInformation (juce::MemoryBlock&) override       {}
    void setStateInformation (const void*, int) override         {}

private:
    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProcessorBase)
};

My working example:
TwoProcessorsExampleSource.zip (5.4 KB)

Full code of project with error:
GeoHead Source only.zip (16.8 KB)

I am absolutely puzzled I did exactly the same…

It’s probably something to do with the header file include orders. A circular set of requirements maybe?

It’s not immediately obvious tho is it :slight_smile:

… edit: nope, I can’t figure it out from a quick stare at your zip file :slight_smile:

Have you perhaps neglected to implement an override for a virtual function in ProcessorBase or OscillatorProcessor that is required for an AudioProcessor-derived class? Haven’t looked to see if that’s an issue or not; just a guess.

Found it: you’re missing a closing } on the for loop here, causing the class definition to not be complete:

  void processBlock (juce::AudioSampleBuffer& buffer, juce::MidiBuffer&) override
  {
    for (int i = 0; i < 5; i++)
    {
        //if myVoice sucessfully casts as a SynthVoice*, get the voice and set the params
        if ((voice = dynamic_cast<SynthVoice*>(synth.getVoice(i))))
        {
          voice->setSampleRate(lastSampleRate);
          voice->setWavetable(wavetable, id);
          voice->setADSRParameters(att, dec, sus, rel);
          voice->setGain(gain);
          voice->setTableRange(first_sample, last_sample);
          voice->setTuning(tune);
        }
        synth.renderNextBlock(buffer, midiMessages, 0, buffer.getNumSamples());
  }

(By the way, the full output of the build states that the class is not complete until the closing }. That’s how I found it. Double-clicking on what should have been the closing brace showed it didn’t match with the opening brace.)

1 Like

Thanks mate, absolute legend. Now I know what to look for when I get these kind of errors again. Time to debug the rest of the code :slight_smile: