Browse Source

AudioPluginDemo now uses AudioProcessorValueTreeState to store it's parameter and ui state

tags/2021-05-28
hogliux 7 years ago
parent
commit
af25a4147a
1 changed files with 60 additions and 109 deletions
  1. +60
    -109
      examples/Plugins/AudioPluginDemo.h

+ 60
- 109
examples/Plugins/AudioPluginDemo.h View File

@@ -172,15 +172,20 @@ class JuceDemoPluginAudioProcessor : public AudioProcessor
public: public:
//============================================================================== //==============================================================================
JuceDemoPluginAudioProcessor() JuceDemoPluginAudioProcessor()
: AudioProcessor (getBusesProperties())
: AudioProcessor (getBusesProperties()),
state (*this, nullptr)
{ {
lastPosInfo.resetToDefault(); 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(); initialiseSynth();
} }
@@ -282,48 +287,21 @@ public:
//============================================================================== //==============================================================================
void getStateInformation (MemoryBlock& destData) override 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:
// 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<AudioProcessorParameterWithID*> (param))
xml.setAttribute (p->paramID, p->getValue());
// Store an xml representation of our state.
std::unique_ptr<XmlElement> xmlState (state.copyState().createXml());
// 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 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<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes)); std::unique_ptr<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));
if (xmlState.get() != nullptr) 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<AudioProcessorParameterWithID*> (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. // callback - the UI component will read this and display it.
AudioPlayHead::CurrentPositionInfo lastPosInfo; 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 // Current track colour and name
TrackProperties trackProperties; TrackProperties trackProperties;
@@ -364,27 +336,27 @@ private:
//============================================================================== //==============================================================================
/** This is the editor component that our filter will display. */ /** This is the editor component that our filter will display. */
class JuceDemoPluginAudioProcessorEditor : public AudioProcessorEditor, class JuceDemoPluginAudioProcessorEditor : public AudioProcessorEditor,
private Timer
private Timer, private Value::Listener
{ {
public: public:
JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor& owner) JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor& owner)
: AudioProcessorEditor (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.. // 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.. // add some labels for the sliders..
gainLabel.attachToComponent (gainSlider.get(), false);
gainLabel.attachToComponent (&gainSlider, false);
gainLabel.setFont (Font (11.0f)); gainLabel.setFont (Font (11.0f));
delayLabel.attachToComponent (delaySlider.get(), false);
delayLabel.attachToComponent (&delaySlider, false);
delayLabel.setFont (Font (11.0f)); delayLabel.setFont (Font (11.0f));
// add the midi keyboard component.. // add the midi keyboard component..
@@ -397,9 +369,14 @@ private:
// set resize limits for this plug-in // set resize limits for this plug-in
setResizeLimits (400, 200, 1024, 700); 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 // 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(); updateTrackProperties();
@@ -427,11 +404,11 @@ private:
r.removeFromTop (20); r.removeFromTop (20);
auto sliderArea = r.removeFromTop (60); 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 void timerCallback() override
@@ -455,53 +432,21 @@ private:
} }
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; MidiKeyboardComponent midiKeyboard;
Label timecodeDisplayLabel, Label timecodeDisplayLabel,
gainLabel { {}, "Throughput level:" }, gainLabel { {}, "Throughput level:" },
delayLabel { {}, "Delay:" }; delayLabel { {}, "Delay:" };
std::unique_ptr<ParameterSlider> gainSlider, delaySlider;
Slider gainSlider, delaySlider;
AudioProcessorValueTreeState::SliderAttachment gainAttachment, delayAttachment;
Colour backgroundColour; 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 JuceDemoPluginAudioProcessor& getProcessor() const
{ {
@@ -558,12 +503,20 @@ private:
timecodeDisplayLabel.setText (displayText.toString(), dontSendNotification); timecodeDisplayLabel.setText (displayText.toString(), dontSendNotification);
} }
// called when the stored window size changes
void valueChanged (Value&) override
{
setSize (lastUIWidth.getValue(), lastUIHeight.getValue());
}
}; };
//============================================================================== //==============================================================================
template <typename FloatType> template <typename FloatType>
void process (AudioBuffer<FloatType>& buffer, MidiBuffer& midiMessages, AudioBuffer<FloatType>& delayBuffer) void process (AudioBuffer<FloatType>& buffer, MidiBuffer& midiMessages, AudioBuffer<FloatType>& delayBuffer)
{ {
auto gainParamValue = state.getParameter ("gain") ->getValue();
auto delayParamValue = state.getParameter ("delay")->getValue();
auto numSamples = buffer.getNumSamples(); auto numSamples = buffer.getNumSamples();
// In case we have more outputs than inputs, we'll clear any output // In case we have more outputs than inputs, we'll clear any output
@@ -580,29 +533,27 @@ private:
synth.renderNextBlock (buffer, midiMessages, 0, numSamples); synth.renderNextBlock (buffer, midiMessages, 0, numSamples);
// Apply our delay effect to the new output.. // 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... // Now ask the host for the current time so we can store it to be displayed later...
updateCurrentTimeInfoFromHost(); updateCurrentTimeInfoFromHost();
} }
template <typename FloatType> template <typename FloatType>
void applyGain (AudioBuffer<FloatType>& buffer, AudioBuffer<FloatType>& delayBuffer)
void applyGain (AudioBuffer<FloatType>& buffer, AudioBuffer<FloatType>& delayBuffer, float gainLevel)
{ {
ignoreUnused (delayBuffer); ignoreUnused (delayBuffer);
auto gainLevel = gainParam->get();
for (auto channel = 0; channel < getTotalNumOutputChannels(); ++channel) for (auto channel = 0; channel < getTotalNumOutputChannels(); ++channel)
buffer.applyGain (channel, 0, buffer.getNumSamples(), gainLevel); buffer.applyGain (channel, 0, buffer.getNumSamples(), gainLevel);
} }
template <typename FloatType> template <typename FloatType>
void applyDelay (AudioBuffer<FloatType>& buffer, AudioBuffer<FloatType>& delayBuffer)
void applyDelay (AudioBuffer<FloatType>& buffer, AudioBuffer<FloatType>& delayBuffer, float delayLevel)
{ {
auto numSamples = buffer.getNumSamples(); auto numSamples = buffer.getNumSamples();
auto delayLevel = delayParam->get();
auto delayPos = 0; auto delayPos = 0;


Loading…
Cancel
Save