From 374394330f1b5a9641f221c1bb7c9855faee694d Mon Sep 17 00:00:00 2001 From: Alex Birch Date: Mon, 8 Jul 2019 23:36:27 +0100 Subject: [PATCH] successfully save/load ui width/height --- .../xcschemes/juicysfplugin - AU.xcscheme | 84 ++++++++++++ .../xcschemes/juicysfplugin - All.xcscheme | 2 +- ...juicysfplugin - Standalone Plugin.xcscheme | 9 +- .../xcschemes/juicysfplugin - VST.xcscheme | 84 ++++++++++++ .../xcschemes/juicysfplugin - VST3.xcscheme | 4 + Source/PluginEditor.cpp | 127 +++++++++++------- Source/PluginEditor.h | 31 +++-- Source/PluginProcessor.cpp | 61 ++++++++- 8 files changed, 329 insertions(+), 73 deletions(-) create mode 100644 Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - AU.xcscheme create mode 100644 Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - VST.xcscheme diff --git a/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - AU.xcscheme b/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - AU.xcscheme new file mode 100644 index 0000000..6ec7b0e --- /dev/null +++ b/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - AU.xcscheme @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - All.xcscheme b/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - All.xcscheme index bee1ae6..f8aae0e 100644 --- a/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - All.xcscheme +++ b/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - All.xcscheme @@ -33,7 +33,7 @@ - + + + - + diff --git a/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - VST.xcscheme b/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - VST.xcscheme new file mode 100644 index 0000000..0d99cec --- /dev/null +++ b/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - VST.xcscheme @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - VST3.xcscheme b/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - VST3.xcscheme index f1ab27e..b6c7b9d 100644 --- a/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - VST3.xcscheme +++ b/Builds/MacOSX/juicysfplugin.xcodeproj/xcshareddata/xcschemes/juicysfplugin - VST3.xcscheme @@ -42,6 +42,10 @@ debugDocumentVersioning = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> + + (param) != nullptr); // AudioParameterInt* castParam {dynamic_cast (param)}; // width = castParam->get(); // } // { - // RangedAudioParameter *param {valueTreeState.getParameter("uiHeight")}; + // RangedAudioParameter *param {valueTreeState.getParameter("uiHeightPersist")}; // jassert(dynamic_cast (param) != nullptr); // AudioParameterInt* castParam {dynamic_cast (param)}; // height = castParam->get(); // } - // valueTreeState.addParameterListener("uiWidthPersist", this); - // valueTreeState.addParameterListener("uiHeightPersist", this); - // valueTreeState.addParameterListener("uiWidth", this); - // valueTreeState.addParameterListener("uiHeight", this); + // valueTreeState.addParameterListener("uiWidthPersist", this); + // valueTreeState.addParameterListener("uiHeightPersist", this); +// valueTreeState.addParameterListener("uiWidth", this); +// valueTreeState.addParameterListener("uiHeight", this); - valueTreeState.state.addListener(this); +// valueTreeState.state.addListener(this); - setSize(GuiConstants::minWidth, GuiConstants::minHeight); + // setSize(GuiConstants::minWidth, GuiConstants::minHeight); + // setSize(width, height); + + lastUIWidth.referTo(valueTreeState.state.getChildWithName("uiState").getPropertyAsValue("width", nullptr)); + lastUIHeight.referTo(valueTreeState.state.getChildWithName("uiState").getPropertyAsValue("height", nullptr)); + + // set our component's initial size to be the last one that was stored in the filter's settings + setSize(lastUIWidth.getValue(), lastUIHeight.getValue()); + + lastUIWidth.addListener(this); + lastUIHeight.addListener(this); // processor.subscribeToStateChanges(this); @@ -71,52 +81,60 @@ JuicySFAudioProcessorEditor::JuicySFAudioProcessorEditor( } +// called when the stored window size changes +void JuicySFAudioProcessorEditor::valueChanged(Value&) { + setSize(lastUIWidth.getValue(), lastUIHeight.getValue()); +} + JuicySFAudioProcessorEditor::~JuicySFAudioProcessorEditor() { - // valueTreeState.removeParameterListener("uiWidthPersist", this); - // valueTreeState.removeParameterListener("uiHeightPersist", this); + lastUIWidth.removeListener(this); + lastUIHeight.removeListener(this); + // valueTreeState.removeParameterListener("uiWidthPersist", this); + // valueTreeState.removeParameterListener("uiHeightPersist", this); // valueTreeState.removeParameterListener("uiWidth", this); // valueTreeState.removeParameterListener("uiHeight", this); - valueTreeState.state.removeListener(this); +// valueTreeState.state.removeListener(this); // processor.unsubscribeFromStateChanges(this); } -void JuicySFAudioProcessorEditor::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasChanged, - const Identifier& property) { - if (&treeWhosePropertyHasChanged == &valueTreeState.state) { - if (property == Identifier("uiWidth")) { - // String soundFontPath{treeWhosePropertyHasChanged.getProperty("soundFontPath", "")}; - // if (soundFontPath.isNotEmpty()) { - // loadFont(soundFontPath); - // } - int value{treeWhosePropertyHasChanged.getProperty("uiWidth", GuiConstants::minWidth)}; - setSize(value, getHeight()); - } else if (property == Identifier("uiHeight")) { - int value{treeWhosePropertyHasChanged.getProperty("uiHeight", GuiConstants::minHeight)}; - setSize(getWidth(), value); - } - } -} +// void JuicySFAudioProcessorEditor::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasChanged, +// const Identifier& property) { +// // if (treeWhosePropertyHasChanged.getType() == Identifier("PARAM")) { +// const String propertyString{property.toString()}; +// if (propertyString == "uiWidth") { +// // String soundFontPath{treeWhosePropertyHasChanged.getProperty("soundFontPath", "")}; +// // if (soundFontPath.isNotEmpty()) { +// // loadFont(soundFontPath); +// // } +// int value{treeWhosePropertyHasChanged.getProperty("uiWidth", GuiConstants::minWidth)}; +// setSize(value, getHeight()); +// } else if (propertyString == "uiHeight") { +// int value{treeWhosePropertyHasChanged.getProperty("uiHeight", GuiConstants::minHeight)}; +// setSize(getWidth(), value); +// } +// // } +// } // void JuicySFAudioProcessorEditor::parameterChanged(const String& parameterID, float newValue) { -// // if (parameterID == "uiWidthPersist" -// // || parameterID == "uiHeightPersist") { -// if (parameterID == "uiWidth" -// || parameterID == "uiHeight") { +// // if (parameterID == "uiWidthPersist" +// // || parameterID == "uiHeightPersist") { +// if (parameterID == "uiWidth" +// || parameterID == "uiHeight") { // RangedAudioParameter *param {valueTreeState.getParameter(parameterID)}; // jassert(dynamic_cast (param) != nullptr); // AudioParameterInt* castParam {dynamic_cast (param)}; // int value{castParam->get()}; -// // if (parameterID == "uiWidthPersist") { -// // setSize(value, getHeight()); -// // } else if (parameterID == "uiHeightPersist") { -// // setSize(getWidth(), value); -// // } // if (parameterID == "uiWidth") { // setSize(value, getHeight()); // } else if (parameterID == "uiHeight") { // setSize(getWidth(), value); // } +// // if (parameterID == "uiWidthPersist") { +// // setSize(value, getHeight()); +// // } else if (parameterID == "uiHeightPersist") { +// // setSize(getWidth(), value); +// // } // } // } @@ -171,21 +189,30 @@ void JuicySFAudioProcessorEditor::resized() tablesComponent.setBounds(rContent); - valueTreeState.state.setPropertyExcludingListener(this, "uiWidth", getWidth(), nullptr); - valueTreeState.state.setPropertyExcludingListener(this, "uiHeight", getHeight(), nullptr); + lastUIWidth = getWidth(); + lastUIHeight = getHeight(); + + // valueTreeState.state.setPropertyExcludingListener(this, "uiWidth", getWidth(), nullptr); + // valueTreeState.state.setPropertyExcludingListener(this, "uiHeight", getHeight(), nullptr); - // { - // RangedAudioParameter *param {valueTreeState.getParameter("uiWidth2")}; - // jassert(dynamic_cast (param) != nullptr); - // AudioParameterInt* castParam {dynamic_cast (param)}; - // *castParam = getWidth(); - // } - // { - // RangedAudioParameter *param {valueTreeState.getParameter("uiHeight2")}; - // jassert(dynamic_cast (param) != nullptr); - // AudioParameterInt* castParam {dynamic_cast (param)}; - // *castParam = getHeight(); - // } +// { +// // RangedAudioParameter *param {valueTreeState.getParameter("uiWidthTemp")}; +// RangedAudioParameter *param {valueTreeState.getParameter("uiWidth")}; +// // param->setValueNotifyingHost(param->convertTo0to1(getWidth())); +// jassert(dynamic_cast (param) != nullptr); +// AudioParameterInt* castParam {dynamic_cast (param)}; +// *castParam = getWidth(); +// // castParam->AudioProcessorParameter::setValue(castParam->convertTo0to1(static_cast(getWidth()))); +// } +// { +// // RangedAudioParameter *param {valueTreeState.getParameter("uiHeightTemp")}; +// RangedAudioParameter *param {valueTreeState.getParameter("uiHeight")}; +// // param->setValueNotifyingHost(param->convertTo0to1(getHeight())); +// jassert(dynamic_cast (param) != nullptr); +// AudioParameterInt* castParam {dynamic_cast (param)}; +// *castParam = getHeight(); +// // castParam->AudioProcessorParameter::setValue(castParam->convertTo0to1(static_cast(getHeight()))); +// } // sharedParams.setUiWidth(getWidth()); // sharedParams.setUiHeight(getHeight()); diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 68ed6f5..1e39902 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -26,7 +26,8 @@ class JuicySFAudioProcessorEditor : public AudioProcessorEditor // , public AudioProcessorValueTreeState::Listener -, public ValueTree::Listener +, private Value::Listener +// , public ValueTree::Listener /*, , public ExposesComponents public StateChangeSubscriber*/ @@ -55,19 +56,20 @@ public: // int getWidth(); // int getHeight(); - virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, - const Identifier& property) override; - inline virtual void valueTreeChildAdded (ValueTree& parentTree, - ValueTree& childWhichHasBeenAdded) override {}; - inline virtual void valueTreeChildRemoved (ValueTree& parentTree, - ValueTree& childWhichHasBeenRemoved, - int indexFromWhichChildWasRemoved) override {}; - inline virtual void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved, - int oldIndex, int newIndex) override {}; - inline virtual void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) override {}; - inline virtual void valueTreeRedirected (ValueTree& treeWhichHasBeenChanged) override {}; + // virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, + // const Identifier& property) override; + // inline virtual void valueTreeChildAdded (ValueTree& parentTree, + // ValueTree& childWhichHasBeenAdded) override {}; + // inline virtual void valueTreeChildRemoved (ValueTree& parentTree, + // ValueTree& childWhichHasBeenRemoved, + // int indexFromWhichChildWasRemoved) override {}; + // inline virtual void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved, + // int oldIndex, int newIndex) override {}; + // inline virtual void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) override {}; + // inline virtual void valueTreeRedirected (ValueTree& treeWhichHasBeenChanged) override {}; private: + void valueChanged (Value&) override; // This reference is provided as a quick way for your editor to // access the processor object that created it. @@ -76,6 +78,11 @@ private: AudioProcessorValueTreeState& valueTreeState; // SharesParams& sharedParams; + // these are used to persist the UI's size - the values are stored along with the + // filter's other parameters, and the UI component will update them when it gets + // resized. + Value lastUIWidth, lastUIHeight; + SurjectiveMidiKeyboardComponent midiKeyboard; TablesComponent tablesComponent; FilePicker filePicker; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 952cf2c..d683e70 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -33,12 +33,19 @@ JuicySFAudioProcessor::JuicySFAudioProcessor() , valueTreeState{ *this, nullptr, - { "MYPLUGINSETTINGS" }, + "MYPLUGINSETTINGS", createParameterLayout()} , fluidSynthModel{valueTreeState, valueTree} //, fluidSynthModel{*this} //, pluginEditor(nullptr) { + valueTreeState.state.appendChild({ "uiState", { + { "width", GuiConstants::minWidth }, + { "height", GuiConstants::minHeight } + }, {} }, nullptr); + valueTreeState.state.setProperty("soundFontPath", "", nullptr); +// valueTreeState.state.appendChild({ "soundFontPath", {} }, nullptr); + initialiseSynth(); } @@ -57,8 +64,8 @@ AudioProcessorValueTreeState::ParameterLayout JuicySFAudioProcessor::createParam // make_unique("uiHeightPersist", "height of this plugin's GUI. Editor listens for changes (e.g. on load)", GuiConstants::minHeight, GuiConstants::maxHeight, GuiConstants::minHeight, "UI Height Persist" ), // make_unique("uiWidthTemp", "width of this plugin's GUI. Editor writes here on change (e.g. on window resize). Processor copies this into Persist before any save.", GuiConstants::minWidth, GuiConstants::maxWidth, GuiConstants::minWidth, "UI Width Temp" ), // make_unique("uiHeightTemp", "height of this plugin's GUI. Editor writes here on change (e.g. on window resize). Processor copies this into Persist before any save.", GuiConstants::minHeight, GuiConstants::maxHeight, GuiConstants::minHeight, "UI Height Temp" ), - make_unique("uiWidth", "width of this plugin's GUI", GuiConstants::minWidth, GuiConstants::maxWidth, GuiConstants::minWidth, "UI Width" ), - make_unique("uiHeight", "height of this plugin's GUI", GuiConstants::minHeight, GuiConstants::maxHeight, GuiConstants::minHeight, "UI Height" ), + // make_unique("uiWidth", "width of this plugin's GUI", GuiConstants::minWidth, GuiConstants::maxWidth, GuiConstants::minWidth, "UI Width" ), + // make_unique("uiHeight", "height of this plugin's GUI", GuiConstants::minHeight, GuiConstants::maxHeight, GuiConstants::minHeight, "UI Height" ), // todo: check whether bank really is 0-127 make_unique("bank", "which bank is selected in the soundfont", MidiConstants::midiMinValue, MidiConstants::midiMaxValue, MidiConstants::midiMinValue, "Bank" ), // note: banks may be sparse, and lack a 0th preset. so defend against this. @@ -227,7 +234,11 @@ void JuicySFAudioProcessor::processBlock (AudioBuffer& buffer, MidiBuffer switch(static_cast(m.getControllerNumber())) { case SOUND_CTRL2: { // MIDI CC 71 Timbre/Harmonic Intensity (filter resonance) - valueTreeState.state.setProperty({"filterResonance"}, m.getControllerValue(), nullptr); + // valueTreeState.state.setProperty({"filterResonance"}, m.getControllerValue(), nullptr); + RangedAudioParameter *param {valueTreeState.getParameter("filterResonance")}; + jassert(dynamic_cast (param) != nullptr); + AudioParameterInt* castParam {dynamic_cast (param)}; + *castParam = m.getControllerValue(); break; } case SOUND_CTRL3: { // MIDI CC 72 Release time @@ -382,9 +393,11 @@ void JuicySFAudioProcessor::getStateInformation (MemoryBlock& destData) // for (auto* param : getParameters()) // if (auto* p = dynamic_cast (param)) // xml->setAttribute (p->paramID, p->getValue()); - + // then use this helper function to stuff it into the binary blob and return it.. - copyXmlToBinary (*xml, destData); + if (xml.get() != nullptr) { + copyXmlToBinary(*xml, destData); + } } void JuicySFAudioProcessor::setStateInformation (const void* data, int sizeInBytes) @@ -399,7 +412,41 @@ void JuicySFAudioProcessor::setStateInformation (const void* data, int sizeInByt // make sure that it's actually our type of XML object.. // if (xmlState->hasTagName ("MYPLUGINSETTINGS")) { if (xmlState->hasTagName(valueTreeState.state.getType())) { - valueTreeState.replaceState(ValueTree::fromXml(*xmlState)); + // valueTreeState.replaceState(ValueTree::fromXml(*xmlState)); + for (auto* param : getParameters()) + if (auto* p = dynamic_cast(param)) + p->setValue(static_cast(xmlState->getDoubleAttribute(p->paramID, p->getValue()))); + + { + Value value{valueTreeState.state.getPropertyAsValue("soundFontPath", nullptr)}; + value = xmlState->getStringAttribute("soundFontPath", value.getValue()); + // valueTreeState.getParameter("soundFontPath")->getValue() + // valueTreeState.getParameter("soundFontPath")->getValue(); + // RangedAudioParameter *param {valueTreeState.getParameter("release")}; + // jassert(dynamic_cast (param) != nullptr); + // AudioParameterInt* castParam {dynamic_cast (param)}; + // *castParam = m.getControllerValue(); + } + { + ValueTree tree{valueTreeState.state.getChildWithName("uiState")}; + XmlElement* uiState{xmlState->getChildByName("uiState")}; + if (uiState) { + { + Value value{tree.getPropertyAsValue("width", nullptr)}; + value = uiState->getIntAttribute("width", value.getValue()); + } + { + Value value{tree.getPropertyAsValue("height", nullptr)}; + value = uiState->getIntAttribute("height", value.getValue()); + } + } + +// tree.getPropertyAsValue("width", nullptr) +// tree. +// valueTreeState.replaceState(ValueTree::fromXml(*xmlState)) +// value = xmlState->getStringAttribute("soundFontPath", value.getValue()); + } + // list::iterator p; // for(p = stateChangeSubscribers.begin(); p != stateChangeSubscribers.end(); p++) { // (*p)->setStateInformation(xmlState);