From af25a4147aae8ff9fc4c129eb3efae91cb80af55 Mon Sep 17 00:00:00 2001 From: hogliux Date: Mon, 4 Jun 2018 16:58:11 +0100 Subject: [PATCH] AudioPluginDemo now uses AudioProcessorValueTreeState to store it's parameter and ui state --- examples/Plugins/AudioPluginDemo.h | 169 ++++++++++------------------- 1 file changed, 60 insertions(+), 109 deletions(-) diff --git a/examples/Plugins/AudioPluginDemo.h b/examples/Plugins/AudioPluginDemo.h index 6d01d6ba4e..348b605a82 100644 --- a/examples/Plugins/AudioPluginDemo.h +++ b/examples/Plugins/AudioPluginDemo.h @@ -172,15 +172,20 @@ class JuceDemoPluginAudioProcessor : public AudioProcessor public: //============================================================================== JuceDemoPluginAudioProcessor() - : AudioProcessor (getBusesProperties()) + : AudioProcessor (getBusesProperties()), + state (*this, nullptr) { lastPosInfo.resetToDefault(); - // This creates our parameters. We'll keep some raw pointers to them in this class, - // so that we can easily access them later, but the base class will take care of - // deleting them for us. - addParameter (gainParam = new AudioParameterFloat ("gain", "Gain", 0.0f, 1.0f, 0.9f)); - addParameter (delayParam = new AudioParameterFloat ("delay", "Delay Feedback", 0.0f, 1.0f, 0.5f)); + // This creates our parameters + state.createAndAddParameter ("gain", "Gain", {}, {}, 0.9f, {}, {}); + state.createAndAddParameter ("delay", "Delay Feedback", {}, {}, 0.5f, {}, {}); + + state.state = ValueTree ("state", {}, + { + // add a sub-tree to store the state of our UI + {"uiState", {{"width", 400}, {"height", 200}}, {}} + }); initialiseSynth(); } @@ -282,48 +287,21 @@ public: //============================================================================== void getStateInformation (MemoryBlock& destData) override { - // You should use this method to store your parameters in the memory block. - // Here's an example of how you can use XML to make it easy and more robust: + // Store an xml representation of our state. + std::unique_ptr xmlState (state.copyState().createXml()); - // Create an outer XML element.. - XmlElement xml ("MYPLUGINSETTINGS"); - - // add some attributes to it.. - xml.setAttribute ("uiWidth", lastUIWidth); - xml.setAttribute ("uiHeight", lastUIHeight); - - // Store the values of all our parameters, using their param ID as the XML attribute - 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 (xmlState.get() != nullptr) + copyXmlToBinary (*xmlState, destData); } void setStateInformation (const void* data, int sizeInBytes) override { - // You should use this method to restore your parameters from this memory block, - // whose contents will have been created by the getStateInformation() call. - - // This getXmlFromBinary() helper function retrieves our XML from the binary blob.. + // Restore our plug-in's state from the xml representation stored in the above + // method. std::unique_ptr xmlState (getXmlFromBinary (data, sizeInBytes)); if (xmlState.get() != nullptr) - { - // make sure that it's actually our type of XML object.. - if (xmlState->hasTagName ("MYPLUGINSETTINGS")) - { - // ok, now pull out our last window size.. - lastUIWidth = jmax (xmlState->getIntAttribute ("uiWidth", lastUIWidth), 400); - lastUIHeight = jmax (xmlState->getIntAttribute ("uiHeight", lastUIHeight), 200); - - // Now reload our parameters.. - for (auto* param : getParameters()) - if (auto* p = dynamic_cast (param)) - p->setValue ((float) xmlState->getDoubleAttribute (p->paramID, p->getValue())); - } - } + state.replaceState (ValueTree::fromXml (*xmlState)); } //============================================================================== @@ -348,14 +326,8 @@ public: // callback - the UI component will read this and display it. AudioPlayHead::CurrentPositionInfo lastPosInfo; - // 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. - int lastUIWidth = 400, lastUIHeight = 200; - - // Our parameters - AudioParameterFloat* gainParam = nullptr; - AudioParameterFloat* delayParam = nullptr; + // Our plug-in's current state + AudioProcessorValueTreeState state; // Current track colour and name TrackProperties trackProperties; @@ -364,27 +336,27 @@ private: //============================================================================== /** This is the editor component that our filter will display. */ class JuceDemoPluginAudioProcessorEditor : public AudioProcessorEditor, - private Timer + private Timer, private Value::Listener { public: JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor& owner) : AudioProcessorEditor (owner), - midiKeyboard (owner.keyboardState, MidiKeyboardComponent::horizontalKeyboard) + midiKeyboard (owner.keyboardState, MidiKeyboardComponent::horizontalKeyboard), + gainAttachment (owner.state, "gain", gainSlider), + delayAttachment (owner.state, "delay", delaySlider) { // add some sliders.. - gainSlider.reset (new ParameterSlider (*owner.gainParam)); - addAndMakeVisible (gainSlider.get()); - gainSlider->setSliderStyle (Slider::Rotary); + addAndMakeVisible (gainSlider); + gainSlider.setSliderStyle (Slider::Rotary); - delaySlider.reset (new ParameterSlider (*owner.delayParam)); - addAndMakeVisible (delaySlider.get()); - delaySlider->setSliderStyle (Slider::Rotary); + addAndMakeVisible (delaySlider); + delaySlider.setSliderStyle (Slider::Rotary); // add some labels for the sliders.. - gainLabel.attachToComponent (gainSlider.get(), false); + gainLabel.attachToComponent (&gainSlider, false); gainLabel.setFont (Font (11.0f)); - delayLabel.attachToComponent (delaySlider.get(), false); + delayLabel.attachToComponent (&delaySlider, false); delayLabel.setFont (Font (11.0f)); // add the midi keyboard component.. @@ -397,9 +369,14 @@ private: // set resize limits for this plug-in setResizeLimits (400, 200, 1024, 700); + lastUIWidth .referTo (owner.state.state.getChildWithName ("uiState").getPropertyAsValue ("width", nullptr)); + lastUIHeight.referTo (owner.state.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 (owner.lastUIWidth, - owner.lastUIHeight); + setSize (lastUIWidth.getValue(), lastUIHeight.getValue()); + + lastUIWidth. addListener (this); + lastUIHeight.addListener (this); updateTrackProperties(); @@ -427,11 +404,11 @@ private: r.removeFromTop (20); auto sliderArea = r.removeFromTop (60); - gainSlider->setBounds (sliderArea.removeFromLeft (jmin (180, sliderArea.getWidth() / 2))); - delaySlider->setBounds (sliderArea.removeFromLeft (jmin (180, sliderArea.getWidth()))); + gainSlider.setBounds (sliderArea.removeFromLeft (jmin (180, sliderArea.getWidth() / 2))); + delaySlider.setBounds (sliderArea.removeFromLeft (jmin (180, sliderArea.getWidth()))); - getProcessor().lastUIWidth = getWidth(); - getProcessor().lastUIHeight = getHeight(); + lastUIWidth = getWidth(); + lastUIHeight = getHeight(); } void timerCallback() override @@ -455,53 +432,21 @@ private: } private: - //============================================================================== - // This is a handy slider subclass that controls an AudioProcessorParameter - // (may move this class into the library itself at some point in the future..) - class ParameterSlider : public Slider, - private Timer - { - public: - ParameterSlider (AudioProcessorParameter& p) - : Slider (p.getName (256)), param (p) - { - setRange (0.0, 1.0, 0.0); - startTimerHz (30); - updateSliderPos(); - } - - void valueChanged() override { param.setValueNotifyingHost ((float) Slider::getValue()); } - - void timerCallback() override { updateSliderPos(); } - - void startedDragging() override { param.beginChangeGesture(); } - void stoppedDragging() override { param.endChangeGesture(); } - - double getValueFromText (const String& text) override { return param.getValueForText (text); } - String getTextFromValue (double value) override { return param.getText ((float) value, 1024); } - - void updateSliderPos() - { - auto newValue = param.getValue(); - - if (newValue != (float) Slider::getValue() && ! isMouseButtonDown()) - Slider::setValue (newValue, NotificationType::dontSendNotification); - } - - AudioProcessorParameter& param; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParameterSlider) - }; - MidiKeyboardComponent midiKeyboard; Label timecodeDisplayLabel, gainLabel { {}, "Throughput level:" }, delayLabel { {}, "Delay:" }; - std::unique_ptr gainSlider, delaySlider; + Slider gainSlider, delaySlider; + AudioProcessorValueTreeState::SliderAttachment gainAttachment, delayAttachment; Colour backgroundColour; + // 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; + //============================================================================== JuceDemoPluginAudioProcessor& getProcessor() const { @@ -558,12 +503,20 @@ private: timecodeDisplayLabel.setText (displayText.toString(), dontSendNotification); } + + // called when the stored window size changes + void valueChanged (Value&) override + { + setSize (lastUIWidth.getValue(), lastUIHeight.getValue()); + } }; //============================================================================== template void process (AudioBuffer& buffer, MidiBuffer& midiMessages, AudioBuffer& delayBuffer) { + auto gainParamValue = state.getParameter ("gain") ->getValue(); + auto delayParamValue = state.getParameter ("delay")->getValue(); auto numSamples = buffer.getNumSamples(); // In case we have more outputs than inputs, we'll clear any output @@ -580,29 +533,27 @@ private: synth.renderNextBlock (buffer, midiMessages, 0, numSamples); // Apply our delay effect to the new output.. - applyDelay (buffer, delayBuffer); + applyDelay (buffer, delayBuffer, gainParamValue); - applyGain (buffer, delayBuffer); // apply our gain-change to the outgoing data.. + applyGain (buffer, delayBuffer, delayParamValue); // apply our gain-change to the outgoing data.. // Now ask the host for the current time so we can store it to be displayed later... updateCurrentTimeInfoFromHost(); } template - void applyGain (AudioBuffer& buffer, AudioBuffer& delayBuffer) + void applyGain (AudioBuffer& buffer, AudioBuffer& delayBuffer, float gainLevel) { ignoreUnused (delayBuffer); - auto gainLevel = gainParam->get(); for (auto channel = 0; channel < getTotalNumOutputChannels(); ++channel) buffer.applyGain (channel, 0, buffer.getNumSamples(), gainLevel); } template - void applyDelay (AudioBuffer& buffer, AudioBuffer& delayBuffer) + void applyDelay (AudioBuffer& buffer, AudioBuffer& delayBuffer, float delayLevel) { auto numSamples = buffer.getNumSamples(); - auto delayLevel = delayParam->get(); auto delayPos = 0;