Having trouble with "Load XML" in Faust-generated project

Continuing on specifically from the previous thread Having some confusion with PGM - #17 by Digital_Larry

I have whittled down the Faust generated cpp file (which includes all header info as well) to those functions which mention “magic” somehow.

/* ------------------------------------------------------------
author: "Gary Worsham"
copyright: "(c) Gary Worsham 2021"
license: "none"
name: "Harmonic Tremolo"
version: "0.95"
Code generated with Faust 2.32.17 (https://faust.grame.fr)
Compilation options: -a /usr/local/share/faust/juce/juce-plugin.cpp -lang cpp -es 1 -single -ftz 0
------------------------------------------------------------ */


// Using the PluginGuiMagic project (https://foleysfinest.com/developer/pluginguimagic/)

#if defined(PLUGIN_MAGIC)

class FaustPlugInAudioProcessor : public foleys::MagicProcessor, private juce::Timer
{
    
public:
//    juce::AudioProcessorValueTreeState treeState{ *this, nullptr };

    FaustPlugInAudioProcessor();
    virtual ~FaustPlugInAudioProcessor() {}
    
    void prepareToPlay (double sampleRate, int samplesPerBlock) override;
    
    bool isBusesLayoutSupported (const BusesLayout& layouts) const override;
    
    void processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages) override
    {
        jassert (! isUsingDoublePrecision());
        process (buffer, midiMessages);
    }
    
    void processBlock (juce::AudioBuffer<double>& buffer, juce::MidiBuffer& midiMessages) override
    {
        jassert (isUsingDoublePrecision());
        process (buffer, midiMessages);
    }
    
    const juce::String getName() const override;
    
    bool acceptsMidi() const override;
    bool producesMidi() 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 releaseResources() override
    {}
    
    void timerCallback() override;
    
    juce::AudioProcessor::BusesProperties getBusesProperties();
    bool supportsDoublePrecisionProcessing() const override;
    
#ifdef JUCE_POLY
    std::unique_ptr<FaustSynthesiser> fSynth;
#else
#if defined(MIDICTRL)
    std::unique_ptr<juce_midi_handler> fMIDIHandler;
    std::unique_ptr<MidiUI> fMIDIUI;
#endif
    std::unique_ptr<faustdsp> fDSP;
#endif
    
#if defined(OSCCTRL)
    std::unique_ptr<JuceOSCUI> fOSCUI;
#endif
    
#if defined(SOUNDFILE)
    std::unique_ptr<SoundUI> fSoundUI;
#endif
    
    JuceStateUI fStateUI;
    JuceParameterUI fParameterUI;

private:
    
    template <typename FloatType>
    void process (juce::AudioBuffer<FloatType>& buffer, juce::MidiBuffer& midiMessages);
    
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FaustPlugInAudioProcessor)
    
};

#else

...
    
};

#endif

#ifndef PLUGIN_MAGIC
FaustPlugInAudioProcessor::FaustPlugInAudioProcessor()
: juce::AudioProcessor (getBusesProperties()), fParameterUI(this)
#else
FaustPlugInAudioProcessor::FaustPlugInAudioProcessor()
: foleys::MagicProcessor (getBusesProperties()), fParameterUI(this)	
#endif
{
    bool midi_sync = false;
    int nvoices = 0;
    
    mydsp* tmp_dsp = new mydsp();
    MidiMeta::analyse(tmp_dsp, midi_sync, nvoices);
    delete tmp_dsp;
	
#ifdef PLUGIN_MAGIC
	// Digital Larry - I added these two lines and commented out the following one
	// to see if it has any effect on the load XML function.
    auto defaultGUI = magicState.createDefaultGUITree();
    magicState.setGuiValueTree(defaultGUI);
//    magicState.setGuiValueTree(BinaryData::magic_xml, BinaryData::magic_xmlSize);
#endif
   
...
    
    
}

#ifndef PLUGIN_MAGIC
bool FaustPlugInAudioProcessor::hasEditor() const
{
    return true;
}

//==============================================================================
juce::AudioProcessorEditor* FaustPlugInAudioProcessor::createEditor()
{
    // You add the XML into BinaryData later. At the beginning just leave those 
    // arguments out and you get a default generated editor.
//    return new foleys::MagicPluginEditor(magicState, BinaryData::magic_xml, BinaryData::magic_xmlSize);
      return new FaustPlugInAudioProcessorEditor (*this);
}

//==============================================================================
void FaustPlugInAudioProcessor::getStateInformation (juce::MemoryBlock& destData)
{
    // You should use this method to store your parameters in the memory block.
    // You could do that either as raw data, or use the XML or ValueTree classes
    // as intermediaries to make it easy to save and load complex data.
    
    fStateUI.getStateInformation(destData);
}

void FaustPlugInAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
    // You should use this method to restore your parameters from this memory block,
    // whose contents will have been created by the getStateInformation() call.
    
    fStateUI.setStateInformation(data, sizeInBytes);
 }
#endif

Here is the Signal Generator .cpp and .h files similarly edited.

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

    This file was auto-generated!

    It contains the basic framework code for a JUCE plugin processor.

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

#include "PluginProcessor.h"
//==============================================================================
SignalGeneratorAudioProcessor::SignalGeneratorAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
     : foleys::MagicProcessor (juce::AudioProcessor::BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  juce::AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", juce::AudioChannelSet::stereo(), true)
                     #endif
                       ),
#else
    :
#endif
    treeState (*this, nullptr, "PARAMETERS", createParameterLayout())
{
    frequency = treeState.getRawParameterValue (IDs::mainFreq);
    jassert (frequency != nullptr);
    level = treeState.getRawParameterValue (IDs::mainLevel);
    jassert (level != nullptr);

    lfoFrequency = treeState.getRawParameterValue (IDs::lfoFreq);
    jassert (lfoFrequency != nullptr);
    lfoLevel = treeState.getRawParameterValue (IDs::lfoLevel);
    jassert (lfoLevel != nullptr);

    vfoFrequency = treeState.getRawParameterValue (IDs::vfoFreq);
    jassert (vfoFrequency != nullptr);
    vfoLevel = treeState.getRawParameterValue (IDs::vfoLevel);
    jassert (vfoLevel != nullptr);

    treeState.addParameterListener (IDs::mainType, this);
    treeState.addParameterListener (IDs::lfoType, this);
    treeState.addParameterListener (IDs::vfoType, this);

    // MAGIC GUI: register an oscilloscope to display in the GUI.
    //            We keep a pointer to push samples into in processBlock().
    //            And we are only interested in channel 0
    oscilloscope = magicState.createAndAddObject<foleys::MagicOscilloscope>(IDs::oscilloscope, 0);
	// Digital Larry - I added these two lines and commented out the following one
	// to see if it has any effect on the load XML function.
    auto defaultGUI = magicState.createDefaultGUITree();
    magicState.setGuiValueTree(defaultGUI);
//    magicState.setGuiValueTree (BinaryData::magic_xml, BinaryData::magic_xmlSize);
}

void SignalGeneratorAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    // Use this method as the place to do any pre-playback
    // initialisation that you need..

    const auto numChannels = getTotalNumOutputChannels();

    juce::dsp::ProcessSpec spec;
    spec.sampleRate = sampleRate;
    spec.maximumBlockSize = juce::uint32 (samplesPerBlock);
    spec.numChannels = juce::uint32 (numChannels);

    mainOSC.prepare (spec);
    lfoOSC.prepare (spec);
    vfoOSC.prepare (spec);

    setOscillator (mainOSC, WaveType (juce::roundToInt (treeState.getRawParameterValue (IDs::mainType)->load())));
    setOscillator (lfoOSC, WaveType (juce::roundToInt (treeState.getRawParameterValue (IDs::lfoType)->load())));
    setOscillator (vfoOSC, WaveType (juce::roundToInt (treeState.getRawParameterValue (IDs::vfoType)->load())));

    // MAGIC GUI: this will setup all internals like MagicPlotSources etc.
    magicState.prepareToPlay (sampleRate, samplesPerBlock);
}


void SignalGeneratorAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
    ignoreUnused (midiMessages);

    juce::ScopedNoDenormals noDenormals;
    auto totalNumInputChannels  = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();

    // In case we have more outputs than inputs, this code clears any output
    // channels that didn't contain input data, (because these aren't
    // guaranteed to be empty - they may contain garbage).
    // This is here to avoid people getting screaming feedback
    // when they first compile a plugin, but obviously you don't need to keep
    // this code if your algorithm always overwrites all the output channels.
    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear (i, 0, buffer.getNumSamples());


    auto gain = juce::Decibels::decibelsToGain (level->load());

    lfoOSC.setFrequency (*lfoFrequency);
    vfoOSC.setFrequency (*vfoFrequency);

    auto* channelData = buffer.getWritePointer (0);
    for (int i = 0; i < buffer.getNumSamples(); ++i)
    {
        mainOSC.setFrequency (frequency->load() * (1.0 + vfoOSC.processSample (0.0f) * vfoLevel->load()));
        channelData [i] = juce::jlimit (-1.0f, 1.0f,
                                  mainOSC.processSample (0.0f) * gain * ( 1.0f - (lfoLevel->load() * lfoOSC.processSample (0.0f))));
    }

    for (int i=1; i < getTotalNumOutputChannels(); ++i)
        buffer.copyFrom (i, 0, buffer.getReadPointer (0), buffer.getNumSamples());

    // MAGIC GUI: push the samples to be displayed
    oscilloscope->pushSamples (buffer);
}
/*
  ==============================================================================

    This file was auto-generated!

    It contains the basic framework code for a JUCE plugin processor.

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

#pragma once

#include "../JuceLibraryCode/JuceHeader.h"

//==============================================================================
/**
*/
class SignalGeneratorAudioProcessor  : public  foleys::MagicProcessor,
                                       private juce::AudioProcessorValueTreeState::Listener
{
public:
    enum WaveType
    {
        None = 0,
        Sine,
        Triangle,
        Square
    };

    //==============================================================================
    SignalGeneratorAudioProcessor();
    ~SignalGeneratorAudioProcessor();

    //==============================================================================
    void prepareToPlay (double sampleRate, int samplesPerBlock) override;
    void releaseResources() override;

   #ifndef JucePlugin_PreferredChannelConfigurations
    bool isBusesLayoutSupported (const juce::AudioProcessor::BusesLayout& layouts) const override;
   #endif

    void parameterChanged (const juce::String& param, float value) override;

    void processBlock (juce::AudioBuffer<float>&, juce::MidiBuffer&) override;

    //==============================================================================
    double getTailLengthSeconds() const override;

private:
    //==============================================================================

    void setOscillator (juce::dsp::Oscillator<float>& osc, WaveType type);

    std::atomic<float>* frequency  = nullptr;
    std::atomic<float>* level      = nullptr;

    std::atomic<float>* lfoFrequency  = nullptr;
    std::atomic<float>* lfoLevel      = nullptr;

    std::atomic<float>* vfoFrequency  = nullptr;
    std::atomic<float>* vfoLevel      = nullptr;

    juce::dsp::Oscillator<float> mainOSC;
    juce::dsp::Oscillator<float> lfoOSC;
    juce::dsp::Oscillator<float> vfoOSC;

    juce::AudioProcessorValueTreeState treeState;

    // MAGIC GUI: this is a shorthand where the samples to display are fed to
    foleys::MagicPlotSource*    oscilloscope = nullptr;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SignalGeneratorAudioProcessor)
};

There are some differences.

This, I attribute to the Signal Generator loading binary resources, while I have not yet done that.

	// Digital Larry - I added these two lines and commented out the following one
	// to see if it has any effect on the load XML function.
    auto defaultGUI = magicState.createDefaultGUITree();
    magicState.setGuiValueTree(defaultGUI);
//    magicState.setGuiValueTree (BinaryData::magic_xml, BinaryData::magic_xmlSize);

The are several other places also where specific calls are made to support the plot component which I do not have. It’s still not leaping out at me as to what I’ve done wrong.

Here’s the harmonicTrem.jucer.

<?xml version="1.0" encoding="UTF-8"?>

<JUCERPROJECT id="L9dULy" name="harmonicTrem" projectType="audioplug" version="1.0.0"
              bundleIdentifier="com.grame.harmonicTrem" includeBinaryInAppConfig="1"
              buildVST="0" buildVST3="1" buildAU="0" buildAUv3="0" buildRTAS="0"
              buildAAX="0" buildStandalone="1" pluginName="harmonicTrem" pluginDesc="harmonicTrem"
              pluginManufacturer="GRAME" pluginManufacturerCode="Manu" pluginCode="8959"
              pluginChannelConfigs="" pluginIsSynth="0" pluginWantsMidiIn="0"
              pluginProducesMidiOut="0" pluginIsMidiEffectPlugin="0" pluginEditorRequiresKeys="0"
              pluginAUExportPrefix="harmonicTremAU" pluginRTASCategory="" aaxIdentifier="com.grame.harmonicTrem"
              pluginAAXCategory="2" pluginFormats="buildAU,buildAUv3,buildVST3,buildStandalone"
              displaySplashScreen="1" jucerFormatVersion="1" enableIAA="0"
              pluginCharacteristicsValue="">
  <MAINGROUP id="DIThxi" name="harmonicTrem">
    <GROUP id="{3EA8B881-7A5A-9E29-6E83-82528C15E424}" name="Source">
      <FILE id="BecAMR" name="FaustPluginProcessor.cpp" compile="1" resource="0"
            file="FaustPluginProcessor.cpp"/>
    </GROUP>
  </MAINGROUP>
  <EXPORTFORMATS>
    <VS2019 targetFolder="Builds/VisualStudio2019" extraDefs="PLUGIN_MAGIC"
            extraCompilerFlags="-DNVOICES=NUM_VOICES -DFAUSTFLOAT=float">
      <CONFIGURATIONS>
        <CONFIGURATION isDebug="1" name="Debug"/>
        <CONFIGURATION isDebug="0" name="Release"/>
      </CONFIGURATIONS>
      <MODULEPATHS>
        <MODULEPATH id="juce_osc"/>
        <MODULEPATH id="juce_opengl"/>
        <MODULEPATH id="juce_gui_extra"/>
        <MODULEPATH id="juce_gui_basics"/>
        <MODULEPATH id="juce_graphics"/>
        <MODULEPATH id="juce_events"/>
        <MODULEPATH id="juce_data_structures"/>
        <MODULEPATH id="juce_core"/>
        <MODULEPATH id="juce_audio_utils"/>
        <MODULEPATH id="juce_audio_processors"/>
        <MODULEPATH id="juce_audio_plugin_client"/>
        <MODULEPATH id="juce_audio_formats"/>
        <MODULEPATH id="juce_audio_devices"/>
        <MODULEPATH id="juce_audio_basics"/>
        <MODULEPATH id="juce_dsp" path="C:/Program Files/JUCE/JUCE/modules"/>
        <MODULEPATH id="juce_cryptography" path="C:/Program Files/JUCE/JUCE/modules"/>
        <MODULEPATH id="foleys_gui_magic" path="../../JUCE Projects"/>
      </MODULEPATHS>
    </VS2019>
  </EXPORTFORMATS>
  <MODULES>
    <MODULE id="foleys_gui_magic" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_audio_devices" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_audio_formats" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_audio_plugin_client" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_audio_processors" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_audio_utils" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_core" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_cryptography" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_data_structures" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_dsp" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_events" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_graphics" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_gui_basics" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_gui_extra" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_opengl" showAllCode="1" useLocalCopy="0"/>
    <MODULE id="juce_osc" showAllCode="1" useLocalCopy="0"/>
  </MODULES>
  <JUCEOPTIONS JUCE_QUICKTIME="disabled" JUCE_VST3_CAN_REPLACE_VST2="0" FOLEYS_SAVE_EDITED_GUI_IN_PLUGIN_STATE="0"
               FOLEYS_ENABLE_BINARY_DATA="0"/>
  <LIVE_SETTINGS>
    <WINDOWS/>
  </LIVE_SETTINGS>
</JUCERPROJECT>

Here’s SignalGenerator.jucer

<?xml version="1.0" encoding="UTF-8"?>

<JUCERPROJECT id="T33gqD" name="SignalGenerator" projectType="audioplug" pluginAUMainType="'aufx'"
              pluginVST3Category="Generator" pluginRTASCategory="2048" pluginAAXCategory="2048"
              pluginVSTCategory="kPlugCategGenerator" projectLineFeed="&#10;"
              companyName="Foleys Finest Audio" companyWebsite="https://foleysfinest.com"
              bundleIdentifier="com.foleysfinest.signalgenerator" pluginManufacturerCode="FFAU"
              addUsingNamespaceToJuceHeader="0" jucerFormatVersion="1" displaySplashScreen="1">
  <MAINGROUP id="KtcAG2" name="SignalGenerator">
    <GROUP id="{C9FD3DD7-E1DA-CA2D-54CB-B4D603FF3A7D}" name="Source">
      <FILE id="GPUQn8" name="PluginProcessor.cpp" compile="1" resource="0"
            file="Source/PluginProcessor.cpp"/>
      <FILE id="DEaCAP" name="PluginProcessor.h" compile="0" resource="0"
            file="Source/PluginProcessor.h"/>
    </GROUP>
    <GROUP id="{C27362CC-14CC-858C-78D2-E93C371A29FD}" name="Resources">
      <FILE id="eLL4zv" name="magic.xml" compile="0" resource="1" file="Resources/magic.xml"/>
    </GROUP>
  </MAINGROUP>
  <EXPORTFORMATS>
    <VS2019 targetFolder="Builds/VisualStudio2019">
      <CONFIGURATIONS>
        <CONFIGURATION isDebug="1" name="Debug"/>
        <CONFIGURATION isDebug="0" name="Release" defines="FOLEYS_SHOW_GUI_EDITOR_PALLETTE=0"/>
      </CONFIGURATIONS>
      <MODULEPATHS>
        <MODULEPATH id="juce_audio_basics" path="C:\Program Files\JUCE\JUCE\modules"/>
        <MODULEPATH id="juce_audio_devices" path="C:\Program Files\JUCE\JUCE\modules"/>
        <MODULEPATH id="juce_audio_formats" path="C:\Program Files\JUCE\JUCE\modules"/>
        <MODULEPATH id="juce_audio_plugin_client" path="../../JUCE/modules"/>
        <MODULEPATH id="juce_audio_processors" path="C:\Program Files\JUCE\JUCE\modules"/>
        <MODULEPATH id="juce_audio_utils" path="C:\Program Files\JUCE\JUCE\modules"/>
        <MODULEPATH id="juce_core" path="../../JUCE/modules"/>
        <MODULEPATH id="juce_cryptography" path="../../JUCE/modules"/>
        <MODULEPATH id="juce_data_structures" path="../../JUCE/modules"/>
        <MODULEPATH id="juce_events" path="../../JUCE/modules"/>
        <MODULEPATH id="juce_graphics" path="../../JUCE/modules"/>
        <MODULEPATH id="juce_gui_basics" path="../../JUCE/modules"/>
        <MODULEPATH id="juce_gui_extra" path="../../JUCE/modules"/>
        <MODULEPATH id="juce_opengl" path="../../JUCE/modules"/>
        <MODULEPATH id="juce_dsp" path="../../JUCE/modules"/>
        <MODULEPATH id="foleys_gui_magic" path="../../../../JUCE Projects"/>
      </MODULEPATHS>
    </VS2019>
  </EXPORTFORMATS>
  <MODULES>
    <MODULE id="foleys_gui_magic" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_audio_devices" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_audio_formats" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_audio_plugin_client" showAllCode="1" useLocalCopy="0"
            useGlobalPath="1"/>
    <MODULE id="juce_audio_processors" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_audio_utils" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_core" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_cryptography" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_data_structures" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_dsp" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_events" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_graphics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_gui_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_gui_extra" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
    <MODULE id="juce_opengl" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
  </MODULES>
  <LIVE_SETTINGS>
    <WINDOWS/>
  </LIVE_SETTINGS>
  <JUCEOPTIONS JUCE_VST3_CAN_REPLACE_VST2="0" JUCE_STRICT_REFCOUNTEDPOINTER="1"
               JUCE_PLUGINHOST_VST3="1"/>
</JUCERPROJECT>

I’m starting to think that perhaps the issue is Faust-specific. For example, the project already has a bunch of controls defined that show up when using JUCE without the gui Magic module added. Maybe this prevents the loading somehow?

I tried finding the place in the code where “Load XML” does something. While I could set a breakpoint to occur just before the File Load dialog pops up, single stepping or stepping “out” from here just took me through what looks like a bunch of low level code. @daniel is there a function that I can set a breakpoint at to see what is really going on when it tries to load the XML?

Here’s a bit of code that seems important that is not getting executed. So one or the other of the conditions is not being met.

image

I think it’s not null, so it’s valid.

getType()

image

I’m pretty sure the getType call is failing.

@daniel any suggestion as to what to look at?

Hang on, are you trying to load jucer files? The Toolbox load file is not meant for that.
You can only load xml files that you stored before using the PluginGuiMagic toolbox.

In that case it is correct of PGM to reject the XML.

No, I am trying to load the XML file which I just saved.

For example:

<?xml version="1.0" encoding="UTF-8"?>

<View id="root">
  <Styles>
    <Style name="default">
      <Nodes/>
      <Classes>
        <plot-view border="2" background-color="black" border-color="silver" display="contents"/>
        <nomargin margin="0" padding="0" border="0"/>
        <group margin="5" padding="5" border="2" flex-direction="column"/>
      </Classes>
      <Types>
        <Slider border="0" slider-textbox="textbox-below"/>
        <ToggleButton border="0" max-height="50" caption-size="0" text="Active"/>
        <TextButton border="0" max-height="50" caption-size="0"/>
        <ComboBox border="0" max-height="50" caption-size="0"/>
        <Plot border="0" margin="0" padding="0" background-color="00000000"
              radius="0"/>
        <XYDragComponent border="0" margin="0" padding="0" background-color="00000000"
                         radius="0"/>
      </Types>
      <Palettes>
        <default/>
      </Palettes>
    </Style>
  </Styles>
  <View id="root">
    <View caption="Low">
      <Slider caption="Res" parameter="/Harmonic_Tremolo/Hi/Res" slider-type="rotary"
              width="40" height="120"/>
      <Slider caption="Ratio" parameter="/Harmonic_Tremolo/Hi/Ratio" slider-type="rotary"
              width="40" height="120"/>
      <Slider caption="Freq" parameter="/Harmonic_Tremolo/Hi/Freq" slider-type="rotary"
              width="40" height="120"/>
      <Slider caption="Delta" parameter="/Harmonic_Tremolo/Hi/Delta" slider-type="rotary"
              width="40" height="120"/>
    </View>
    <View caption="LFO">
      <Slider caption="Width" parameter="/Harmonic_Tremolo/LFO/Width" slider-type="rotary"
              width="40" height="120"/>
      <Slider caption="Rate" parameter="/Harmonic_Tremolo/LFO/Rate" slider-type="rotary"
              width="40" height="120"/>
    </View>
    <View caption="High">
      <Slider caption="Res" parameter="/Harmonic_Tremolo/Low/Res" slider-type="rotary"
              width="40" height="120"/>
      <Slider caption="Ratio" parameter="/Harmonic_Tremolo/Low/Ratio" slider-type="rotary"
              width="40" height="120"/>
      <Slider caption="Freq" parameter="/Harmonic_Tremolo/Low/Freq" slider-type="rotary"
              width="40" height="120"/>
      <Slider caption="Delta" parameter="/Harmonic_Tremolo/Low/Delta" slider-type="rotary"
              width="40" height="120"/>
    </View>
  </View>
</View>
 

Thanks, now there is something to go on. I must have screwed something up.
The XML file should be one level up and be of type <magic>.

Please bear with me, I will come up with a fix.

Thanks for your patience!

Cool, thanks. The examples work! Weird.

I can explain what happened and will work on a fix asap.

Previously there was a fallback that created the default GUI in case none was loaded. But that was error prone especially in combination with storing the last GUI tree in the plugin state.

When I changed that and provided the example how to populate with a default GUI I lost one level where the StyleClasses, the Component defaults and the Colour palettes were defined.

That explains a few open issues on the forum at the moment.