From f87ec7c8e4898142b665123a7fa286eb8f2a5373 Mon Sep 17 00:00:00 2001 From: Alex Birch Date: Sat, 27 Jul 2019 23:04:20 +0100 Subject: [PATCH] remove some unused methods on FluidSynthModel. make FilePicker update displayed text upon load. read and write into XML just the bits that we need, and take advantage of attribute names' being indexed. take more care in setting sfont_id. --- Source/FilePicker.cpp | 9 +- Source/FilePicker.h | 2 +- Source/FluidSynthModel.cpp | 241 ++++++++++++++++++++----------------- Source/FluidSynthModel.h | 16 +-- Source/PluginProcessor.cpp | 66 +++++++--- 5 files changed, 194 insertions(+), 140 deletions(-) diff --git a/Source/FilePicker.cpp b/Source/FilePicker.cpp index 4787f49..d2a7eff 100644 --- a/Source/FilePicker.cpp +++ b/Source/FilePicker.cpp @@ -66,7 +66,8 @@ void FilePicker::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasChanged // if (&treeWhosePropertyHasChanged == &valueTree) { if (property == StringRef("path")) { String soundFontPath{treeWhosePropertyHasChanged.getProperty("path", "")}; - // DEBUG_PRINT(soundFontPath); + DEBUG_PRINT(soundFontPath); + setDisplayedFilePath(soundFontPath); // if (soundFontPath.isNotEmpty()) { // loadFont(soundFontPath); // } @@ -75,9 +76,9 @@ void FilePicker::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasChanged } void FilePicker::setDisplayedFilePath(const String& path) { - // if (!shouldChangeDisplayedFilePath(path)) { - // return; - // } + if (!shouldChangeDisplayedFilePath(path)) { + return; + } // currentPath = path; fileChooser.setCurrentFile(File(path), true, dontSendNotification); } diff --git a/Source/FilePicker.h b/Source/FilePicker.h index f590604..5d34c8c 100644 --- a/Source/FilePicker.h +++ b/Source/FilePicker.h @@ -50,4 +50,4 @@ private: bool shouldChangeDisplayedFilePath(const String &path); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FilePicker) -}; \ No newline at end of file +}; diff --git a/Source/FluidSynthModel.cpp b/Source/FluidSynthModel.cpp index d0294c0..20fd318 100644 --- a/Source/FluidSynthModel.cpp +++ b/Source/FluidSynthModel.cpp @@ -20,10 +20,10 @@ FluidSynthModel::FluidSynthModel( // , sharedParams{sharedParams} //, synth{nullptr} , settings{nullptr, nullptr} -, currentSoundFontAbsPath{} +//, currentSoundFontAbsPath{} , currentSampleRate{44100} -, initialised{false} -, sfont_id{0} +//, initialised{false} +, sfont_id{-1} , channel{0}/*, mod(nullptr)*/ { @@ -97,12 +97,15 @@ void FluidSynthModel::initialise() { // loadFont(sharedParams.getSoundFontPath()); // changePreset(sharedParams->getBank(), sharedParams->getPreset()); // } + ValueTree soundFont{valueTreeState.state.getChildWithName("soundFont")}; + String path{soundFont.getProperty("path", "")}; + loadFont(path); fluid_synth_set_gain(synth.get(), 2.0); - for(int i{SOUND_CTRL1}; i <= SOUND_CTRL10; i++) - { - setControllerValue(i, 0); + fluid_midi_control_change controllers[]{SOUND_CTRL2, SOUND_CTRL3, SOUND_CTRL4, SOUND_CTRL5, SOUND_CTRL6, SOUND_CTRL10}; + for(fluid_midi_control_change controller : controllers) { + setControllerValue(static_cast(controller), 0); } // fluid_synth_bank_select(synth, 0, 3); @@ -116,7 +119,7 @@ void FluidSynthModel::initialise() { // float env_amount(12000.0f); // http://www.synthfont.com/SoundFont_NRPNs.PDF - float env_amount(20000.0f); + float env_amount{20000.0f}; // float env_amount(24000.0f); // note: fluid_chan.c#fluid_channel_init_ctrl() @@ -200,7 +203,7 @@ void FluidSynthModel::initialise() { fluid_mod_set_amount(mod.get(), 1000.0f); fluid_synth_add_default_mod(synth.get(), mod.get(), FLUID_SYNTH_ADD); - valueTreeState.state.getChildWithName("soundFont").sendPropertyChangeMessage("path"); +// valueTreeState.state.getChildWithName("soundFont").sendPropertyChangeMessage("path"); // valueTree.sendPropertyChangeMessage("soundFontPath"); // initialised = true; @@ -273,7 +276,7 @@ void FluidSynthModel::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasCh if (property == StringRef("path")) { String soundFontPath{treeWhosePropertyHasChanged.getProperty("path", "")}; if (soundFontPath.isNotEmpty()) { - loadFont(soundFontPath); + unloadAndLoadFont(soundFontPath); } } } @@ -294,82 +297,82 @@ int FluidSynthModel::getChannel() { return channel; } -void FluidSynthModel::changePreset(int bank, int preset) { - if (bank == -1 || preset == -1) { - unique_ptr bankAndPreset = getFirstBankAndPreset(); - bank = bankAndPreset->getBank(); - preset = bankAndPreset->getPreset(); - } - changePresetImpl(bank, preset); -// sharedParams->setPreset(preset); -// sharedParams->setBank(bank); -} +//void FluidSynthModel::changePreset(int bank, int preset) { +// if (bank == -1 || preset == -1) { +// unique_ptr bankAndPreset = getFirstBankAndPreset(); +// bank = bankAndPreset->getBank(); +// preset = bankAndPreset->getPreset(); +// } +// changePresetImpl(bank, preset); +//// sharedParams->setPreset(preset); +//// sharedParams->setBank(bank); +//} -void FluidSynthModel::changePresetImpl(int bank, int preset) { - fluid_synth_program_select(synth.get(), channel, sfont_id, static_cast(bank), static_cast(preset)); -} +//void FluidSynthModel::changePresetImpl(int bank, int preset) { +// fluid_synth_program_select(synth.get(), channel, sfont_id, static_cast(bank), static_cast(preset)); +//} -fluid_preset_t* FluidSynthModel::getFirstPreset() { - fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(synth.get(), sfont_id); +//fluid_preset_t* FluidSynthModel::getFirstPreset() { +// fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(synth.get(), sfont_id); +// +// jassert(sfont != nullptr); +// fluid_sfont_iteration_start(sfont); +// +// return fluid_sfont_iteration_next(sfont); +//} +// +//unique_ptr FluidSynthModel::getFirstBankAndPreset() { +// fluid_preset_t* preset = getFirstPreset(); +// +// int offset = fluid_synth_get_bank_offset(synth.get(), sfont_id); +// +// return make_unique(fluid_preset_get_banknum(preset) + offset, fluid_preset_get_num(preset)); +//}; +// +//void FluidSynthModel::selectFirstPreset() { +// fluid_preset_t* preset = getFirstPreset(); +// +// int offset = fluid_synth_get_bank_offset(synth.get(), sfont_id); +// +// changePreset(fluid_preset_get_banknum(preset) + offset, fluid_preset_get_num(preset)); +//} - jassert(sfont != nullptr); - fluid_sfont_iteration_start(sfont); - - return fluid_sfont_iteration_next(sfont); -} - -unique_ptr FluidSynthModel::getFirstBankAndPreset() { - fluid_preset_t* preset = getFirstPreset(); - - int offset = fluid_synth_get_bank_offset(synth.get(), sfont_id); - - return make_unique(fluid_preset_get_banknum(preset) + offset, fluid_preset_get_num(preset)); -}; - -void FluidSynthModel::selectFirstPreset() { - fluid_preset_t* preset = getFirstPreset(); - - int offset = fluid_synth_get_bank_offset(synth.get(), sfont_id); - - changePreset(fluid_preset_get_banknum(preset) + offset, fluid_preset_get_num(preset)); -} - -BanksToPresets FluidSynthModel::getBanks() { - BanksToPresets banksToPresets; - - int soundfontCount = fluid_synth_sfcount(synth.get()); - - if (soundfontCount == 0) { - // no soundfont selected - return banksToPresets; - } - - fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(synth.get(), sfont_id); - if(sfont == nullptr) { - // no soundfont found by that ID - // the above guard (soundfontCount) protects us for the - // main case we're expecting. this guard is just defensive programming. - return banksToPresets; - } - - int offset = fluid_synth_get_bank_offset(synth.get(), sfont_id); - - fluid_sfont_iteration_start(sfont); - - for(fluid_preset_t* preset = fluid_sfont_iteration_next(sfont); - preset != nullptr; - preset = fluid_sfont_iteration_next(sfont)) { - banksToPresets.insert(BanksToPresets::value_type( - fluid_preset_get_banknum(preset) + offset, - *new Preset( - fluid_preset_get_num(preset), - fluid_preset_get_name(preset) - ) - )); - } - - return banksToPresets; -} +//BanksToPresets FluidSynthModel::getBanks() { +// BanksToPresets banksToPresets; +// +// int soundfontCount = fluid_synth_sfcount(synth.get()); +// +// if (soundfontCount == 0) { +// // no soundfont selected +// return banksToPresets; +// } +// +// fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(synth.get(), sfont_id); +// if(sfont == nullptr) { +// // no soundfont found by that ID +// // the above guard (soundfontCount) protects us for the +// // main case we're expecting. this guard is just defensive programming. +// return banksToPresets; +// } +// +// int offset = fluid_synth_get_bank_offset(synth.get(), sfont_id); +// +// fluid_sfont_iteration_start(sfont); +// +// for(fluid_preset_t* preset = fluid_sfont_iteration_next(sfont); +// preset != nullptr; +// preset = fluid_sfont_iteration_next(sfont)) { +// banksToPresets.insert(BanksToPresets::value_type( +// fluid_preset_get_banknum(preset) + offset, +// *new Preset( +// fluid_preset_get_num(preset), +// fluid_preset_get_name(preset) +// ) +// )); +// } +// +// return banksToPresets; +//} shared_ptr FluidSynthModel::getSynth() { // https://msdn.microsoft.com/en-us/library/hh279669.aspx @@ -378,38 +381,50 @@ shared_ptr FluidSynthModel::getSynth() { return synth; } -void FluidSynthModel::onFileNameChanged(const String &absPath, int bank, int preset) { - if (!shouldLoadFont(absPath)) { - return; - } - unloadAndLoadFont(absPath); - changePreset(bank, preset); - ValueTree valueTree{valueTreeState.state.getChildWithName("soundFont")}; - valueTree.setPropertyExcludingListener(this, "path", absPath, nullptr); - // valueTree.setPropertyExcludingListener(this, "soundFontPath", absPath, nullptr); -// sharedParams.setSoundFontPath(absPath); - // eventListeners.call(&FluidSynthModel::Listener::fontChanged, this, absPath); -} +//void FluidSynthModel::onFileNameChanged(const String &absPath, int bank, int preset) { +// if (!shouldLoadFont(absPath)) { +// return; +// } +// unloadAndLoadFont(absPath); +// changePreset(bank, preset); +// ValueTree valueTree{valueTreeState.state.getChildWithName("soundFont")}; +// valueTree.setPropertyExcludingListener(this, "path", absPath, nullptr); +// // valueTree.setPropertyExcludingListener(this, "soundFontPath", absPath, nullptr); +//// sharedParams.setSoundFontPath(absPath); +// // eventListeners.call(&FluidSynthModel::Listener::fontChanged, this, absPath); +//} void FluidSynthModel::unloadAndLoadFont(const String &absPath) { // in the base case, there is no font loaded if (fluid_synth_sfcount(synth.get()) > 0) { + // if -1 is returned, that indicates failure + // not really sure how to handle "fail to unload" fluid_synth_sfunload(synth.get(), sfont_id, 1); + sfont_id = -1; } loadFont(absPath); } void FluidSynthModel::loadFont(const String &absPath) { - currentSoundFontAbsPath = absPath; - sfont_id++; - fluid_synth_sfload(synth.get(), absPath.toStdString().c_str(), 1); +// currentSoundFontAbsPath = absPath; +// sfont_id++; +// fluid_synth_sfunload(synth.get(), sfont_id, 1); + if (!absPath.isEmpty()) { + sfont_id = fluid_synth_sfload(synth.get(), absPath.toStdString().c_str(), 1); + // if -1 is returned, that indicates failure + } + // refresh regardless of success, if only to clear the table refreshBanks(); } void FluidSynthModel::refreshBanks() { - fluid_sfont_t* sfont {fluid_synth_get_sfont_by_id(synth.get(), sfont_id)}; ValueTree banks{"banks"}; - if (sfont != nullptr) { + fluid_sfont_t* sfont{ + sfont_id == -1 + ? nullptr + : fluid_synth_get_sfont_by_id(synth.get(), sfont_id) + }; + if (sfont) { int greatestEncounteredBank{-1}; ValueTree bank; @@ -440,8 +455,8 @@ void FluidSynthModel::refreshBanks() { valueTreeState.state.getChildWithName("banks").sendPropertyChangeMessage("synthetic"); #if JUCE_DEBUG - unique_ptr xml{valueTreeState.state.createXml()}; - Logger::outputDebugString(xml->createDocument("",false,false)); +// unique_ptr xml{valueTreeState.state.createXml()}; +// Logger::outputDebugString(xml->createDocument("",false,false)); #endif } @@ -557,22 +572,22 @@ void FluidSynthModel::refreshBanks() { // FluidSynthModel::Listener::~Listener() { // } -bool FluidSynthModel::shouldLoadFont(const String &absPath) { - if (absPath.isEmpty()) { - return false; - } - if (absPath == currentSoundFontAbsPath) { - return false; - } - return true; -} +//bool FluidSynthModel::shouldLoadFont(const String &absPath) { +// if (absPath.isEmpty()) { +// return false; +// } +//// if (absPath == currentSoundFontAbsPath) { +//// return false; +//// } +// return true; +//} // void FluidSynthModel::Listener::fontChanged(FluidSynthModel * model, const String &absPath) { // } -const String& FluidSynthModel::getCurrentSoundFontAbsPath() { - return currentSoundFontAbsPath; -} +//const String& FluidSynthModel::getCurrentSoundFontAbsPath() { +// return currentSoundFontAbsPath; +//} //============================================================================== // void FluidSynthModel::addListener (FluidSynthModel::Listener* const newListener) diff --git a/Source/FluidSynthModel.h b/Source/FluidSynthModel.h index 92a06e6..3978721 100644 --- a/Source/FluidSynthModel.h +++ b/Source/FluidSynthModel.h @@ -31,12 +31,12 @@ public: shared_ptr getSynth(); void initialise(); - BanksToPresets getBanks(); +// BanksToPresets getBanks(); - void changePreset(int bank, int preset); +// void changePreset(int bank, int preset); int getChannel(); - void onFileNameChanged(const String &absPath, int bank, int preset); +// void onFileNameChanged(const String &absPath, int bank, int preset); void setControllerValue(int controller, int value); //============================================================================== @@ -68,7 +68,7 @@ public: void setSampleRate(float sampleRate); - const String& getCurrentSoundFontAbsPath(); +// const String& getCurrentSoundFontAbsPath(); virtual void parameterChanged (const String& parameterID, float newValue) override; @@ -123,7 +123,7 @@ private: shared_ptr synth; // unique_ptr midiDriver; - String currentSoundFontAbsPath; +// String currentSoundFontAbsPath; float currentSampleRate; @@ -133,12 +133,12 @@ private: void unloadAndLoadFont(const String &absPath); void loadFont(const String &absPath); - bool shouldLoadFont(const String &absPath); +// bool shouldLoadFont(const String &absPath); void changePresetImpl(int bank, int preset); - bool initialised; - unsigned int sfont_id; +// bool initialised; + int sfont_id; unsigned int channel; // fluid_mod_t* mod; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 2ad8085..e9831c5 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -218,7 +218,7 @@ void JuicySFAudioProcessor::processBlock (AudioBuffer& buffer, MidiBuffer int time; MidiMessage m; - // TODO: factor into a MidiCollector + // TODO: factor into a MidiMessageCollector for (MidiBuffer::Iterator i (midiMessages); i.getNextEvent (m, time);) { DEBUG_PRINT ( m.getDescription() ); @@ -385,10 +385,10 @@ void JuicySFAudioProcessor::getStateInformation (MemoryBlock& destData) // as intermediaries to make it easy to save and load complex data. // Create an outer XML element.. -// XmlElement xml{"MYPLUGINSETTINGS"}; + XmlElement xml{"MYPLUGINSETTINGS"}; // sharedParams->setAttributesOnXml(xml); - auto state{valueTreeState.copyState()}; - unique_ptr xml{state.createXml()}; +// auto state{valueTreeState.copyState()}; +// unique_ptr xml{state.createXml()}; // sharedParams.setAttributesOnXml(xml); // list::iterator p; @@ -397,14 +397,44 @@ void JuicySFAudioProcessor::getStateInformation (MemoryBlock& destData) // } // 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()); + XmlElement* params{xml.createNewChildElement("params")}; + for (auto* param : getParameters()) { + if (auto* p = dynamic_cast (param)) { +// xml.setAttribute(p->paramID, p->getValue()); +// XmlElement* param{params->createNewChildElement("PARAM")}; +// param->setAttribute(p->paramID, p->getValue()); + params->setAttribute(p->paramID, p->getValue()); + } + } + { + ValueTree tree{valueTreeState.state.getChildWithName("uiState")}; + XmlElement* newElement{xml.createNewChildElement("uiState")}; +// Value value{tree.getPropertyAsValue("width", nullptr)}; + { + double value{tree.getProperty("width", GuiConstants::minWidth)}; + newElement->setAttribute("width", value); + } + { + double value{tree.getProperty("height", GuiConstants::minHeight)}; + newElement->setAttribute("height", value); + } + } + { + ValueTree tree{valueTreeState.state.getChildWithName("soundFont")}; + XmlElement* newElement{xml.createNewChildElement("soundFont")}; + { + String value{tree.getProperty("path", "")}; + newElement->setAttribute("path", value); + } + } + + DEBUG_PRINT(xml.createDocument("",false,false)); // then use this helper function to stuff it into the binary blob and return it.. - if (xml.get() != nullptr) { - copyXmlToBinary(*xml, destData); - } +// if (xml.get() != nullptr) { +// copyXmlToBinary(*xml, destData); +// } + copyXmlToBinary(xml, destData); } void JuicySFAudioProcessor::setStateInformation (const void* data, int sizeInBytes) @@ -433,16 +463,24 @@ void JuicySFAudioProcessor::setStateInformation (const void* data, int sizeInByt // if (xmlState->hasTagName ("MYPLUGINSETTINGS")) { if (xmlState->hasTagName(valueTreeState.state.getType())) { // valueTreeState.replaceState(ValueTree::fromXml(*xmlState)); - for (auto* param : getParameters()) - if (auto* p = dynamic_cast(param)) - p->setValue(static_cast(xmlState->getDoubleAttribute(p->paramID, p->getValue()))); +// for (auto* param : getParameters()) +// if (auto* p = dynamic_cast(param)) +// p->setValue(static_cast(xmlState->getDoubleAttribute(p->paramID, p->getValue()))); + XmlElement* params{xmlState->getChildByName("params")}; + if (params) { + for (auto* param : getParameters()) + if (auto* p = dynamic_cast(param)) + // XmlElement* xmlParam{params->getChildByAttribute("id", p->paramID)}; + // p->setValue(static_cast(xmlState->getDoubleAttribute(p->paramID, p->getValue()))); + p->setValue(static_cast(params->getDoubleAttribute(p->paramID, p->getValue()))); + } { // Value value{valueTreeState.state.getPropertyAsValue("soundFontPath", nullptr)}; // value = xmlState->getStringAttribute("soundFontPath", value.getValue()); - ValueTree tree{valueTreeState.state.getChildWithName("soundFont")}; XmlElement* xmlElement{xmlState->getChildByName("soundFont")}; if (xmlElement) { + ValueTree tree{valueTreeState.state.getChildWithName("soundFont")}; Value value{tree.getPropertyAsValue("path", nullptr)}; value = xmlState->getStringAttribute("path", value.getValue()); }