Adding child component to audio plugin breaks it? [fixed]

Hey Everyone,

I’m trying to refactor an audio plugin I made with a proper component hierarchy, but I’m stuck at the start with something that’s probably a beginners mistake…

So I got my empty VST3 project setup and that works in the daw (I use StudioOne):

But if add a basic empty child component, in the daw it just shows a bunch of dials like this:

Screenshot 2021-08-07 163827

Here’s my PluginEditor.h:

// Conductor : Copyright ioFlow Studios 2021 //

#pragma once

// System includes
#include <vector>
#include <iostream>
#include <map>

#include "HeaderComponent.h"
#include "BodyComponent.h"
#include "FooterComponent.h"

#include <JuceHeader.h>
#include "PluginProcessor.h"

/////////////////////////////////////
//                                 //
//  ConductorAudioProcessorEditor  //
//                                 //
/////////////////////////////////////

class ConductorAudioProcessorEditor  : public juce::AudioProcessorEditor, private juce::Timer
{
public:
	
	////////// ---------- Components ---------- //////////
	

	// Layout components
	HeaderComponent* header;
	BodyComponent* body;
	FooterComponent* footer;
	
    // Resizer component
	ResizableCornerComponent* resizer;
	ComponentBoundsConstrainer resizeLimits;

	
	////////// ---------- Methods ---------- //////////
	
	
	// Construction
    ConductorAudioProcessorEditor (ConductorAudioProcessor&);
    ~ConductorAudioProcessorEditor() override;

    // Rendering
    void paint (juce::Graphics&) override;
    void resized() override;
    
    // listeners
	void timerCallback() override; // Check processor frequently (thread safe alternative to processor pushing to editor)

private:

	////////// ---------- Properties ---------- //////////

	// Processor reference for editor
    ConductorAudioProcessor& audioProcessor;



    
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConductorAudioProcessorEditor)
};

And here’s my PluginEditor.cpp

// Conductor : Copyright ioFlow Studios 2021 //

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

///////////////////
//               //
//  constructor  //
//               //
///////////////////

ConductorAudioProcessorEditor::ConductorAudioProcessorEditor (ConductorAudioProcessor& p)
    : AudioProcessorEditor (&p), audioProcessor (p)
{
	//// ---- header component ---- ////

	addAndMakeVisible(header);

	//// ---- set starting size ---- ////

    setSize (1600, 730);
}

ConductorAudioProcessorEditor::~ConductorAudioProcessorEditor() {}

/////////////////////
//                 //
//  timerCallBack  //
//                 //
/////////////////////

void ConductorAudioProcessorEditor::timerCallback()
{
	
}

/////////////
//         //
//  paint  //
//         //
/////////////

void ConductorAudioProcessorEditor::paint (juce::Graphics& g)
{
    // (Our component is opaque, so we must completely fill the background with a solid colour)
    g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));

    g.setColour (juce::Colours::white);
    g.setFont (15.0f);
    g.drawFittedText ("Hello World!", getLocalBounds(), juce::Justification::centred, 1);
}

///////////////
//           //
//  resized  //
//           //
///////////////

void ConductorAudioProcessorEditor::resized()
{
    // This gets called when you set the size of the canvas (either in the constructor or by resizing in the daw)

	header->setBounds(0, 0, getWidth(), getHeight());
}

So, pretty basic, don’t think there’s something else interfering with the plugin working (the header, body and footer components are just empty components made in projucer).

Did I miss something in the tutorials? Is there something extra you have to do to make it work when you’re doing an audio plugin?

It looks like generated by the host, so just to be sure, does your processor hasEditor() return true?

bool ConductorAudioProcessorEditor::hasEditor()
{
    return true;
}

Hi Daniel,

Yep, I left it the way it was generated by projucer.

The weird thing is, it’s only after I add the child component that it breaks…

If I comment out the header stuff (its addAndMakeVisible and setBounds) the plugin loads fine again.

This is why I didn’t use seperate classes the first time round (did it all in PluginEditor) but as you could imagine, that’s an overly large class :slight_smile: that made my inner code puritan feel dirty.

(hence the refactor).

Makes perfect sense.
Since it compiles fine it is tricky to say and probably host dependent.
So I am guessing around what could be tried. It’s nothing I experienced myself.

I see that the size you give the editor is quite big. Maybe the host has some size limits built in and uses its generic view as fallback. I would try with a more moderate size and if that works trying to employ the screen size, since 1600 can easily be too big for some screens.

Good luck

Hmmm… just noticed this:

Yep that’s fixed it… have these (custom) components in PluginEditor.h:

// Layout components
HeaderComponent* header;
BodyComponent* body;
FooterComponent* footer;

Added this to the constructor for PluginEditor.cpp:

header = new HeaderComponent();
body = new BodyComponent();
footer = new FooterComponent();

It runs in StudioOne now.

I am surprised that it doesn’t crash.

Make sure that setSize() is the last thing you are calling in the constructors body.
The reason is that is will call resized() directly and your header, body and footer might not have been constructed yet (although your code doesn’t show where they are constructed, and maybe you have a check against nullptr in resized())

It is much better though to use the variables as plain members and not as pointers, like

// Layout components
HeaderComponent header;
BodyComponent body;
FooterComponent footer;

This makes sure they are constructed without you calling new and especially they are destroyed together with the editor object.

If you need a pointer though, because the member can be created and destroyed independently from the editors life time, then please use smart pointers like

std::unique_ptr<HeaderComponent> header;

and so on.

Hey Daniel,

Yah resize is always last (learned that the hard way).

Thanks for the tip re plain members, just one question about the resizer now though:

    resizeLimits.setSizeLimits(1600, 730, 1920, 1030);
    resizer = new ResizableCornerComponent(this, &resizeLimits);

After ditching the new statement above, I’m not sure how to set the size limits (went through all the autocomplete stuff, did I miss it in there somewhere?)

Members can use default initialisers in the header where you declare them, like this:

juce::ComponentBoundsConstrainer resizeLimits;
juce::ResizableCornerComponent   resizer { this, &resizeLimits };

and call in the constructor body early on (at least before setSize(), because that’s when it is evaluated):

resizeLimits.setSizeLimits (1600, 730, 1920, 1030);

I haven’t tested it, but I think it should work (famous last words)

Good luck