Thanks for taking a look. I cobbled together a way to host a plug-in inside a plug-in, but:
- its interface disappears after closing and reopening.
- It is positioned at the top of the editor window (in JUCE Audio Plug-in Host) when I setTopLeftPosition(0, 60)
- paintOverChildren paints under it. On reopening, the results of paintOverChildren are visible, but not the hosted plug-in.
By the way, the string “realFileName” here is just an arbitrary VST3 plug-in that I drop into the same folder for it to load. That is how I want this to be used, by being in the same folder, but it will not be “Surge.vst3”.
Code here:
https://github.com/chuckkh/WrapperTest/tree/master/Source
#pragma once
#include <JuceHeader.h>
class WrapperTestAudioProcessor : public juce::AudioProcessor
{
public:
WrapperTestAudioProcessor();
~WrapperTestAudioProcessor() override;
void prepareToPlay(double sampleRate, int samplesPerBlock) override;
void releaseResources() override;#ifndef JucePlugin_PreferredChannelConfigurations
bool isBusesLayoutSupported(const BusesLayout& layouts) const override;
#endif
void processBlock(juce::AudioBuffer&, juce::MidiBuffer&) override;
juce::AudioProcessorEditor* createEditor() override;
bool hasEditor() const override;
juce::AudioProcessorEditor* getWrappedInstanceEditor();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;
private:
AudioPluginFormatManager fm;
PluginDescription descr;
OwnedArray pluginDescriptions;
KnownPluginList plist;
File myFile, myPath;
const String myFileName = myFile.getFileName();
const String realFileName = “Surge.vst3”;
String realFullPathName;
AudioProcessor* plugin;
std::unique_ptr wrappedInstance;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WrapperTestAudioProcessor)
};
// PluginProcessor.cpp
#include “PluginProcessor.h”
#include “PluginEditor.h”WrapperTestAudioProcessor::WrapperTestAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
: AudioProcessor(BusesProperties()
#if ! JucePlugin_IsMidiEffect
#if ! JucePlugin_IsSynth
.withInput(“Input”, juce::AudioChannelSet::stereo(), true)
#endif
.withOutput(“Output”, juce::AudioChannelSet::stereo(), true)
#endif
)
#endif{
fm.addDefaultFormats();
descr.pluginFormatName = “VST3”;
myFile = File::getSpecialLocation(File::currentApplicationFile);
myPath = myFile.getParentDirectory();
const String myPathName = myPath.getFullPathName();static String myPathNameSep = File::addTrailingSeparator(myPathName); realFullPathName = myPathNameSep + realFileName; descr.fileOrIdentifier = realFullPathName; for (uint32 i = 0; i < fm.getNumFormats(); ++i) plist.scanAndAddFile(realFullPathName, true, pluginDescriptions, *fm.getFormat(i)); jassert(pluginDescriptions.size() > 0); bool loadingSuccess = false; String ignore; if (wrappedInstance = fm.createPluginInstance(*pluginDescriptions[0], 44100.0, 512, ignore)) loadingSuccess = true;
}
WrapperTestAudioProcessor::~WrapperTestAudioProcessor()
{
delete wrappedInstance->getActiveEditor();
}
const juce::String WrapperTestAudioProcessor::getName() const
{
return JucePlugin_Name;
}
bool WrapperTestAudioProcessor::acceptsMidi() const
{
return wrappedInstance->acceptsMidi();
}
bool WrapperTestAudioProcessor::producesMidi() const
{
return wrappedInstance->producesMidi();
}
bool WrapperTestAudioProcessor::isMidiEffect() const
{
return wrappedInstance->isMidiEffect();
}
double WrapperTestAudioProcessor::getTailLengthSeconds() const
{
return wrappedInstance->getTailLengthSeconds();
}
int WrapperTestAudioProcessor::getNumPrograms()
{
return 1;
}
int WrapperTestAudioProcessor::getCurrentProgram()
{
return 0;
}
void WrapperTestAudioProcessor::setCurrentProgram(int index)
{
}
const juce::String WrapperTestAudioProcessor::getProgramName(int index)
{
return {};
}
void WrapperTestAudioProcessor::changeProgramName(int index, const juce::String& newName)
{
}
void WrapperTestAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
{
wrappedInstance->prepareToPlay(sampleRate, samplesPerBlock);
}
void WrapperTestAudioProcessor::releaseResources()
{
}
#ifndef JucePlugin_PreferredChannelConfigurations
bool WrapperTestAudioProcessor::isBusesLayoutSupported(const BusesLayout& layouts) const
{
#if JucePlugin_IsMidiEffect
juce::ignoreUnused(layouts);
return true;
#else
if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono()
&& layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo())
return false;
#if ! JucePlugin_IsSynth
if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
return false;
#endif
return true;
#endif
}
#endif
void WrapperTestAudioProcessor::processBlock(juce::AudioBuffer& buffer, juce::MidiBuffer& midiMessages)
{
juce::ScopedNoDenormals noDenormals;
auto totalNumInputChannels = getTotalNumInputChannels();
auto totalNumOutputChannels = getTotalNumOutputChannels();
wrappedInstance->processBlock(buffer, midiMessages);
}
bool WrapperTestAudioProcessor::hasEditor() const
{
return true;
}
juce::AudioProcessorEditor* WrapperTestAudioProcessor::createEditor()
{
return new WrapperTestAudioProcessorEditor(this);
}
juce::AudioProcessorEditor WrapperTestAudioProcessor::getWrappedInstanceEditor()
{
return wrappedInstance->createEditorIfNeeded();
}
void WrapperTestAudioProcessor::getStateInformation(juce::MemoryBlock& destData)
{
wrappedInstance->getStateInformation(destData);
}
void WrapperTestAudioProcessor::setStateInformation(const void* data, int sizeInBytes)
{
wrappedInstance->setStateInformation(data, sizeInBytes);
}
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
return new WrapperTestAudioProcessor();
}
// PluginEditor.h
#pragma once
#include <JuceHeader.h>
#include “PluginProcessor.h”class WrapperTestAudioProcessorEditor : public juce::AudioProcessorEditor
{
public:
WrapperTestAudioProcessorEditor(WrapperTestAudioProcessor&);
~WrapperTestAudioProcessorEditor() override;
void paint(juce::Graphics&) override;
void paintOverChildren(juce::Graphics&) override;
void resized() override;
private:
WrapperTestAudioProcessor& audioProcessor;
AudioProcessorEditor* wrappedEditor;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WrapperTestAudioProcessorEditor)
};
// PluginEditor.cpp
#include “PluginProcessor.h”
#include “PluginEditor.h”WrapperTestAudioProcessorEditor::WrapperTestAudioProcessorEditor(WrapperTestAudioProcessor& p)
: AudioProcessorEditor(&p), audioProcessor(p)
{
wrappedEditor = audioProcessor.getWrappedInstanceEditor();
addAndMakeVisible(wrappedEditor, -1);
bool visible = wrappedEditor->isVisible();
setSize(wrappedEditor->getWidth(), wrappedEditor->getHeight() + 60);
}
WrapperTestAudioProcessorEditor::~WrapperTestAudioProcessorEditor()
{
// delete wrappedEditor;
}
void WrapperTestAudioProcessorEditor::paint(juce::Graphics& g)
{
}
void WrapperTestAudioProcessorEditor::paintOverChildren(juce::Graphics& g)
{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);
}
void WrapperTestAudioProcessorEditor::resized()
{
wrappedEditor->setTopLeftPosition(0, 60);
}