Skip to content

Commit

Permalink
Merge pull request #4 from haszari/fix/3-save-and-restore-plugin-state
Browse files Browse the repository at this point in the history
Fix/3 save and restore plugin state
  • Loading branch information
haszari authored Sep 11, 2021
2 parents a26758a + c4f01a5 commit 825d667
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 100 deletions.
66 changes: 39 additions & 27 deletions ChannelFilter/Source/PluginProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,56 @@
//==============================================================================
MIDIClipVariationsAudioProcessor::MIDIClipVariationsAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
: AudioProcessor (BusesProperties()
:
AudioProcessor (BusesProperties()
#if ! JucePlugin_IsMidiEffect
#if ! JucePlugin_IsSynth
.withInput ("Input", juce::AudioChannelSet::stereo(), true)
#endif
.withOutput ("Output", juce::AudioChannelSet::stereo(), true)
#endif
)
),
parameters (*this, nullptr, juce::Identifier (JucePlugin_Name),
{
std::make_unique<juce::AudioParameterInt> (
"channel", // parameterID
"Channel", // parameter name
1, // minimum value
16, // maximum value
1
),

// Now allows phrase length 1 beat for consistency with ControllerMotion param.
std::make_unique<juce::AudioParameterChoice> (
"phraseBeats", // parameterID
"Phrase length", // parameter name
juce::StringArray( {"1 beat", "4 beats", "8 beats", "16 beats", "32 beats", "64 beats"} ),
2 // default index
)
} )
#endif
{
tempoBpm = 120.0;
lastBufferTimestamp = 0;
currentAllowedChannel = 1;
addParameter (selectedChannel = new juce::AudioParameterInt (
"channel", // parameterID
"Channel", // parameter name
1, // minimum value
16, // maximum value
1)
);
addParameter (phraseBeats = new juce::AudioParameterChoice (
"phraseBeats", // parameterID
"Phrase length", // parameter name
juce::StringArray( {"4 beats", "8 beats", "16 beats", "32 beats", "64 beats"} ),
1 // default index
));

selectedChannel = (juce::AudioParameterInt*)parameters.getParameter("channel");
phraseBeats = (juce::AudioParameterChoice*)parameters.getParameter("phraseBeats");
}

int MIDIClipVariationsAudioProcessor::getPhraseBeats ()
{
int selected = phraseBeats->getIndex();

// This looks like pow(2, index) but it's not.
switch (selected) {
case 0: return 4;
case 1: return 8;
case 2: return 16;
case 3: return 32;
case 4: return 64;
case 0: return 1;
case 1: return 4;
case 2: return 8;
case 3: return 16;
case 4: return 32;
case 5: return 64;
}

return 4;
}
MIDIClipVariationsAudioProcessor::~MIDIClipVariationsAudioProcessor()
Expand Down Expand Up @@ -271,15 +280,18 @@ juce::AudioProcessorEditor* MIDIClipVariationsAudioProcessor::createEditor()
//==============================================================================
void MIDIClipVariationsAudioProcessor::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.
auto state = parameters.copyState();
std::unique_ptr<juce::XmlElement> xml (state.createXml());
copyXmlToBinary (*xml, destData);
}

void MIDIClipVariationsAudioProcessor::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.
std::unique_ptr<juce::XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));

if (xmlState.get() != nullptr)
if (xmlState->hasTagName (parameters.state.getType()))
parameters.replaceState (juce::ValueTree::fromXml (*xmlState));
}

//==============================================================================
Expand Down
2 changes: 2 additions & 0 deletions ChannelFilter/Source/PluginProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class MIDIClipVariationsAudioProcessor : public juce::AudioProcessor

int getPhraseBeats ();

juce::AudioProcessorValueTreeState parameters;

juce::AudioParameterInt* selectedChannel;
juce::AudioParameterChoice* phraseBeats;

Expand Down
103 changes: 64 additions & 39 deletions ControllerMotion/Source/PluginProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,61 +11,83 @@
//==============================================================================
MIDIControllerMotionAudioProcessor::MIDIControllerMotionAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
: AudioProcessor (BusesProperties()
:
AudioProcessor (BusesProperties()
#if ! JucePlugin_IsMidiEffect
#if ! JucePlugin_IsSynth
.withInput ("Input", juce::AudioChannelSet::stereo(), true)
#endif
.withOutput ("Output", juce::AudioChannelSet::stereo(), true)
#endif
)
),
parameters (*this, nullptr, juce::Identifier (JucePlugin_Name),
{
// Note this plugin allows phrase length 1 beat for "real time" control.
// (The clip variation plugins start at 4 beats.)
std::make_unique<juce::AudioParameterChoice> (
"phraseBeats", // parameterID
"Phrase length", // parameter name
juce::StringArray( {"1 beat", "4 beats", "8 beats", "16 beats", "32 beats", "64 beats"} ),
2 // default index
),

// Moving CC parameters. The number of these params should match CBR_CCMOTION_NUM_PARAMS constant.
std::make_unique<juce::AudioParameterFloat> (
"target1", // parameterID
"Target 1", // parameter name
0.0, 1.0, 0.0
),
std::make_unique<juce::AudioParameterFloat> (
"target2", // parameterID
"Target 2", // parameter name
0.0, 1.0, 0.0
),
std::make_unique<juce::AudioParameterFloat> (
"target3", // parameterID
"Target 3", // parameter name
0.0, 1.0, 0.0
),
std::make_unique<juce::AudioParameterFloat> (
"target4", // parameterID
"Target 4", // parameter name
0.0, 1.0, 0.0
),

std::make_unique<juce::AudioParameterInt> (
"firstCCNumber", // parameterID
"First CC number", // parameter name
1,
127,
1
),
std::make_unique<juce::AudioParameterInt> (
"channelNumber", // parameterID
"Channel", // parameter name
1,
16,
1
),
} )
#endif
{
tempoBpm = 120.0;
lastBufferTimestamp = 0;

// Note this plugin allows phrase length 1 beat for "real time" control.
// (The clip variation plugins start at 4 beats.)
addParameter (phraseBeats = new juce::AudioParameterChoice (
"phraseBeats", // parameterID
"Phrase length", // parameter name
juce::StringArray( {"1 beat", "4 beats", "8 beats", "16 beats", "32 beats", "64 beats"} ),
2 // default index
));
// Assuming it's ok to just cast these to specific param type.
phraseBeats = (juce::AudioParameterChoice*)parameters.getParameter("phraseBeats");
firstCCNumber = (juce::AudioParameterInt*)parameters.getParameter("firstCCNumber");
channelNumber = (juce::AudioParameterInt*)parameters.getParameter("channelNumber");

for (int i=0; i<CBR_CCMOTION_NUM_PARAMS; i++) {
int controllerNumber = i + 1;

std::ostringstream paramIdentifier;
paramIdentifier << "target" << controllerNumber;
std::ostringstream paramName;
paramName << "Target " << controllerNumber;

currentValue[i] = 0;
lastOutputCC[i] = 0;
addParameter (destinationValue[i] = new juce::AudioParameterFloat (
paramIdentifier.str(), // parameterID
paramName.str(), // parameter name
0.0,
1.0,
0.0
));
destinationValue[i] = (juce::AudioParameterFloat*)parameters.getParameter(paramIdentifier.str());
}

addParameter (firstCCNumber = new juce::AudioParameterInt (
"firstCC", // parameterID
"First CC number", // parameter name
1,
127,
1
));
addParameter (channelNumber = new juce::AudioParameterInt (
"channelNumber", // parameterID
"Channel", // parameter name
1,
16,
1
));
}

double MIDIControllerMotionAudioProcessor::getPhraseBeats ()
Expand Down Expand Up @@ -303,15 +325,18 @@ juce::AudioProcessorEditor* MIDIControllerMotionAudioProcessor::createEditor()
//==============================================================================
void MIDIControllerMotionAudioProcessor::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.
auto state = parameters.copyState();
std::unique_ptr<juce::XmlElement> xml (state.createXml());
copyXmlToBinary (*xml, destData);
}

void MIDIControllerMotionAudioProcessor::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.
std::unique_ptr<juce::XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));

if (xmlState.get() != nullptr)
if (xmlState->hasTagName (parameters.state.getType()))
parameters.replaceState (juce::ValueTree::fromXml (*xmlState));
}

//==============================================================================
Expand Down
4 changes: 4 additions & 0 deletions ControllerMotion/Source/PluginProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include <JuceHeader.h>

// These parameters are now hard coded in the constructor initialiser list.
// If this constant is changed, need to add/remove `target` params accordingly.
#define CBR_CCMOTION_NUM_PARAMS 4

//==============================================================================
Expand Down Expand Up @@ -70,6 +72,8 @@ class MIDIControllerMotionAudioProcessor : public juce::AudioProcessor
double currentValue[CBR_CCMOTION_NUM_PARAMS];
int lastOutputCC[CBR_CCMOTION_NUM_PARAMS];

juce::AudioProcessorValueTreeState parameters;

juce::AudioParameterChoice* phraseBeats;
juce::AudioParameterInt* firstCCNumber;
juce::AudioParameterInt* channelNumber;
Expand Down
81 changes: 47 additions & 34 deletions NoteFilter/Source/PluginProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,55 @@
//==============================================================================
MIDIClipVariationsAudioProcessor::MIDIClipVariationsAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
: AudioProcessor (BusesProperties()
:
AudioProcessor (BusesProperties()
#if ! JucePlugin_IsMidiEffect
#if ! JucePlugin_IsSynth
.withInput ("Input", juce::AudioChannelSet::stereo(), true)
#endif
.withOutput ("Output", juce::AudioChannelSet::stereo(), true)
#endif
)
),
parameters (*this, nullptr, juce::Identifier (JucePlugin_Name),
{
std::make_unique<juce::AudioParameterInt> (
"variation", // parameterID
"Variation", // parameter name
1, // minimum value
16, // maximum value TBD
1
),

// Now allows phrase length 1 beat for consistency with ControllerMotion param.
std::make_unique<juce::AudioParameterChoice> (
"phraseBeats", // parameterID
"Phrase length", // parameter name
juce::StringArray( {"1 beat", "4 beats", "8 beats", "16 beats", "32 beats", "64 beats"} ),
2 // default index
),

std::make_unique<juce::AudioParameterChoice> (
"notesPerVariation", // parameterID
"Variation height", // parameter name
juce::StringArray( {"6 semitones / half octave", "1 octave", "2 octaves", "3 octaves"} ),
1 // default index
)
} )
#endif
{
tempoBpm = 120.0;
lastBufferTimestamp = 0;
currentVariation = 0; // Zero based .. is that confusing, compared to channel plugin?
addParameter (selectedVariation = new juce::AudioParameterInt (
"variation", // parameterID
"Variation", // parameter name
1, // minimum value
16, // maximum value TBD
1)
);
addParameter (notesPerVariation = new juce::AudioParameterChoice (
"notesPerVariation", // parameterID
"Variation height", // parameter name
juce::StringArray( {"6 semitones / half octave", "1 octave", "2 octaves", "3 octaves"} ),
1 // default index
));
addParameter (phraseBeats = new juce::AudioParameterChoice (
"phraseBeats", // parameterID
"Phrase length", // parameter name
juce::StringArray( {"4 beats", "8 beats", "16 beats", "32 beats", "64 beats"} ),
1 // default index
));

selectedVariation = (juce::AudioParameterInt*)parameters.getParameter("variation");
phraseBeats = (juce::AudioParameterChoice*)parameters.getParameter("phraseBeats");
notesPerVariation = (juce::AudioParameterChoice*)parameters.getParameter("notesPerVariation");
}

int MIDIClipVariationsAudioProcessor::getSemitonesPerVariation ()
{
int selected = notesPerVariation->getIndex();

// This looks like pow(2, index) but it's not.
switch (selected) {
case 0: return 6;
case 1: return 12;
Expand All @@ -64,15 +74,15 @@ int MIDIClipVariationsAudioProcessor::getPhraseBeats ()
{
int selected = phraseBeats->getIndex();

// This looks like pow(2, index) but it's not.
switch (selected) {
case 0: return 4;
case 1: return 8;
case 2: return 16;
case 3: return 32;
case 4: return 64;
case 0: return 1;
case 1: return 4;
case 2: return 8;
case 3: return 16;
case 4: return 32;
case 5: return 64;
}

return 4;
}

Expand Down Expand Up @@ -322,15 +332,18 @@ juce::AudioProcessorEditor* MIDIClipVariationsAudioProcessor::createEditor()
//==============================================================================
void MIDIClipVariationsAudioProcessor::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.
auto state = parameters.copyState();
std::unique_ptr<juce::XmlElement> xml (state.createXml());
copyXmlToBinary (*xml, destData);
}

void MIDIClipVariationsAudioProcessor::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.
std::unique_ptr<juce::XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));

if (xmlState.get() != nullptr)
if (xmlState->hasTagName (parameters.state.getType()))
parameters.replaceState (juce::ValueTree::fromXml (*xmlState));
}

//==============================================================================
Expand Down
Loading

0 comments on commit 825d667

Please sign in to comment.