switch to unique_ptr for fluidsynth

This commit is contained in:
Alex Birch 2019-07-28 23:02:22 +01:00
parent 39f9d86bd1
commit cdf6f89019
No known key found for this signature in database
GPG Key ID: 305EB1F98D44ACBA
2 changed files with 41 additions and 349 deletions

View File

@ -12,20 +12,13 @@ using namespace std;
FluidSynthModel::FluidSynthModel( FluidSynthModel::FluidSynthModel(
AudioProcessorValueTreeState& valueTreeState AudioProcessorValueTreeState& valueTreeState
// ValueTree& valueTree
// SharesParams& sharedParams
) )
: valueTreeState{valueTreeState} : valueTreeState{valueTreeState}
// , valueTree{valueTree}
// , sharedParams{sharedParams}
//, synth{nullptr}
, settings{nullptr, nullptr} , settings{nullptr, nullptr}
//, currentSoundFontAbsPath{} , synth{nullptr, nullptr}
, currentSampleRate{44100} , currentSampleRate{44100}
//, initialised{false}
, sfont_id{-1} , sfont_id{-1}
, channel{0}/*, , channel{0}
mod(nullptr)*/
{ {
valueTreeState.addParameterListener("bank", this); valueTreeState.addParameterListener("bank", this);
valueTreeState.addParameterListener("preset", this); valueTreeState.addParameterListener("preset", this);
@ -36,28 +29,9 @@ FluidSynthModel::~FluidSynthModel() {
valueTreeState.removeParameterListener("bank", this); valueTreeState.removeParameterListener("bank", this);
valueTreeState.removeParameterListener("preset", this); valueTreeState.removeParameterListener("preset", this);
valueTreeState.state.removeListener(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() { void FluidSynthModel::initialise() {
// if (initialised) {
// delete_fluid_synth(synth);
// delete_fluid_settings(settings);
// }
settings = { new_fluid_settings(), delete_fluid_settings }; settings = { new_fluid_settings(), delete_fluid_settings };
// deactivate all audio drivers in fluidsynth to avoid FL Studio deadlock when initialising CoreAudio // 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}; const char *DRV[] {NULL};
fluid_audio_driver_register(DRV); fluid_audio_driver_register(DRV);
// handle_midi_event_func_t handler = [](void* data, fluid_midi_event_t* event) -> int {
//
// };
// midiDriver = unique_ptr<fluid_midi_driver_t, decltype(&delete_fluid_midi_driver)>(
// 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/ // https://sourceforge.net/p/fluidsynth/wiki/FluidSettings/
#if JUCE_DEBUG #if JUCE_DEBUG
fluid_settings_setint(settings.get(), "synth.verbose", 1); fluid_settings_setint(settings.get(), "synth.verbose", 1);
@ -93,10 +53,6 @@ void FluidSynthModel::initialise() {
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)}; // AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// *castParam = m.getControllerValue(); // *castParam = m.getControllerValue();
// if (sharedParams.getSoundFontPath().isNotEmpty()) {
// loadFont(sharedParams.getSoundFontPath());
// changePreset(sharedParams->getBank(), sharedParams->getPreset());
// }
ValueTree soundFont{valueTreeState.state.getChildWithName("soundFont")}; ValueTree soundFont{valueTreeState.state.getChildWithName("soundFont")};
String path{soundFont.getProperty("path", "")}; String path{soundFont.getProperty("path", "")};
loadFont(path); loadFont(path);
@ -202,20 +158,10 @@ void FluidSynthModel::initialise() {
// clamps the range to between 0 and 1000, so we'll copy that // clamps the range to between 0 and 1000, so we'll copy that
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);
// valueTreeState.state.getChildWithName("soundFont").sendPropertyChangeMessage("path");
// valueTree.sendPropertyChangeMessage("soundFontPath");
// initialised = true;
} }
void FluidSynthModel::parameterChanged(const String& parameterID, float newValue) { void FluidSynthModel::parameterChanged(const String& parameterID, float newValue) {
if (parameterID == "bank") { if (parameterID == "bank") {
// RangedAudioParameter *param {valueTreeState.getParameter("bank")};
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// int value{castParam->get()};
int bank, preset; int bank, preset;
{ {
RangedAudioParameter *param {valueTreeState.getParameter("bank")}; RangedAudioParameter *param {valueTreeState.getParameter("bank")};
@ -236,15 +182,6 @@ void FluidSynthModel::parameterChanged(const String& parameterID, float newValue
sfont_id, sfont_id,
static_cast<unsigned int>(bankOffset + bank), static_cast<unsigned int>(bankOffset + bank),
static_cast<unsigned int>(preset)); static_cast<unsigned int>(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") { } else if (parameterID == "preset") {
int bank, preset; int bank, preset;
{ {
@ -272,7 +209,6 @@ void FluidSynthModel::parameterChanged(const String& parameterID, float newValue
void FluidSynthModel::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasChanged, void FluidSynthModel::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasChanged,
const Identifier& property) { const Identifier& property) {
if (treeWhosePropertyHasChanged.getType() == StringRef("soundFont")) { if (treeWhosePropertyHasChanged.getType() == StringRef("soundFont")) {
// if (&treeWhosePropertyHasChanged == &valueTree) {
if (property == StringRef("path")) { if (property == StringRef("path")) {
String soundFontPath{treeWhosePropertyHasChanged.getProperty("path", "")}; String soundFontPath{treeWhosePropertyHasChanged.getProperty("path", "")};
if (soundFontPath.isNotEmpty()) { if (soundFontPath.isNotEmpty()) {
@ -283,117 +219,17 @@ void FluidSynthModel::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasCh
} }
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_synth_cc(
fluid_midi_event_set_type(midi_event, static_cast<int>(CONTROL_CHANGE)); synth.get(),
fluid_midi_event_set_channel(midi_event, channel); channel,
fluid_midi_event_set_control(midi_event, controller); controller,
fluid_midi_event_set_value(midi_event, value); value);
fluid_synth_handle_midi_event(synth.get(), midi_event);
delete_fluid_midi_event(midi_event);
// fluid_channel_set_cc(channel, i, 0);
} }
int FluidSynthModel::getChannel() { int FluidSynthModel::getChannel() {
return channel; return channel;
} }
//void FluidSynthModel::changePreset(int bank, int preset) {
// if (bank == -1 || preset == -1) {
// unique_ptr<BankAndPreset> 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<unsigned int>(bank), static_cast<unsigned int>(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<BankAndPreset> FluidSynthModel::getFirstBankAndPreset() {
// fluid_preset_t* preset = getFirstPreset();
//
// int offset = fluid_synth_get_bank_offset(synth.get(), sfont_id);
//
// return make_unique<BankAndPreset>(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<fluid_synth_t> 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) { void FluidSynthModel::unloadAndLoadFont(const String &absPath) {
// in the base case, there is no font loaded // in the base case, there is no font loaded
if (fluid_synth_sfcount(synth.get()) > 0) { if (fluid_synth_sfcount(synth.get()) > 0) {
@ -406,9 +242,6 @@ void FluidSynthModel::unloadAndLoadFont(const String &absPath) {
} }
void FluidSynthModel::loadFont(const String &absPath) { void FluidSynthModel::loadFont(const String &absPath) {
// currentSoundFontAbsPath = absPath;
// sfont_id++;
// fluid_synth_sfunload(synth.get(), sfont_id, 1);
if (!absPath.isEmpty()) { if (!absPath.isEmpty()) {
sfont_id = fluid_synth_sfload(synth.get(), absPath.toStdString().c_str(), 1); sfont_id = fluid_synth_sfload(synth.get(), absPath.toStdString().c_str(), 1);
// if -1 is returned, that indicates failure // if -1 is returned, that indicates failure
@ -460,146 +293,6 @@ void FluidSynthModel::refreshBanks() {
#endif #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<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (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<XmlElement> 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) { void FluidSynthModel::setSampleRate(float sampleRate) {
currentSampleRate = sampleRate; currentSampleRate = sampleRate;
// https://stackoverflow.com/a/40856043/5257399 // https://stackoverflow.com/a/40856043/5257399
@ -765,35 +458,39 @@ void FluidSynthModel::setCurrentProgram(int index)
const String FluidSynthModel::getProgramName(int index) const String FluidSynthModel::getProgramName(int index)
{ {
fluid_sfont_t* sfont{ // fluid_sfont_t* sfont{
sfont_id == -1 // sfont_id == -1
? nullptr // ? nullptr
: fluid_synth_get_sfont_by_id(synth.get(), sfont_id) // : fluid_synth_get_sfont_by_id(synth.get(), sfont_id)
}; // };
if (!sfont) { // if (!sfont) {
return {}; // return {};
} // }
int bank, presetNum; // int bank, presetNum;
{ // {
RangedAudioParameter *param {valueTreeState.getParameter("bank")}; // RangedAudioParameter *param {valueTreeState.getParameter("bank")};
jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr); // jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)}; // AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
bank = castParam->get(); // bank = castParam->get();
} // }
{ // {
RangedAudioParameter *param {valueTreeState.getParameter("preset")}; // RangedAudioParameter *param {valueTreeState.getParameter("preset")};
jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr); // jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)}; // AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
presetNum = castParam->get(); // presetNum = castParam->get();
} // }
fluid_preset_t *preset{fluid_sfont_get_preset( // fluid_preset_t *preset{fluid_sfont_get_preset(
sfont, // sfont,
bank, // bank,
presetNum)}; // presetNum)};
if (!preset) { // if (!preset) {
return {}; // return {};
} // }
return {fluid_preset_get_name(preset)}; // 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) void FluidSynthModel::changeProgramName(int index, const String& newName)

View File

@ -56,7 +56,6 @@ public:
void changeProgramName(int index, const String& newName); void changeProgramName(int index, const String& newName);
private: private:
int handleMidiEvent(void* data, fluid_midi_event_t* event);
void refreshBanks(); void refreshBanks();
AudioProcessorValueTreeState& valueTreeState; AudioProcessorValueTreeState& valueTreeState;
@ -66,9 +65,7 @@ private:
// http://www.fluidsynth.org/api/ // http://www.fluidsynth.org/api/
// in their examples, they destroy the synth before destroying the settings // 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 unique_ptr<fluid_synth_t, decltype(&delete_fluid_synth)> synth;
shared_ptr<fluid_synth_t> synth;
// unique_ptr<fluid_midi_driver_t, decltype(&delete_fluid_midi_driver)> midiDriver;
float currentSampleRate; float currentSampleRate;
@ -79,8 +76,6 @@ private:
void unloadAndLoadFont(const String &absPath); void unloadAndLoadFont(const String &absPath);
void loadFont(const String &absPath); void loadFont(const String &absPath);
void changePresetImpl(int bank, int preset);
int sfont_id; int sfont_id;
unsigned int channel; unsigned int channel;