From cdf6f890196954184d8ac69bc01c757050a69f24 Mon Sep 17 00:00:00 2001 From: Alex Birch Date: Sun, 28 Jul 2019 23:02:22 +0100 Subject: [PATCH] switch to unique_ptr for fluidsynth --- Source/FluidSynthModel.cpp | 383 ++++--------------------------------- Source/FluidSynthModel.h | 7 +- 2 files changed, 41 insertions(+), 349 deletions(-) diff --git a/Source/FluidSynthModel.cpp b/Source/FluidSynthModel.cpp index f7092a8..d902d02 100644 --- a/Source/FluidSynthModel.cpp +++ b/Source/FluidSynthModel.cpp @@ -12,20 +12,13 @@ using namespace std; FluidSynthModel::FluidSynthModel( AudioProcessorValueTreeState& valueTreeState - // ValueTree& valueTree - // SharesParams& sharedParams ) : valueTreeState{valueTreeState} -// , valueTree{valueTree} -// , sharedParams{sharedParams} -//, synth{nullptr} , settings{nullptr, nullptr} -//, currentSoundFontAbsPath{} +, synth{nullptr, nullptr} , currentSampleRate{44100} -//, initialised{false} , sfont_id{-1} -, channel{0}/*, -mod(nullptr)*/ +, channel{0} { valueTreeState.addParameterListener("bank", this); valueTreeState.addParameterListener("preset", this); @@ -36,28 +29,9 @@ FluidSynthModel::~FluidSynthModel() { valueTreeState.removeParameterListener("bank", this); valueTreeState.removeParameterListener("preset", this); valueTreeState.state.removeListener(this); - // if (initialised) { -// delete_fluid_audio_driver(driver); - // delete_fluid_synth(synth); -// delete_fluid_settings(settings); -// delete driver; -// delete settings; -// delete_fluid_mod(mod); - // } - } - -int FluidSynthModel::handleMidiEvent(void* data, fluid_midi_event_t* event) -{ -// DEBUG_PRINT(fluid_midi_event_get_type(event)); - // printf("event type: %d\n", fluid_midi_event_get_type(event)); - return 0; } void FluidSynthModel::initialise() { -// if (initialised) { -// delete_fluid_synth(synth); -// delete_fluid_settings(settings); -// } settings = { new_fluid_settings(), delete_fluid_settings }; // deactivate all audio drivers in fluidsynth to avoid FL Studio deadlock when initialising CoreAudio @@ -65,20 +39,6 @@ void FluidSynthModel::initialise() { const char *DRV[] {NULL}; fluid_audio_driver_register(DRV); -// handle_midi_event_func_t handler = [](void* data, fluid_midi_event_t* event) -> int { -// -// }; - -// midiDriver = unique_ptr( -// new_fluid_midi_driver( -// settings.get(), -// [](void* data, fluid_midi_event_t* event) -> int { -// -// }, -// nullptr), -// delete_fluid_midi_driver); - - // https://sourceforge.net/p/fluidsynth/wiki/FluidSettings/ #if JUCE_DEBUG fluid_settings_setint(settings.get(), "synth.verbose", 1); @@ -93,10 +53,6 @@ void FluidSynthModel::initialise() { // AudioParameterInt* castParam {dynamic_cast (param)}; // *castParam = m.getControllerValue(); -// if (sharedParams.getSoundFontPath().isNotEmpty()) { -// loadFont(sharedParams.getSoundFontPath()); -// changePreset(sharedParams->getBank(), sharedParams->getPreset()); -// } ValueTree soundFont{valueTreeState.state.getChildWithName("soundFont")}; String path{soundFont.getProperty("path", "")}; loadFont(path); @@ -202,20 +158,10 @@ void FluidSynthModel::initialise() { // clamps the range to between 0 and 1000, so we'll copy that 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"); - // valueTree.sendPropertyChangeMessage("soundFontPath"); - - // initialised = true; } void FluidSynthModel::parameterChanged(const String& parameterID, float newValue) { if (parameterID == "bank") { - // RangedAudioParameter *param {valueTreeState.getParameter("bank")}; - // jassert(dynamic_cast (param) != nullptr); - // AudioParameterInt* castParam {dynamic_cast (param)}; - // int value{castParam->get()}; - int bank, preset; { RangedAudioParameter *param {valueTreeState.getParameter("bank")}; @@ -236,15 +182,6 @@ void FluidSynthModel::parameterChanged(const String& parameterID, float newValue sfont_id, static_cast(bankOffset + bank), static_cast(preset)); - - // fluid_synth_bank_select(synth.get(), channel, value); -// refreshPresets(); - // fluid_sfont_t* sfont{fluid_synth_get_sfont_by_id(synth.get(), sfont_id)}; - // fluid_sfont_iteration_start(sfont); - // fluid_preset_t* presetObj{fluid_sfont_iteration_next(sfont)}; - // int offset{fluid_synth_get_bank_offset(synth.get(), sfont_id)}; - // int bank{fluid_preset_get_banknum(presetObj) + offset}; - // int preset{fluid_preset_get_num(presetObj)}; } else if (parameterID == "preset") { int bank, preset; { @@ -272,7 +209,6 @@ void FluidSynthModel::parameterChanged(const String& parameterID, float newValue void FluidSynthModel::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasChanged, const Identifier& property) { if (treeWhosePropertyHasChanged.getType() == StringRef("soundFont")) { - // if (&treeWhosePropertyHasChanged == &valueTree) { if (property == StringRef("path")) { String soundFontPath{treeWhosePropertyHasChanged.getProperty("path", "")}; if (soundFontPath.isNotEmpty()) { @@ -283,117 +219,17 @@ void FluidSynthModel::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasCh } void FluidSynthModel::setControllerValue(int controller, int value) { - fluid_midi_event_t *midi_event(new_fluid_midi_event()); - fluid_midi_event_set_type(midi_event, static_cast(CONTROL_CHANGE)); - fluid_midi_event_set_channel(midi_event, channel); - fluid_midi_event_set_control(midi_event, controller); - fluid_midi_event_set_value(midi_event, value); - fluid_synth_handle_midi_event(synth.get(), midi_event); - delete_fluid_midi_event(midi_event); - // fluid_channel_set_cc(channel, i, 0); + fluid_synth_cc( + synth.get(), + channel, + controller, + value); } 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::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); -// -// 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; -//} - -shared_ptr FluidSynthModel::getSynth() { - // https://msdn.microsoft.com/en-us/library/hh279669.aspx - // You can pass a shared_ptr to another function in the following ways: - // Pass the shared_ptr by value. This invokes the copy constructor, increments the reference count, and makes the callee an owner. - 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::unloadAndLoadFont(const String &absPath) { // in the base case, there is no font loaded if (fluid_synth_sfcount(synth.get()) > 0) { @@ -406,9 +242,6 @@ void FluidSynthModel::unloadAndLoadFont(const String &absPath) { } void FluidSynthModel::loadFont(const String &absPath) { -// 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 @@ -460,146 +293,6 @@ void FluidSynthModel::refreshBanks() { #endif } -// void FluidSynthModel::refreshBanks() { -// fluid_sfont_t* sfont {fluid_synth_get_sfont_by_id(synth.get(), sfont_id)}; -// ValueTree banks{"banks"}; -// if (sfont != nullptr) { -// // int initialBankOffset{fluid_synth_get_bank_offset(synth.get(), sfont_id)}; -// banks.appendChild({ "bank", { -// { "num", /* initialBankOffset */ 0 }, -// }, {} }, nullptr); -// // int greatestPersistedBank{initialBankOffset}; -// int greatestPersistedBank{0}; - -// fluid_sfont_iteration_start(sfont); - -// for(fluid_preset_t* preset {fluid_sfont_iteration_next(sfont)}; -// preset != nullptr; -// preset = fluid_sfont_iteration_next(sfont)) { -// int bank{fluid_preset_get_banknum(preset) /* + initialBankOffset */}; -// if (bank > greatestPersistedBank) { -// banks.appendChild({ "bank", { -// { "num", bank }, -// }, {} }, nullptr); -// greatestPersistedBank = bank; -// } -// } -// } -// valueTreeState.state.getChildWithName("banks").copyPropertiesAndChildrenFrom(banks, nullptr); -// valueTreeState.state.getChildWithName("banks").sendPropertyChangeMessage("synthetic"); -// refreshPresets(); -// } - -// void FluidSynthModel::refreshPresets() { -// fluid_sfont_t* sfont {fluid_synth_get_sfont_by_id(synth.get(), sfont_id)}; -// ValueTree presets{"presets"}; -// if (sfont != nullptr) { -// RangedAudioParameter *param {valueTreeState.getParameter("bank")}; -// jassert(dynamic_cast (param) != nullptr); -// AudioParameterInt* castParam {dynamic_cast (param)}; -// int value{castParam->get()}; - -// // int initialBank{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)) { -// int bank{fluid_preset_get_banknum(preset) /* + initialBank */}; -// if (bank == value) { -// presets.appendChild({ "preset", { -// { "num", fluid_preset_get_num(preset) }, -// { "name", String{fluid_preset_get_name(preset)} } -// }, {} }, nullptr); -// } -// } -// } -// valueTreeState.state.getChildWithName("presets").copyPropertiesAndChildrenFrom(presets, nullptr); -// valueTreeState.state.getChildWithName("presets").sendPropertyChangeMessage("synthetic"); -// } - -// void FluidSynthModel::refreshBanksAndPresets() { -// fluid_sfont_t* sfont {fluid_synth_get_sfont_by_id(synth.get(), sfont_id)}; -// ValueTree banks{"banks"}; -// ValueTree presets{"presets"}; -// if (sfont != nullptr) { -// int initialBankOffset{fluid_synth_get_bank_offset(synth.get(), sfont_id)}; -// banks.appendChild({ "bank", { -// { "num", initialBankOffset }, -// }, {} }, nullptr); -// int greatestPersistedBank{initialBankOffset}; - -// fluid_sfont_iteration_start(sfont); - -// for(fluid_preset_t* preset {fluid_sfont_iteration_next(sfont)}; -// preset != nullptr; -// preset = fluid_sfont_iteration_next(sfont)) { -// int bankOffset{fluid_preset_get_banknum(preset) + initialBankOffset}; -// // ValueTree preset{"preset"}; -// // banksToPresets.insert(BanksToPresets::value_type( -// // fluid_preset_get_banknum(preset) + bankOffset, -// // *new Preset( -// // fluid_preset_get_num(preset), -// // fluid_preset_get_name(preset) -// // ) -// // )); -// if (bankOffset > greatestPersistedBank) { -// banks.appendChild({ "bank", { -// { "num", bankOffset }, -// }, {} }, nullptr); -// greatestPersistedBank = bankOffset; -// } -// presets.appendChild({ "preset", { -// { "num", fluid_preset_get_num(preset) }, -// { "name", String{fluid_preset_get_name(preset)} } -// }, {} }, nullptr); -// } -// } -// // valueTreeState.state.getChildWithName("banks") = banks; -// // valueTreeState.state.getChildWithName("presets") = presets; -// valueTreeState.state.getChildWithName("banks").copyPropertiesAndChildrenFrom(banks, nullptr); -// valueTreeState.state.getChildWithName("presets").copyPropertiesAndChildrenFrom(presets, nullptr); -// valueTreeState.state.getChildWithName("banks").sendPropertyChangeMessage("synthetic"); -// valueTreeState.state.getChildWithName("presets").sendPropertyChangeMessage("synthetic"); - -// #if JUCE_DEBUG -// unique_ptr xml{valueTreeState.state.createXml()}; -// Logger::outputDebugString(xml->createDocument("",false,false)); -// #endif -// } - -// FluidSynthModel::Listener::~Listener() { -// } - -//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; -//} - -//============================================================================== -// void FluidSynthModel::addListener (FluidSynthModel::Listener* const newListener) -// { -// eventListeners.add(newListener); -// } - -// void FluidSynthModel::removeListener (FluidSynthModel::Listener* const listener) -// { -// eventListeners.remove(listener); -// } - void FluidSynthModel::setSampleRate(float sampleRate) { currentSampleRate = sampleRate; // https://stackoverflow.com/a/40856043/5257399 @@ -765,35 +458,39 @@ void FluidSynthModel::setCurrentProgram(int index) const String FluidSynthModel::getProgramName(int index) { - fluid_sfont_t* sfont{ - sfont_id == -1 - ? nullptr - : fluid_synth_get_sfont_by_id(synth.get(), sfont_id) - }; - if (!sfont) { - return {}; - } - int bank, presetNum; - { - RangedAudioParameter *param {valueTreeState.getParameter("bank")}; - jassert(dynamic_cast (param) != nullptr); - AudioParameterInt* castParam {dynamic_cast (param)}; - bank = castParam->get(); - } - { - RangedAudioParameter *param {valueTreeState.getParameter("preset")}; - jassert(dynamic_cast (param) != nullptr); - AudioParameterInt* castParam {dynamic_cast (param)}; - presetNum = castParam->get(); - } - fluid_preset_t *preset{fluid_sfont_get_preset( - sfont, - bank, - presetNum)}; - if (!preset) { - return {}; - } - return {fluid_preset_get_name(preset)}; + // fluid_sfont_t* sfont{ + // sfont_id == -1 + // ? nullptr + // : fluid_synth_get_sfont_by_id(synth.get(), sfont_id) + // }; + // if (!sfont) { + // return {}; + // } + // int bank, presetNum; + // { + // RangedAudioParameter *param {valueTreeState.getParameter("bank")}; + // jassert(dynamic_cast (param) != nullptr); + // AudioParameterInt* castParam {dynamic_cast (param)}; + // bank = castParam->get(); + // } + // { + // RangedAudioParameter *param {valueTreeState.getParameter("preset")}; + // jassert(dynamic_cast (param) != nullptr); + // AudioParameterInt* castParam {dynamic_cast (param)}; + // presetNum = castParam->get(); + // } + // fluid_preset_t *preset{fluid_sfont_get_preset( + // sfont, + // bank, + // presetNum)}; + // if (!preset) { + // return {}; + // } + // return {fluid_preset_get_name(preset)}; + + // I think the presets' names will be collected only at synth startup, so we won't yet have loaded the soundfont. + String presetName{"Preset "}; + return presetName << index; } void FluidSynthModel::changeProgramName(int index, const String& newName) diff --git a/Source/FluidSynthModel.h b/Source/FluidSynthModel.h index 30440b0..4e844dd 100644 --- a/Source/FluidSynthModel.h +++ b/Source/FluidSynthModel.h @@ -56,7 +56,6 @@ public: void changeProgramName(int index, const String& newName); private: - int handleMidiEvent(void* data, fluid_midi_event_t* event); void refreshBanks(); AudioProcessorValueTreeState& valueTreeState; @@ -66,9 +65,7 @@ private: // http://www.fluidsynth.org/api/ // in their examples, they destroy the synth before destroying the settings unique_ptr settings; - // TODO: shared_ptr may ruin our guarantee of synth's being destroyed first, so consider changing the access we expose - shared_ptr synth; - // unique_ptr midiDriver; + unique_ptr synth; float currentSampleRate; @@ -78,8 +75,6 @@ private: void unloadAndLoadFont(const String &absPath); void loadFont(const String &absPath); - - void changePresetImpl(int bank, int preset); int sfont_id; unsigned int channel;