Hi, when opening the following class on demand, everything works fine until i close the application, where several leaking object warnings arise. I have tried several approaches but i am not able to close the app without warnings. Could somebody please tell me how to open such a window with an AudioPluginInstance’s editor correctly in order not to see a huge amount of leaking objects at the end? Thank you very much.
The warnings (with different VST plugins loaded) are:
*** Leaked objects detected: 1 instance(s) of class VSTPluginWindow
JUCE Assertion failure in juce_LeakedObjectDetector.h:97
*** Leaked objects detected: 1 instance(s) of class ComponentBoundsConstrainer
JUCE Assertion failure in juce_LeakedObjectDetector.h:97
*** Leaked objects detected: 1 instance(s) of class Component
JUCE Assertion failure in juce_LeakedObjectDetector.h:97
*** Leaked objects detected: 1 instance(s) of class MouseCursor
JUCE Assertion failure in juce_LeakedObjectDetector.h:97
Thank you Daniel. The version you see is just one of many i tried.
When i use a ScopedPointer for the editor and close the application the whole thing crashes:
The crash seems to me that two objects own the editor, so it is crucial to make sure everything is only owned once.
I am not sure, it might be related to setContentOwned(comp, true);. As you said, it is in flux, maybe you hand over ownership there? In the posted version it is the unowned comp instance, but who knows…
I think you can get rid of the whole comp thing and add the editor directly as content?
Also, if the window now owns the editor, either remove the editor pointer completely, or if you need a pointer outside the construction, consider to use a SafePointer instead. The drawback is you need to check if it is not nullptr before using it each time.
A trick with ScopedPointers I often do is, use them even inside functions:
ScopedPointer<AudioPluginEditor> editor = instance->createEditor();
// even if you add a return here later, you don't need to cleanup. Only as example...
if (somethingWentWrong)
return;
// then hand over the ownership:
setContentOwned (editor.release(), true);
This seems also inconsistent:
Either instance and editor are ScopedPointers, then they are deleted by that statement. Or like in your posted version if they are raw pointers, this statement has no effect, because it’s the last place to see these variables before they are gone.
thank you very much for your tips. I got it finally working! Now i can close and reopen SynthWindow objects for different synths and close them or the whole application without any crash or memory leaks anymore.
Here is my solution:
class PresetsListComponent::SynthWindow : public DocumentWindow
{
public:
SynthWindow (PresetsListComponent& owner_, const int synthId)
: DocumentWindow ("", Colours::lightgrey, DocumentWindow::allButtons),
owner (owner_)
{
audioDeviceManager = new AudioDeviceManager();
audioDeviceManager->initialiseWithDefaultDevices(2, 2);
graph = new AudioProcessorGraph();
player = new AudioProcessorPlayer();
rescanMidiDevices();
buildBasicGraph();
pluginFormatManager = new AudioPluginFormatManager();
pluginFormatManager->addDefaultFormats();
ScopedPointer<Synth> synth = AudioController::getInstance().getSynthForId(synthId);
if (synth != nullptr) {
KnownPluginList plist;
OwnedArray<juce::PluginDescription> pluginDescriptions;
juce::VSTPluginFormat format;
plist.scanAndAddFile(synth->pluginPath, true, pluginDescriptions, format);
if (pluginDescriptions.size() > 0) {
String msg;
AudioPluginInstance* instance = pluginFormatManager->createPluginInstance(*pluginDescriptions[0], 0, 0, msg);
AudioProcessorGraph::Node* newPluginNode = graph->addNode(instance, NodeId::Plugin);
// add midi in to plugin node
graph->addConnection(
graph->getNodeForId(NodeId::MidiIn)->nodeId, AudioProcessorGraph::midiChannelIndex,
newPluginNode->nodeId, AudioProcessorGraph::midiChannelIndex);
// Add pluginNode to audio out in stereo
graph->addConnection(newPluginNode->nodeId, 0, graph->getNodeForId(NodeId::AudioOut)->nodeId, 0);
graph->addConnection(newPluginNode->nodeId, 1, graph->getNodeForId(NodeId::AudioOut)->nodeId, 1);
player->setProcessor(graph);
audioDeviceManager->addAudioCallback(player);
setContentOwned(instance->createEditor(), true);
setResizable(false, false);
setVisible (true);
}
}
}
~SynthWindow()
{
audioDeviceManager->removeAudioCallback(player);
clearContentComponent();
}
void closeButtonPressed()
{
owner.synthWindow = nullptr;
}
}
All member variables (like audioDeviceManager) are ScopedPointers and the editor is added now directly as owned content.
Works like a charm, thanks again!
Regards
ricochet