mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
AudioPluginDemo now uses AudioProcessorValueTreeState to store it's parameter and ui state
This commit is contained in:
parent
9b81643aa9
commit
af25a4147a
1 changed files with 60 additions and 109 deletions
|
|
@ -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<XmlElement> 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<AudioProcessorParameterWithID*> (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<XmlElement> 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<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.
|
||||
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<ParameterSlider> 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 <typename FloatType>
|
||||
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();
|
||||
|
||||
// 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 <typename FloatType>
|
||||
void applyGain (AudioBuffer<FloatType>& buffer, AudioBuffer<FloatType>& delayBuffer)
|
||||
void applyGain (AudioBuffer<FloatType>& buffer, AudioBuffer<FloatType>& delayBuffer, float gainLevel)
|
||||
{
|
||||
ignoreUnused (delayBuffer);
|
||||
auto gainLevel = gainParam->get();
|
||||
|
||||
for (auto channel = 0; channel < getTotalNumOutputChannels(); ++channel)
|
||||
buffer.applyGain (channel, 0, buffer.getNumSamples(), gainLevel);
|
||||
}
|
||||
|
||||
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 delayLevel = delayParam->get();
|
||||
|
||||
auto delayPos = 0;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue