progress moving uiWidth/Height into audio params, and moving soundFontPath out of SharesParams (for better listener support, and to generalize)

This commit is contained in:
Alex Birch 2019-07-07 17:35:31 +01:00
parent 6d2267e23a
commit a990072f1f
No known key found for this signature in database
GPG Key ID: 305EB1F98D44ACBA
11 changed files with 274 additions and 103 deletions

View File

@ -12,10 +12,12 @@ using namespace std;
FluidSynthModel::FluidSynthModel( FluidSynthModel::FluidSynthModel(
AudioProcessorValueTreeState& valueTreeState, AudioProcessorValueTreeState& valueTreeState,
SharesParams& sharedParams ValueTree& valueTree
// SharesParams& sharedParams
) )
: valueTreeState{valueTreeState} : valueTreeState{valueTreeState}
, sharedParams{sharedParams} , valueTree{valueTree}
// , sharedParams{sharedParams}
//, synth{nullptr} //, synth{nullptr}
, settings{nullptr, nullptr} , settings{nullptr, nullptr}
, currentSoundFontAbsPath{} , currentSoundFontAbsPath{}
@ -24,10 +26,12 @@ FluidSynthModel::FluidSynthModel(
, sfont_id{0} , sfont_id{0}
, channel{0}/*, , channel{0}/*,
mod(nullptr)*/ mod(nullptr)*/
{
valueTree.addListener(this);
}
{} FluidSynthModel::~FluidSynthModel() {
valueTree.removeListener(this);
// FluidSynthModel::~FluidSynthModel() {
// if (initialised) { // if (initialised) {
// delete_fluid_audio_driver(driver); // delete_fluid_audio_driver(driver);
// delete_fluid_synth(synth); // delete_fluid_synth(synth);
@ -36,7 +40,7 @@ mod(nullptr)*/
// delete settings; // delete settings;
// delete_fluid_mod(mod); // delete_fluid_mod(mod);
// } // }
// } }
int FluidSynthModel::handleMidiEvent(void* data, fluid_midi_event_t* event) int FluidSynthModel::handleMidiEvent(void* data, fluid_midi_event_t* event)
{ {
@ -79,16 +83,16 @@ void FluidSynthModel::initialise() {
synth = { new_fluid_synth(settings.get()), delete_fluid_synth }; synth = { new_fluid_synth(settings.get()), delete_fluid_synth };
fluid_synth_set_sample_rate(synth.get(), currentSampleRate); fluid_synth_set_sample_rate(synth.get(), currentSampleRate);
valueTreeState.getParameter("soundFontPath")->getValue(); // valueTreeState.getParameter("soundFontPath")->getValue();
// RangedAudioParameter *param {valueTreeState.getParameter("release")}; // RangedAudioParameter *param {valueTreeState.getParameter("release")};
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr); // jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)}; // AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// *castParam = m.getControllerValue(); // *castParam = m.getControllerValue();
if (sharedParams.getSoundFontPath().isNotEmpty()) { // if (sharedParams.getSoundFontPath().isNotEmpty()) {
loadFont(sharedParams.getSoundFontPath()); // loadFont(sharedParams.getSoundFontPath());
// changePreset(sharedParams->getBank(), sharedParams->getPreset()); // changePreset(sharedParams->getBank(), sharedParams->getPreset());
} // }
fluid_synth_set_gain(synth.get(), 2.0); fluid_synth_set_gain(synth.get(), 2.0);
@ -192,9 +196,23 @@ void FluidSynthModel::initialise() {
fluid_mod_set_amount(mod.get(), 1000.0f); fluid_mod_set_amount(mod.get(), 1000.0f);
fluid_synth_add_default_mod(synth.get(), mod.get(), FLUID_SYNTH_ADD); fluid_synth_add_default_mod(synth.get(), mod.get(), FLUID_SYNTH_ADD);
valueTree.sendPropertyChangeMessage("soundFontPath");
// initialised = true; // initialised = true;
} }
void FluidSynthModel::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasChanged,
const Identifier& property) {
if (&treeWhosePropertyHasChanged == &valueTree) {
if (property == Identifier("soundFontPath")) {
String soundFontPath{treeWhosePropertyHasChanged.getProperty("soundFontPath", "")};
if (soundFontPath.isNotEmpty()) {
loadFont(soundFontPath);
}
}
}
}
void FluidSynthModel::setControllerValue(int controller, int value) { void FluidSynthModel::setControllerValue(int controller, int value) {
fluid_midi_event_t *midi_event(new_fluid_midi_event()); fluid_midi_event_t *midi_event(new_fluid_midi_event());
fluid_midi_event_set_type(midi_event, static_cast<int>(CONTROL_CHANGE)); fluid_midi_event_set_type(midi_event, static_cast<int>(CONTROL_CHANGE));
@ -300,7 +318,8 @@ void FluidSynthModel::onFileNameChanged(const String &absPath, int bank, int pre
} }
unloadAndLoadFont(absPath); unloadAndLoadFont(absPath);
changePreset(bank, preset); changePreset(bank, preset);
sharedParams.setSoundFontPath(absPath); valueTree.setPropertyExcludingListener(this, "soundFontPath", absPath, nullptr);
// sharedParams.setSoundFontPath(absPath);
eventListeners.call(&FluidSynthModel::Listener::fontChanged, this, absPath); eventListeners.call(&FluidSynthModel::Listener::fontChanged, this, absPath);
} }

View File

@ -17,13 +17,14 @@
using namespace std; using namespace std;
class FluidSynthModel { class FluidSynthModel: public ValueTree::Listener {
public: public:
FluidSynthModel( FluidSynthModel(
AudioProcessorValueTreeState& valueTreeState, AudioProcessorValueTreeState& valueTreeState,
SharesParams& sharedParams // SharesParams& sharedParams
ValueTree& valueTree
); );
// ~FluidSynthModel(); ~FluidSynthModel();
shared_ptr<fluid_synth_t> getSynth(); shared_ptr<fluid_synth_t> getSynth();
void initialise(); void initialise();
@ -67,14 +68,53 @@ public:
const String& getCurrentSoundFontAbsPath(); const String& getCurrentSoundFontAbsPath();
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: private:
// class ValueTreeListener: public ValueTree::Listener {
// public:
//// ValueTreeListener();
//// ~ValueTreeListener();
// 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 {};
// JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueTreeListener)
// };
int handleMidiEvent(void* data, fluid_midi_event_t* event); int handleMidiEvent(void* data, fluid_midi_event_t* event);
AudioProcessorValueTreeState& valueTreeState; // ValueTreeListener valueTreeListener;
SharesParams& sharedParams;
shared_ptr<fluid_synth_t> synth; AudioProcessorValueTreeState& valueTreeState;
// SharesParams& sharedParams;
ValueTree& valueTree;
// https://stackoverflow.com/questions/38980315/is-stdunique-ptr-deletion-order-guaranteed
// members are destroyed in reverse of the order they're declared
// http://www.fluidsynth.org/api/
// in their examples, they destroy the synth before destroying the settings
unique_ptr<fluid_settings_t, decltype(&delete_fluid_settings)> settings; unique_ptr<fluid_settings_t, decltype(&delete_fluid_settings)> settings;
// TODO: shared_ptr may ruin our guarantee of synth's being destroyed first, so consider changing the access we expose
shared_ptr<fluid_synth_t> synth;
// unique_ptr<fluid_midi_driver_t, decltype(&delete_fluid_midi_driver)> midiDriver; // unique_ptr<fluid_midi_driver_t, decltype(&delete_fluid_midi_driver)> midiDriver;
String currentSoundFontAbsPath; String currentSoundFontAbsPath;

View File

@ -15,9 +15,9 @@
using namespace std; using namespace std;
Params::Params() noexcept Params::Params() noexcept
: uiWidth{GuiConstants::minWidth} // : uiWidth{GuiConstants::minWidth}
, uiHeight{GuiConstants::minHeight} // , uiHeight{GuiConstants::minHeight}
, soundFontPath{String()} : soundFontPath{String()}
// , preset{-1} // , preset{-1}
// , bank{-1} // , bank{-1}
// , attack{0} // , attack{0}
@ -30,8 +30,8 @@ Params::Params() noexcept
} }
void Params::setAttributesOnXml(shared_ptr<XmlElement> xml) { void Params::setAttributesOnXml(shared_ptr<XmlElement> xml) {
xml->setAttribute("uiWidth", uiWidth); // xml->setAttribute("uiWidth", uiWidth);
xml->setAttribute("uiHeight", uiHeight); // xml->setAttribute("uiHeight", uiHeight);
xml->setAttribute("soundFontPath", soundFontPath); xml->setAttribute("soundFontPath", soundFontPath);
// xml.setAttribute("preset", preset); // xml.setAttribute("preset", preset);
// xml.setAttribute("bank", bank); // xml.setAttribute("bank", bank);
@ -44,8 +44,8 @@ void Params::setAttributesOnXml(shared_ptr<XmlElement> xml) {
} }
void Params::loadAttributesFromXml(shared_ptr<XmlElement> xmlState) { void Params::loadAttributesFromXml(shared_ptr<XmlElement> xmlState) {
uiWidth = jmin(jmax(xmlState->getIntAttribute("uiWidth", uiWidth), GuiConstants::minWidth), GuiConstants::maxWidth); // uiWidth = jmin(jmax(xmlState->getIntAttribute("uiWidth", uiWidth), GuiConstants::minWidth), GuiConstants::maxWidth);
uiHeight = jmin(jmax(xmlState->getIntAttribute("uiHeight", uiHeight), GuiConstants::minHeight), GuiConstants::maxHeight); // uiHeight = jmin(jmax(xmlState->getIntAttribute("uiHeight", uiHeight), GuiConstants::minHeight), GuiConstants::maxHeight);
soundFontPath = xmlState->getStringAttribute("soundFontPath", soundFontPath); soundFontPath = xmlState->getStringAttribute("soundFontPath", soundFontPath);
// preset = xmlState->getIntAttribute("preset", preset); // preset = xmlState->getIntAttribute("preset", preset);
// bank = xmlState->getIntAttribute("bank", bank); // bank = xmlState->getIntAttribute("bank", bank);
@ -95,12 +95,12 @@ String& Params::getSoundFontPath() {
//int Params::getBank() { //int Params::getBank() {
// return bank; // return bank;
//} //}
int Params::getUiWidth() { // int Params::getUiWidth() {
return uiWidth; // return uiWidth;
} // }
int Params::getUiHeight() { // int Params::getUiHeight() {
return uiHeight; // return uiHeight;
} // }
//int Params::getAttack() { //int Params::getAttack() {
// return attack; // return attack;
//} //}
@ -126,12 +126,12 @@ int Params::getUiHeight() {
//void Params::setBank(int value) { //void Params::setBank(int value) {
// bank = value; // bank = value;
//} //}
void Params::setUiWidth(int value) { // void Params::setUiWidth(int value) {
uiWidth = value; // uiWidth = value;
} // }
void Params::setUiHeight(int value) { // void Params::setUiHeight(int value) {
uiHeight = value; // uiHeight = value;
} // }
//void Params::setAttack(int value) { //void Params::setAttack(int value) {
// attack = value; // attack = value;
//} //}

View File

@ -20,10 +20,10 @@ public:
// virtual int getBank() override; // virtual int getBank() override;
// virtual void setBank(int value) override; // virtual void setBank(int value) override;
virtual int getUiWidth() override; // virtual int getUiWidth() override;
virtual void setUiWidth(int value) override; // virtual void setUiWidth(int value) override;
virtual int getUiHeight() override; // virtual int getUiHeight() override;
virtual void setUiHeight(int value) override; // virtual void setUiHeight(int value) override;
// virtual int getAttack() override; // virtual int getAttack() override;
// virtual void setAttack(int value) override; // virtual void setAttack(int value) override;
@ -40,8 +40,8 @@ public:
// virtual void setFilterResonance(int value) override; // virtual void setFilterResonance(int value) override;
private: private:
int uiWidth; // int uiWidth;
int uiHeight; // int uiHeight;
String soundFontPath; String soundFontPath;
// int preset; // int preset;

View File

@ -13,15 +13,17 @@
#include "GuiConstants.h" #include "GuiConstants.h"
//============================================================================== //==============================================================================
JuicySFAudioProcessorEditor::JuicySFAudioProcessorEditor(JuicySFAudioProcessor& p, AudioProcessorValueTreeState& valueTreeState) JuicySFAudioProcessorEditor::JuicySFAudioProcessorEditor(
: AudioProcessorEditor{&p}, JuicySFAudioProcessor& p,
processor{p}, AudioProcessorValueTreeState& valueTreeState)
valueTreeState{valueTreeState}, : AudioProcessorEditor{&p}
sharedParams{p.getSharedParams()}, , processor{p}
midiKeyboard{p.keyboardState, SurjectiveMidiKeyboardComponent::horizontalKeyboard}, , valueTreeState{valueTreeState}
tablesComponent{valueTreeState, p.getFluidSynthModel()}, // sharedParams{p.getSharedParams()},
filePicker{valueTreeState, p.getFluidSynthModel()}, , midiKeyboard{p.keyboardState, SurjectiveMidiKeyboardComponent::horizontalKeyboard}
slidersComponent{p.getSharedParams(), valueTreeState, p.getFluidSynthModel()} , tablesComponent{valueTreeState, p.getFluidSynthModel()}
, filePicker{valueTreeState, p.getFluidSynthModel()}
, slidersComponent{valueTreeState, p.getFluidSynthModel()}
{ {
// set resize limits for this plug-in // set resize limits for this plug-in
setResizeLimits( setResizeLimits(
@ -30,7 +32,28 @@ JuicySFAudioProcessorEditor::JuicySFAudioProcessorEditor(JuicySFAudioProcessor&
GuiConstants::maxWidth, GuiConstants::maxWidth,
GuiConstants::maxHeight); GuiConstants::maxHeight);
setSize(sharedParams.getUiWidth(), sharedParams.getUiHeight()); // int width, height;
// {
// RangedAudioParameter *param {valueTreeState.getParameter("uiWidth")};
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// width = castParam->get();
// }
// {
// RangedAudioParameter *param {valueTreeState.getParameter("uiHeight")};
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// height = castParam->get();
// }
// valueTreeState.addParameterListener("uiWidthPersist", this);
// valueTreeState.addParameterListener("uiHeightPersist", this);
// valueTreeState.addParameterListener("uiWidth", this);
// valueTreeState.addParameterListener("uiHeight", this);
valueTreeState.state.addListener(this);
setSize(GuiConstants::minWidth, GuiConstants::minHeight);
// processor.subscribeToStateChanges(this); // processor.subscribeToStateChanges(this);
@ -50,9 +73,53 @@ JuicySFAudioProcessorEditor::JuicySFAudioProcessorEditor(JuicySFAudioProcessor&
JuicySFAudioProcessorEditor::~JuicySFAudioProcessorEditor() JuicySFAudioProcessorEditor::~JuicySFAudioProcessorEditor()
{ {
// valueTreeState.removeParameterListener("uiWidthPersist", this);
// valueTreeState.removeParameterListener("uiHeightPersist", this);
// valueTreeState.removeParameterListener("uiWidth", this);
// valueTreeState.removeParameterListener("uiHeight", this);
valueTreeState.state.removeListener(this);
// processor.unsubscribeFromStateChanges(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::parameterChanged(const String& parameterID, float newValue) {
// // if (parameterID == "uiWidthPersist"
// // || parameterID == "uiHeightPersist") {
// if (parameterID == "uiWidth"
// || parameterID == "uiHeight") {
// RangedAudioParameter *param {valueTreeState.getParameter(parameterID)};
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (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);
// }
// }
// }
//void JuicySFAudioProcessorEditor::getStateInformation (XmlElement& xml) { //void JuicySFAudioProcessorEditor::getStateInformation (XmlElement& xml) {
// // save // // save
// xml.setAttribute ("uiWidth", getWidth()); // xml.setAttribute ("uiWidth", getWidth());
@ -104,8 +171,24 @@ void JuicySFAudioProcessorEditor::resized()
tablesComponent.setBounds(rContent); tablesComponent.setBounds(rContent);
sharedParams.setUiWidth(getWidth()); valueTreeState.state.setPropertyExcludingListener(this, "uiWidth", getWidth(), nullptr);
sharedParams.setUiHeight(getHeight()); valueTreeState.state.setPropertyExcludingListener(this, "uiHeight", getHeight(), nullptr);
// {
// RangedAudioParameter *param {valueTreeState.getParameter("uiWidth2")};
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// *castParam = getWidth();
// }
// {
// RangedAudioParameter *param {valueTreeState.getParameter("uiHeight2")};
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// *castParam = getHeight();
// }
// sharedParams.setUiWidth(getWidth());
// sharedParams.setUiHeight(getHeight());
// Rectangle<int> r2 (getLocalBounds()); // Rectangle<int> r2 (getLocalBounds());
// r2.reduce(0, padding); // r2.reduce(0, padding);
@ -154,10 +237,10 @@ bool JuicySFAudioProcessorEditor::keyStateChanged (bool isKeyDown) {
// return false; // return false;
} }
FilePickerFragment& JuicySFAudioProcessorEditor::getFilePicker() { //FilePickerFragment& JuicySFAudioProcessorEditor::getFilePicker() {
return filePicker; // return filePicker;
} //}
//
SlidersFragment& JuicySFAudioProcessorEditor::getSliders() { //SlidersFragment& JuicySFAudioProcessorEditor::getSliders() {
return slidersComponent; // return slidersComponent;
} //}

View File

@ -23,14 +23,18 @@
//============================================================================== //==============================================================================
/** /**
*/ */
class JuicySFAudioProcessorEditor : public AudioProcessorEditor, class JuicySFAudioProcessorEditor
public ExposesComponents/*, : public AudioProcessorEditor
// , public AudioProcessorValueTreeState::Listener
, public ValueTree::Listener
/*,
, public ExposesComponents
public StateChangeSubscriber*/ public StateChangeSubscriber*/
{ {
public: public:
JuicySFAudioProcessorEditor( JuicySFAudioProcessorEditor(
JuicySFAudioProcessor&, JuicySFAudioProcessor&,
AudioProcessorValueTreeState& state AudioProcessorValueTreeState& valueTreeState
); );
~JuicySFAudioProcessorEditor(); ~JuicySFAudioProcessorEditor();
@ -44,16 +48,33 @@ public:
// void getStateInformation (XmlElement& xml) override; // void getStateInformation (XmlElement& xml) override;
// void setStateInformation (XmlElement* xmlState) override; // void setStateInformation (XmlElement* xmlState) override;
virtual FilePickerFragment& getFilePicker() override; // virtual FilePickerFragment& getFilePicker() override;
virtual SlidersFragment& getSliders() override; // virtual SlidersFragment& getSliders() override;
// virtual void parameterChanged (const String& parameterID, float newValue) override;
// 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 {};
private: private:
// This reference is provided as a quick way for your editor to // This reference is provided as a quick way for your editor to
// access the processor object that created it. // access the processor object that created it.
JuicySFAudioProcessor& processor; JuicySFAudioProcessor& processor;
AudioProcessorValueTreeState& valueTreeState; AudioProcessorValueTreeState& valueTreeState;
SharesParams& sharedParams; // SharesParams& sharedParams;
SurjectiveMidiKeyboardComponent midiKeyboard; SurjectiveMidiKeyboardComponent midiKeyboard;
TablesComponent tablesComponent; TablesComponent tablesComponent;

View File

@ -17,7 +17,7 @@
#include "Util.h" #include "Util.h"
#include "SharesParams.h" #include "SharesParams.h"
#include "Params.h" #include "Params.h"
#include "MidiConstants.h" #include "GuiConstants.h"
using namespace std; using namespace std;
using Parameter = AudioProcessorValueTreeState::Parameter; using Parameter = AudioProcessorValueTreeState::Parameter;
@ -29,13 +29,13 @@ AudioProcessor* JUCE_CALLTYPE createPluginFilter();
//, sharedParams{static_pointer_cast<SharesParams>(make_shared<Params>())} //, sharedParams{static_pointer_cast<SharesParams>(make_shared<Params>())}
JuicySFAudioProcessor::JuicySFAudioProcessor() JuicySFAudioProcessor::JuicySFAudioProcessor()
: AudioProcessor{getBusesProperties()} : AudioProcessor{getBusesProperties()}
, sharedParams{} // , sharedParams{}
, valueTreeState{ , valueTreeState{
*this, *this,
nullptr, nullptr,
{ "MYPLUGINSETTINGS" }, { "MYPLUGINSETTINGS" },
createParameterLayout()} createParameterLayout()}
, fluidSynthModel{valueTreeState, sharedParams} , fluidSynthModel{valueTreeState, valueTree}
//, fluidSynthModel{*this} //, fluidSynthModel{*this}
//, pluginEditor(nullptr) //, pluginEditor(nullptr)
{ {
@ -53,15 +53,22 @@ AudioProcessorValueTreeState::ParameterLayout JuicySFAudioProcessor::createParam
// https://stackoverflow.com/a/8469002/5257399 // https://stackoverflow.com/a/8469002/5257399
unique_ptr<AudioParameterInt> params[] { unique_ptr<AudioParameterInt> params[] {
make_unique<AudioParameterInt>("bank", "which bank is selected in the soundfont", 0, 127, 0, "Bank" ), // make_unique<AudioParameterInt>("uiWidthPersist", "width of this plugin's GUI. Editor listens for changes (e.g. on load)", GuiConstants::minWidth, GuiConstants::maxWidth, GuiConstants::minWidth, "UI Width Persist" ),
// make_unique<AudioParameterInt>("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<AudioParameterInt>("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<AudioParameterInt>("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<AudioParameterInt>("uiWidth", "width of this plugin's GUI", GuiConstants::minWidth, GuiConstants::maxWidth, GuiConstants::minWidth, "UI Width" ),
make_unique<AudioParameterInt>("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<AudioParameterInt>("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. // note: banks may be sparse, and lack a 0th preset. so defend against this.
make_unique<AudioParameterInt>("preset", "which patch (aka patch, program, instrument) is selected in the soundfont", 0, 127, 0, "Preset" ), make_unique<AudioParameterInt>("preset", "which patch (aka patch, program, instrument) is selected in the soundfont", MidiConstants::midiMinValue, MidiConstants::midiMaxValue, MidiConstants::midiMinValue, "Preset" ),
make_unique<AudioParameterInt>("attack", "volume envelope attack time", 0, 127, 0, "A" ), make_unique<AudioParameterInt>("attack", "volume envelope attack time", MidiConstants::midiMinValue, MidiConstants::midiMaxValue, MidiConstants::midiMinValue, "A" ),
make_unique<AudioParameterInt>("decay", "volume envelope sustain attentuation", 0, 127, 0, "D" ), make_unique<AudioParameterInt>("decay", "volume envelope sustain attentuation", MidiConstants::midiMinValue, MidiConstants::midiMaxValue, MidiConstants::midiMinValue, "D" ),
make_unique<AudioParameterInt>("sustain", "volume envelope decay time", 0, 127, 0, "S" ), make_unique<AudioParameterInt>("sustain", "volume envelope decay time", MidiConstants::midiMinValue, MidiConstants::midiMaxValue, MidiConstants::midiMinValue, "S" ),
make_unique<AudioParameterInt>("release", "volume envelope release time", 0, 127, 0, "R" ), make_unique<AudioParameterInt>("release", "volume envelope release time", MidiConstants::midiMinValue, MidiConstants::midiMaxValue, MidiConstants::midiMinValue, "R" ),
make_unique<AudioParameterInt>("filterCutOff", "low-pass filter cut-off frequency", 0, 127, 0, "Cut" ), make_unique<AudioParameterInt>("filterCutOff", "low-pass filter cut-off frequency", MidiConstants::midiMinValue, MidiConstants::midiMaxValue, MidiConstants::midiMinValue, "Cut" ),
make_unique<AudioParameterInt>("filterResonance", "low-pass filter resonance attentuation", 0, 127, 0, "Res" ), make_unique<AudioParameterInt>("filterResonance", "low-pass filter resonance attentuation", MidiConstants::midiMinValue, MidiConstants::midiMaxValue, MidiConstants::midiMinValue, "Res" ),
}; };
return { return {
@ -215,7 +222,7 @@ void JuicySFAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer
fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel()); fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel());
fluid_midi_event_set_control(midi_event, m.getControllerNumber()); fluid_midi_event_set_control(midi_event, m.getControllerNumber());
fluid_midi_event_set_value(midi_event, m.getControllerValue()); fluid_midi_event_set_value(midi_event, m.getControllerValue());
fluid_synth_handle_midi_event(fluidSynth, midi_event); fluid_synth_handle_midi_event(fluidSynthModel.getSynth().get(), midi_event);
delete_fluid_midi_event(midi_event); delete_fluid_midi_event(midi_event);
switch(static_cast<fluid_midi_control_change>(m.getControllerNumber())) { switch(static_cast<fluid_midi_control_change>(m.getControllerNumber())) {
@ -274,21 +281,21 @@ void JuicySFAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer
fluid_midi_event_set_type(midi_event, static_cast<int>(PROGRAM_CHANGE)); fluid_midi_event_set_type(midi_event, static_cast<int>(PROGRAM_CHANGE));
fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel()); fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel());
fluid_midi_event_set_program(midi_event, m.getProgramChangeNumber()); fluid_midi_event_set_program(midi_event, m.getProgramChangeNumber());
fluid_synth_handle_midi_event(fluidSynth, midi_event); fluid_synth_handle_midi_event(fluidSynthModel.getSynth().get(), midi_event);
delete_fluid_midi_event(midi_event); delete_fluid_midi_event(midi_event);
} else if (m.isPitchWheel()) { } else if (m.isPitchWheel()) {
fluid_midi_event_t *midi_event(new_fluid_midi_event()); fluid_midi_event_t *midi_event(new_fluid_midi_event());
fluid_midi_event_set_type(midi_event, static_cast<int>(PITCH_BEND)); fluid_midi_event_set_type(midi_event, static_cast<int>(PITCH_BEND));
fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel()); fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel());
fluid_midi_event_set_pitch(midi_event, m.getPitchWheelValue()); fluid_midi_event_set_pitch(midi_event, m.getPitchWheelValue());
fluid_synth_handle_midi_event(fluidSynth, midi_event); fluid_synth_handle_midi_event(fluidSynthModel.getSynth().get(), midi_event);
delete_fluid_midi_event(midi_event); delete_fluid_midi_event(midi_event);
} else if (m.isChannelPressure()) { } else if (m.isChannelPressure()) {
fluid_midi_event_t *midi_event(new_fluid_midi_event()); fluid_midi_event_t *midi_event(new_fluid_midi_event());
fluid_midi_event_set_type(midi_event, static_cast<int>(CHANNEL_PRESSURE)); fluid_midi_event_set_type(midi_event, static_cast<int>(CHANNEL_PRESSURE));
fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel()); fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel());
fluid_midi_event_set_program(midi_event, m.getChannelPressureValue()); fluid_midi_event_set_program(midi_event, m.getChannelPressureValue());
fluid_synth_handle_midi_event(fluidSynth, midi_event); fluid_synth_handle_midi_event(fluidSynthModel.getSynth().get(), midi_event);
delete_fluid_midi_event(midi_event); delete_fluid_midi_event(midi_event);
} else if (m.isAftertouch()) { } else if (m.isAftertouch()) {
fluid_midi_event_t *midi_event(new_fluid_midi_event()); fluid_midi_event_t *midi_event(new_fluid_midi_event());
@ -296,12 +303,12 @@ void JuicySFAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer
fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel()); fluid_midi_event_set_channel(midi_event, fluidSynthModel.getChannel());
fluid_midi_event_set_key(midi_event, m.getNoteNumber()); fluid_midi_event_set_key(midi_event, m.getNoteNumber());
fluid_midi_event_set_value(midi_event, m.getAfterTouchValue()); fluid_midi_event_set_value(midi_event, m.getAfterTouchValue());
fluid_synth_handle_midi_event(fluidSynth, midi_event); fluid_synth_handle_midi_event(fluidSynthModel.getSynth().get(), midi_event);
delete_fluid_midi_event(midi_event); delete_fluid_midi_event(midi_event);
// } else if (m.isMetaEvent()) { // } else if (m.isMetaEvent()) {
// fluid_midi_event_t *midi_event(new_fluid_midi_event()); // fluid_midi_event_t *midi_event(new_fluid_midi_event());
// fluid_midi_event_set_type(midi_event, static_cast<int>(MIDI_SYSTEM_RESET)); // fluid_midi_event_set_type(midi_event, static_cast<int>(MIDI_SYSTEM_RESET));
// fluid_synth_handle_midi_event(fluidSynth, midi_event); // fluid_synth_handle_midi_event(fluidSynthModel.getSynth().get(), midi_event);
// delete_fluid_midi_event(midi_event); // delete_fluid_midi_event(midi_event);
} else if (m.isSysEx()) { } else if (m.isSysEx()) {
fluid_midi_event_t *midi_event(new_fluid_midi_event()); fluid_midi_event_t *midi_event(new_fluid_midi_event());
@ -309,7 +316,7 @@ void JuicySFAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer
// I assume that the MidiMessage's sysex buffer would be freed anyway when MidiMessage is destroyed, so set dynamic=false // I assume that the MidiMessage's sysex buffer would be freed anyway when MidiMessage is destroyed, so set dynamic=false
// to ensure that fluidsynth does not attempt to free the sysex buffer during delete_fluid_midi_event() // to ensure that fluidsynth does not attempt to free the sysex buffer during delete_fluid_midi_event()
fluid_midi_event_set_sysex(midi_event, const_cast<juce::uint8*>(m.getSysExData()), m.getSysExDataSize(), static_cast<int>(false)); fluid_midi_event_set_sysex(midi_event, const_cast<juce::uint8*>(m.getSysExData()), m.getSysExDataSize(), static_cast<int>(false));
fluid_synth_handle_midi_event(fluidSynth, midi_event); fluid_synth_handle_midi_event(fluidSynthModel.getSynth().get(), midi_event);
delete_fluid_midi_event(midi_event); delete_fluid_midi_event(midi_event);
} }
} }
@ -324,7 +331,7 @@ void JuicySFAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer
// and now get our synth to process these midi events and generate its output. // and now get our synth to process these midi events and generate its output.
synth.renderNextBlock (buffer, midiMessages, 0, numSamples); synth.renderNextBlock (buffer, midiMessages, 0, numSamples);
fluid_synth_process(fluidSynth, numSamples, 0, nullptr, buffer.getNumChannels(), buffer.getArrayOfWritePointers()); fluid_synth_process(fluidSynthModel.getSynth().get(), numSamples, 0, nullptr, buffer.getNumChannels(), buffer.getArrayOfWritePointers());
// (see juce_VST3_Wrapper.cpp for the assertion this would trip otherwise) // (see juce_VST3_Wrapper.cpp for the assertion this would trip otherwise)
// we are !JucePlugin_ProducesMidiOutput, so clear remaining MIDI messages from our buffer // we are !JucePlugin_ProducesMidiOutput, so clear remaining MIDI messages from our buffer
@ -364,7 +371,7 @@ void JuicySFAudioProcessor::getStateInformation (MemoryBlock& destData)
// sharedParams->setAttributesOnXml(xml); // sharedParams->setAttributesOnXml(xml);
auto state{valueTreeState.copyState()}; auto state{valueTreeState.copyState()};
shared_ptr<XmlElement> xml{state.createXml()}; shared_ptr<XmlElement> xml{state.createXml()};
sharedParams.setAttributesOnXml(xml); // sharedParams.setAttributesOnXml(xml);
// list<StateChangeSubscriber*>::iterator p; // list<StateChangeSubscriber*>::iterator p;
// for(p = stateChangeSubscribers.begin(); p != stateChangeSubscribers.end(); p++) { // for(p = stateChangeSubscribers.begin(); p != stateChangeSubscribers.end(); p++) {
@ -399,7 +406,7 @@ void JuicySFAudioProcessor::setStateInformation (const void* data, int sizeInByt
// } // }
// ok, now pull out our last window size.. // ok, now pull out our last window size..
sharedParams.loadAttributesFromXml(xmlState); // sharedParams.loadAttributesFromXml(xmlState);
// Now reload our parameters.. // Now reload our parameters..
@ -448,9 +455,9 @@ FluidSynthModel& JuicySFAudioProcessor::getFluidSynthModel() {
return fluidSynthModel; return fluidSynthModel;
} }
SharesParams& JuicySFAudioProcessor::getSharedParams() { //SharesParams& JuicySFAudioProcessor::getSharedParams() {
return sharedParams; // return sharedParams;
} //}
//============================================================================== //==============================================================================
// This creates new instances of the plugin.. // This creates new instances of the plugin..

View File

@ -64,7 +64,7 @@ public:
bool supportsDoublePrecisionProcessing() const override; bool supportsDoublePrecisionProcessing() const override;
FluidSynthModel& getFluidSynthModel(); FluidSynthModel& getFluidSynthModel();
SharesParams& getSharedParams(); // SharesParams& getSharedParams();
MidiKeyboardState keyboardState; MidiKeyboardState keyboardState;
@ -74,11 +74,12 @@ public:
private: private:
void initialiseSynth(); void initialiseSynth();
Params sharedParams; // Params sharedParams;
AudioProcessorValueTreeState valueTreeState; AudioProcessorValueTreeState valueTreeState;
ValueTree valueTree;
FluidSynthModel fluidSynthModel; FluidSynthModel fluidSynthModel;
fluid_synth_t* fluidSynth; // fluid_synth_t* fluidSynth;
Synthesiser synth; Synthesiser synth;
// // just a raw pointer; we do not own // // just a raw pointer; we do not own

View File

@ -24,10 +24,10 @@ public:
// virtual int getBank() = 0; // virtual int getBank() = 0;
// virtual void setBank(int value) = 0; // virtual void setBank(int value) = 0;
virtual int getUiWidth() = 0; // virtual int getUiWidth() = 0;
virtual void setUiWidth(int value) = 0; // virtual void setUiWidth(int value) = 0;
virtual int getUiHeight() = 0; // virtual int getUiHeight() = 0;
virtual void setUiHeight(int value) = 0; // virtual void setUiHeight(int value) = 0;
// virtual int getAttack() = 0; // virtual int getAttack() = 0;
// virtual void setAttack(int value) = 0; // virtual void setAttack(int value) = 0;

View File

@ -115,11 +115,11 @@ void SlidersComponent::acceptMidiControlEvent(int controller, int value) {
// } // }
SlidersComponent::SlidersComponent( SlidersComponent::SlidersComponent(
SharesParams& sharedParams, // SharesParams& sharedParams,
AudioProcessorValueTreeState& valueTreeState, AudioProcessorValueTreeState& valueTreeState,
FluidSynthModel& fluidSynthModel) FluidSynthModel& fluidSynthModel)
: sharedParams{sharedParams} // : sharedParams{sharedParams}
, valueTreeState{valueTreeState} : valueTreeState{valueTreeState}
, fluidSynthModel{fluidSynthModel} , fluidSynthModel{fluidSynthModel}
, envelopeGroup{"envelopeGroup", "Envelope"} , envelopeGroup{"envelopeGroup", "Envelope"}
, filterGroup{"filterGroup", "Filter"} , filterGroup{"filterGroup", "Filter"}

View File

@ -13,7 +13,7 @@ class SlidersComponent : public Component,
{ {
public: public:
SlidersComponent( SlidersComponent(
SharesParams& sharedParams, // SharesParams& sharedParams,
AudioProcessorValueTreeState& valueTreeState, AudioProcessorValueTreeState& valueTreeState,
FluidSynthModel& fluidSynthModel); FluidSynthModel& fluidSynthModel);
~SlidersComponent(); ~SlidersComponent();
@ -35,7 +35,7 @@ public:
private: private:
std::function<void()> makeSliderListener(Slider& slider, int controller); std::function<void()> makeSliderListener(Slider& slider, int controller);
SharesParams& sharedParams; // SharesParams& sharedParams;
AudioProcessorValueTreeState& valueTreeState; AudioProcessorValueTreeState& valueTreeState;
FluidSynthModel& fluidSynthModel; FluidSynthModel& fluidSynthModel;