prefer references where owner will definitely outlive recipient. replace some fluidsynth raw pointers with smart pointers.

This commit is contained in:
Alex Birch 2019-07-07 00:22:47 +01:00
parent 7582fbcc9e
commit 6d2267e23a
No known key found for this signature in database
GPG Key ID: 305EB1F98D44ACBA
18 changed files with 410 additions and 342 deletions

View File

@ -6,24 +6,26 @@
#include "MyColours.h" #include "MyColours.h"
FilePicker::FilePicker( FilePicker::FilePicker(
FluidSynthModel* fluidSynthModel AudioProcessorValueTreeState& valueTreeState,
FluidSynthModel& fluidSynthModel
) )
: fileChooser( : fileChooser{
"File", "File",
File(), File(),
true, true,
false, false,
false, false,
"*.sf2;*.sf3", "*.sf2;*.sf3",
String(), String(),
"Choose a Soundfont file to load into the synthesizer" "Choose a Soundfont file to load into the synthesizer"}
), , valueTreeState{valueTreeState}
fluidSynthModel(fluidSynthModel), , fluidSynthModel{fluidSynthModel}
currentPath() { // , currentPath{}
{
// faster (rounded edges introduce transparency) // faster (rounded edges introduce transparency)
setOpaque (true); setOpaque (true);
setDisplayedFilePath(fluidSynthModel->getCurrentSoundFontAbsPath()); setDisplayedFilePath(fluidSynthModel.getCurrentSoundFontAbsPath());
addAndMakeVisible (fileChooser); addAndMakeVisible (fileChooser);
fileChooser.addListener (this); fileChooser.addListener (this);
@ -47,7 +49,7 @@ void FilePicker::paint(Graphics& g)
void FilePicker::filenameComponentChanged (FilenameComponent*) { void FilePicker::filenameComponentChanged (FilenameComponent*) {
currentPath = fileChooser.getCurrentFile().getFullPathName(); currentPath = fileChooser.getCurrentFile().getFullPathName();
fluidSynthModel->onFileNameChanged(fileChooser.getCurrentFile().getFullPathName(), -1, -1); fluidSynthModel.onFileNameChanged(fileChooser.getCurrentFile().getFullPathName(), -1, -1);
} }
void FilePicker::setDisplayedFilePath(const String& path) { void FilePicker::setDisplayedFilePath(const String& path) {

View File

@ -14,7 +14,8 @@ class FilePicker: public Component,
{ {
public: public:
FilePicker( FilePicker(
FluidSynthModel* fluidSynthModel AudioProcessorValueTreeState& valueTreeState,
FluidSynthModel& fluidSynthModel
); );
~FilePicker(); ~FilePicker();
@ -25,7 +26,8 @@ public:
private: private:
FilenameComponent fileChooser; FilenameComponent fileChooser;
FluidSynthModel* fluidSynthModel; AudioProcessorValueTreeState& valueTreeState;
FluidSynthModel& fluidSynthModel;
String currentPath; String currentPath;

View File

@ -3,33 +3,46 @@
// //
#include <iostream> #include <iostream>
#include <fluidsynth.h>
#include "FluidSynthModel.h" #include "FluidSynthModel.h"
#include "MidiConstants.h" #include "MidiConstants.h"
#include "Util.h"
using namespace std; using namespace std;
FluidSynthModel::FluidSynthModel(shared_ptr<SharesParams> sharedParams) FluidSynthModel::FluidSynthModel(
: sharedParams{sharedParams}, AudioProcessorValueTreeState& valueTreeState,
synth{nullptr}, SharesParams& sharedParams
settings{nullptr}, )
currentSoundFontAbsPath{}, : valueTreeState{valueTreeState}
currentSampleRate{44100}, , sharedParams{sharedParams}
initialised{false}, //, synth{nullptr}
sfont_id{0}, , settings{nullptr, nullptr}
channel{0}/*, , currentSoundFontAbsPath{}
mod(nullptr)*/ , currentSampleRate{44100}
, initialised{false}
, sfont_id{0}
, channel{0}/*,
mod(nullptr)*/
{} {}
FluidSynthModel::~FluidSynthModel() { // FluidSynthModel::~FluidSynthModel() {
if (initialised) { // if (initialised) {
// delete_fluid_audio_driver(driver); // delete_fluid_audio_driver(driver);
delete_fluid_synth(synth); // delete_fluid_synth(synth);
delete_fluid_settings(settings); // delete_fluid_settings(settings);
// delete driver; // delete driver;
// delete settings; // delete settings;
// delete_fluid_mod(mod); // 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() {
@ -37,26 +50,47 @@ void FluidSynthModel::initialise() {
// delete_fluid_synth(synth); // delete_fluid_synth(synth);
// delete_fluid_settings(settings); // 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 // deactivate all audio drivers in fluidsynth to avoid FL Studio deadlock when initialising CoreAudio
// after all: we only use fluidsynth to render blocks of audio. it doesn't output to audio driver. // after all: we only use fluidsynth to render blocks of audio. it doesn't output to audio driver.
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);
settings = new_fluid_settings();
// https://sourceforge.net/p/fluidsynth/wiki/FluidSettings/ // https://sourceforge.net/p/fluidsynth/wiki/FluidSettings/
#if JUCE_DEBUG #if JUCE_DEBUG
fluid_settings_setint(settings, "synth.verbose", 1); fluid_settings_setint(settings.get(), "synth.verbose", 1);
#endif #endif
synth = new_fluid_synth(settings); synth = { new_fluid_synth(settings.get()), delete_fluid_synth };
fluid_synth_set_sample_rate(synth, currentSampleRate); fluid_synth_set_sample_rate(synth.get(), currentSampleRate);
if (sharedParams->getSoundFontPath().isNotEmpty()) { valueTreeState.getParameter("soundFontPath")->getValue();
loadFont(sharedParams->getSoundFontPath()); // RangedAudioParameter *param {valueTreeState.getParameter("release")};
changePreset(sharedParams->getBank(), sharedParams->getPreset()); // jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// *castParam = m.getControllerValue();
if (sharedParams.getSoundFontPath().isNotEmpty()) {
loadFont(sharedParams.getSoundFontPath());
// changePreset(sharedParams->getBank(), sharedParams->getPreset());
} }
fluid_synth_set_gain(synth, 2.0); fluid_synth_set_gain(synth.get(), 2.0);
for(int i{SOUND_CTRL1}; i <= SOUND_CTRL10; i++) for(int i{SOUND_CTRL1}; i <= SOUND_CTRL10; i++)
{ {
@ -81,90 +115,84 @@ void FluidSynthModel::initialise() {
// all SOUND_CTRL are inited with value of 64, not zero. // all SOUND_CTRL are inited with value of 64, not zero.
// "Just like panning, a value of 64 indicates no change for sound ctrls" // "Just like panning, a value of 64 indicates no change for sound ctrls"
fluid_mod_t *mod(new_fluid_mod()); unique_ptr<fluid_mod_t, decltype(&delete_fluid_mod)> mod{new_fluid_mod(), delete_fluid_mod};
// //
fluid_mod_set_source1(mod, fluid_mod_set_source1(mod.get(),
static_cast<int>(SOUND_CTRL2), // MIDI CC 71 Timbre/Harmonic Intensity (filter resonance) static_cast<int>(SOUND_CTRL2), // MIDI CC 71 Timbre/Harmonic Intensity (filter resonance)
FLUID_MOD_CC FLUID_MOD_CC
| FLUID_MOD_UNIPOLAR | FLUID_MOD_UNIPOLAR
| FLUID_MOD_CONCAVE | FLUID_MOD_CONCAVE
| FLUID_MOD_POSITIVE); | FLUID_MOD_POSITIVE);
fluid_mod_set_source2(mod, 0, 0); fluid_mod_set_source2(mod.get(), 0, 0);
fluid_mod_set_dest(mod, GEN_FILTERQ); fluid_mod_set_dest(mod.get(), GEN_FILTERQ);
fluid_mod_set_amount(mod, FLUID_PEAK_ATTENUATION); fluid_mod_set_amount(mod.get(), FLUID_PEAK_ATTENUATION);
fluid_synth_add_default_mod(synth, mod, FLUID_SYNTH_ADD); fluid_synth_add_default_mod(synth.get(), mod.get(), FLUID_SYNTH_ADD);
delete_fluid_mod(mod);
mod = new_fluid_mod(); mod = {new_fluid_mod(), delete_fluid_mod};
fluid_mod_set_source1(mod, fluid_mod_set_source1(mod.get(),
static_cast<int>(SOUND_CTRL3), // MIDI CC 72 Release time static_cast<int>(SOUND_CTRL3), // MIDI CC 72 Release time
FLUID_MOD_CC FLUID_MOD_CC
| FLUID_MOD_UNIPOLAR | FLUID_MOD_UNIPOLAR
| FLUID_MOD_LINEAR | FLUID_MOD_LINEAR
| FLUID_MOD_POSITIVE); | FLUID_MOD_POSITIVE);
fluid_mod_set_source2(mod, 0, 0); fluid_mod_set_source2(mod.get(), 0, 0);
fluid_mod_set_dest(mod, GEN_VOLENVRELEASE); fluid_mod_set_dest(mod.get(), GEN_VOLENVRELEASE);
// fluid_mod_set_amount(mod, 15200.0f); // fluid_mod_set_amount(mod.get(), 15200.0f);
fluid_mod_set_amount(mod, env_amount); fluid_mod_set_amount(mod.get(), env_amount);
fluid_synth_add_default_mod(synth, mod, FLUID_SYNTH_ADD); fluid_synth_add_default_mod(synth.get(), mod.get(), FLUID_SYNTH_ADD);
delete_fluid_mod(mod);
mod = new_fluid_mod(); mod = {new_fluid_mod(), delete_fluid_mod};
fluid_mod_set_source1(mod, fluid_mod_set_source1(mod.get(),
static_cast<int>(SOUND_CTRL4), // MIDI CC 73 Attack time static_cast<int>(SOUND_CTRL4), // MIDI CC 73 Attack time
FLUID_MOD_CC FLUID_MOD_CC
| FLUID_MOD_UNIPOLAR | FLUID_MOD_UNIPOLAR
| FLUID_MOD_LINEAR | FLUID_MOD_LINEAR
| FLUID_MOD_POSITIVE); | FLUID_MOD_POSITIVE);
fluid_mod_set_source2(mod, 0, 0); fluid_mod_set_source2(mod.get(), 0, 0);
fluid_mod_set_dest(mod, GEN_VOLENVATTACK); fluid_mod_set_dest(mod.get(), GEN_VOLENVATTACK);
fluid_mod_set_amount(mod, env_amount); fluid_mod_set_amount(mod.get(), env_amount);
fluid_synth_add_default_mod(synth, mod, FLUID_SYNTH_ADD); fluid_synth_add_default_mod(synth.get(), mod.get(), FLUID_SYNTH_ADD);
delete_fluid_mod(mod);
// soundfont spec says that if cutoff is >20kHz and resonance Q is 0, then no filtering occurs // soundfont spec says that if cutoff is >20kHz and resonance Q is 0, then no filtering occurs
mod = new_fluid_mod(); mod = {new_fluid_mod(), delete_fluid_mod};
fluid_mod_set_source1(mod, fluid_mod_set_source1(mod.get(),
static_cast<int>(SOUND_CTRL5), // MIDI CC 74 Brightness (cutoff frequency, FILTERFC) static_cast<int>(SOUND_CTRL5), // MIDI CC 74 Brightness (cutoff frequency, FILTERFC)
FLUID_MOD_CC FLUID_MOD_CC
| FLUID_MOD_LINEAR | FLUID_MOD_LINEAR
| FLUID_MOD_UNIPOLAR | FLUID_MOD_UNIPOLAR
| FLUID_MOD_POSITIVE); | FLUID_MOD_POSITIVE);
fluid_mod_set_source2(mod, 0, 0); fluid_mod_set_source2(mod.get(), 0, 0);
fluid_mod_set_dest(mod, GEN_FILTERFC); fluid_mod_set_dest(mod.get(), GEN_FILTERFC);
fluid_mod_set_amount(mod, -2400.0f); fluid_mod_set_amount(mod.get(), -2400.0f);
fluid_synth_add_default_mod(synth, mod, FLUID_SYNTH_ADD); fluid_synth_add_default_mod(synth.get(), mod.get(), FLUID_SYNTH_ADD);
delete_fluid_mod(mod);
mod = new_fluid_mod(); mod = {new_fluid_mod(), delete_fluid_mod};
fluid_mod_set_source1(mod, fluid_mod_set_source1(mod.get(),
static_cast<int>(SOUND_CTRL6), // MIDI CC 75 Decay Time static_cast<int>(SOUND_CTRL6), // MIDI CC 75 Decay Time
FLUID_MOD_CC FLUID_MOD_CC
| FLUID_MOD_UNIPOLAR | FLUID_MOD_UNIPOLAR
| FLUID_MOD_LINEAR | FLUID_MOD_LINEAR
| FLUID_MOD_POSITIVE); | FLUID_MOD_POSITIVE);
fluid_mod_set_source2(mod, 0, 0); fluid_mod_set_source2(mod.get(), 0, 0);
fluid_mod_set_dest(mod, GEN_VOLENVDECAY); fluid_mod_set_dest(mod.get(), GEN_VOLENVDECAY);
fluid_mod_set_amount(mod, env_amount); fluid_mod_set_amount(mod.get(), env_amount);
fluid_synth_add_default_mod(synth, mod, FLUID_SYNTH_ADD); fluid_synth_add_default_mod(synth.get(), mod.get(), FLUID_SYNTH_ADD);
delete_fluid_mod(mod);
mod = new_fluid_mod(); mod = {new_fluid_mod(), delete_fluid_mod};
fluid_mod_set_source1(mod, fluid_mod_set_source1(mod.get(),
static_cast<int>(SOUND_CTRL10), // MIDI CC 79 undefined static_cast<int>(SOUND_CTRL10), // MIDI CC 79 undefined
FLUID_MOD_CC FLUID_MOD_CC
| FLUID_MOD_UNIPOLAR | FLUID_MOD_UNIPOLAR
| FLUID_MOD_CONCAVE | FLUID_MOD_CONCAVE
| FLUID_MOD_POSITIVE); | FLUID_MOD_POSITIVE);
fluid_mod_set_source2(mod, 0, 0); fluid_mod_set_source2(mod.get(), 0, 0);
fluid_mod_set_dest(mod, GEN_VOLENVSUSTAIN); fluid_mod_set_dest(mod.get(), GEN_VOLENVSUSTAIN);
// fluice_voice.c#fluid_voice_update_param() // fluice_voice.c#fluid_voice_update_param()
// 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, 1000.0f); fluid_mod_set_amount(mod.get(), 1000.0f);
fluid_synth_add_default_mod(synth, mod, FLUID_SYNTH_ADD); fluid_synth_add_default_mod(synth.get(), mod.get(), FLUID_SYNTH_ADD);
delete_fluid_mod(mod);
initialised = true; // initialised = true;
} }
void FluidSynthModel::setControllerValue(int controller, int value) { void FluidSynthModel::setControllerValue(int controller, int value) {
@ -173,7 +201,7 @@ void FluidSynthModel::setControllerValue(int controller, int value) {
fluid_midi_event_set_channel(midi_event, channel); fluid_midi_event_set_channel(midi_event, channel);
fluid_midi_event_set_control(midi_event, controller); fluid_midi_event_set_control(midi_event, controller);
fluid_midi_event_set_value(midi_event, value); fluid_midi_event_set_value(midi_event, value);
fluid_synth_handle_midi_event(synth, midi_event); fluid_synth_handle_midi_event(synth.get(), midi_event);
delete_fluid_midi_event(midi_event); delete_fluid_midi_event(midi_event);
// fluid_channel_set_cc(channel, i, 0); // fluid_channel_set_cc(channel, i, 0);
} }
@ -189,16 +217,16 @@ void FluidSynthModel::changePreset(int bank, int preset) {
preset = bankAndPreset->getPreset(); preset = bankAndPreset->getPreset();
} }
changePresetImpl(bank, preset); changePresetImpl(bank, preset);
sharedParams->setPreset(preset); // sharedParams->setPreset(preset);
sharedParams->setBank(bank); // sharedParams->setBank(bank);
} }
void FluidSynthModel::changePresetImpl(int bank, int preset) { void FluidSynthModel::changePresetImpl(int bank, int preset) {
fluid_synth_program_select(synth, channel, sfont_id, static_cast<unsigned int>(bank), static_cast<unsigned 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_preset_t* FluidSynthModel::getFirstPreset() {
fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(synth, sfont_id); fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(synth.get(), sfont_id);
jassert(sfont != nullptr); jassert(sfont != nullptr);
fluid_sfont_iteration_start(sfont); fluid_sfont_iteration_start(sfont);
@ -209,7 +237,7 @@ fluid_preset_t* FluidSynthModel::getFirstPreset() {
unique_ptr<BankAndPreset> FluidSynthModel::getFirstBankAndPreset() { unique_ptr<BankAndPreset> FluidSynthModel::getFirstBankAndPreset() {
fluid_preset_t* preset = getFirstPreset(); fluid_preset_t* preset = getFirstPreset();
int offset = fluid_synth_get_bank_offset(synth, sfont_id); 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)); return make_unique<BankAndPreset>(fluid_preset_get_banknum(preset) + offset, fluid_preset_get_num(preset));
}; };
@ -217,7 +245,7 @@ unique_ptr<BankAndPreset> FluidSynthModel::getFirstBankAndPreset() {
void FluidSynthModel::selectFirstPreset() { void FluidSynthModel::selectFirstPreset() {
fluid_preset_t* preset = getFirstPreset(); fluid_preset_t* preset = getFirstPreset();
int offset = fluid_synth_get_bank_offset(synth, sfont_id); int offset = fluid_synth_get_bank_offset(synth.get(), sfont_id);
changePreset(fluid_preset_get_banknum(preset) + offset, fluid_preset_get_num(preset)); changePreset(fluid_preset_get_banknum(preset) + offset, fluid_preset_get_num(preset));
} }
@ -225,14 +253,14 @@ void FluidSynthModel::selectFirstPreset() {
BanksToPresets FluidSynthModel::getBanks() { BanksToPresets FluidSynthModel::getBanks() {
BanksToPresets banksToPresets; BanksToPresets banksToPresets;
int soundfontCount = fluid_synth_sfcount(synth); int soundfontCount = fluid_synth_sfcount(synth.get());
if (soundfontCount == 0) { if (soundfontCount == 0) {
// no soundfont selected // no soundfont selected
return banksToPresets; return banksToPresets;
} }
fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(synth, sfont_id); fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(synth.get(), sfont_id);
if(sfont == nullptr) { if(sfont == nullptr) {
// no soundfont found by that ID // no soundfont found by that ID
// the above guard (soundfontCount) protects us for the // the above guard (soundfontCount) protects us for the
@ -240,7 +268,7 @@ BanksToPresets FluidSynthModel::getBanks() {
return banksToPresets; return banksToPresets;
} }
int offset = fluid_synth_get_bank_offset(synth, sfont_id); int offset = fluid_synth_get_bank_offset(synth.get(), sfont_id);
fluid_sfont_iteration_start(sfont); fluid_sfont_iteration_start(sfont);
@ -259,7 +287,7 @@ BanksToPresets FluidSynthModel::getBanks() {
return banksToPresets; return banksToPresets;
} }
fluid_synth_t* FluidSynthModel::getSynth() { shared_ptr<fluid_synth_t> FluidSynthModel::getSynth() {
// https://msdn.microsoft.com/en-us/library/hh279669.aspx // https://msdn.microsoft.com/en-us/library/hh279669.aspx
// You can pass a shared_ptr to another function in the following ways: // 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. // Pass the shared_ptr by value. This invokes the copy constructor, increments the reference count, and makes the callee an owner.
@ -272,14 +300,14 @@ void FluidSynthModel::onFileNameChanged(const String &absPath, int bank, int pre
} }
unloadAndLoadFont(absPath); unloadAndLoadFont(absPath);
changePreset(bank, preset); changePreset(bank, preset);
sharedParams->setSoundFontPath(absPath); sharedParams.setSoundFontPath(absPath);
eventListeners.call(&FluidSynthModel::Listener::fontChanged, this, 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) > 0) { if (fluid_synth_sfcount(synth.get()) > 0) {
fluid_synth_sfunload(synth, sfont_id, 1); fluid_synth_sfunload(synth.get(), sfont_id, 1);
} }
loadFont(absPath); loadFont(absPath);
} }
@ -287,7 +315,7 @@ void FluidSynthModel::unloadAndLoadFont(const String &absPath) {
void FluidSynthModel::loadFont(const String &absPath) { void FluidSynthModel::loadFont(const String &absPath) {
currentSoundFontAbsPath = absPath; currentSoundFontAbsPath = absPath;
sfont_id++; sfont_id++;
fluid_synth_sfload(synth, absPath.toStdString().c_str(), 1); fluid_synth_sfload(synth.get(), absPath.toStdString().c_str(), 1);
} }
FluidSynthModel::Listener::~Listener() { FluidSynthModel::Listener::~Listener() {
@ -323,9 +351,11 @@ void FluidSynthModel::removeListener (FluidSynthModel::Listener* const listener)
void FluidSynthModel::setSampleRate(float sampleRate) { void FluidSynthModel::setSampleRate(float sampleRate) {
currentSampleRate = sampleRate; currentSampleRate = sampleRate;
if (!initialised) { // https://stackoverflow.com/a/40856043/5257399
// test if a smart pointer is null
if (!synth) {
// don't worry; we'll do this in initialise phase regardless // don't worry; we'll do this in initialise phase regardless
return; return;
} }
fluid_synth_set_sample_rate(synth, sampleRate); fluid_synth_set_sample_rate(synth.get(), sampleRate);
} }

View File

@ -19,10 +19,13 @@ using namespace std;
class FluidSynthModel { class FluidSynthModel {
public: public:
FluidSynthModel(shared_ptr<SharesParams> sharedParams); FluidSynthModel(
~FluidSynthModel(); AudioProcessorValueTreeState& valueTreeState,
SharesParams& sharedParams
);
// ~FluidSynthModel();
fluid_synth_t* getSynth(); shared_ptr<fluid_synth_t> getSynth();
void initialise(); void initialise();
BanksToPresets getBanks(); BanksToPresets getBanks();
@ -65,11 +68,14 @@ public:
const String& getCurrentSoundFontAbsPath(); const String& getCurrentSoundFontAbsPath();
private: private:
shared_ptr<SharesParams> sharedParams; int handleMidiEvent(void* data, fluid_midi_event_t* event);
fluid_synth_t* synth; AudioProcessorValueTreeState& valueTreeState;
fluid_settings_t* settings; SharesParams& sharedParams;
// fluid_audio_driver_t* driver;
shared_ptr<fluid_synth_t> synth;
unique_ptr<fluid_settings_t, decltype(&delete_fluid_settings)> settings;
// unique_ptr<fluid_midi_driver_t, decltype(&delete_fluid_midi_driver)> midiDriver;
String currentSoundFontAbsPath; String currentSoundFontAbsPath;

View File

@ -14,73 +14,73 @@
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}
decay{0}, // , decay{0}
sustain{0}, // , sustain{0}
release{0}, // , release{0}
filterCutOff{0}, // , filterCutOff{0}
filterResonance{0} // .filterResonance{0}
{ {
} }
void Params::setAttributesOnXml(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);
xml.setAttribute("attack", attack); // xml.setAttribute("attack", attack);
xml.setAttribute("decay", decay); // xml.setAttribute("decay", decay);
xml.setAttribute("sustain", sustain); // xml.setAttribute("sustain", sustain);
xml.setAttribute("release", release); // xml.setAttribute("release", release);
xml.setAttribute("filterCutOff", filterCutOff); // xml.setAttribute("filterCutOff", filterCutOff);
xml.setAttribute("filterResonance", filterResonance); // xml.setAttribute("filterResonance", filterResonance);
} }
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);
attack = jmin(jmax(xmlState->getIntAttribute("attack", attack), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); // attack = jmin(jmax(xmlState->getIntAttribute("attack", attack), MidiConstants::midiMinValue), MidiConstants::midiMaxValue);
decay = jmin(jmax(xmlState->getIntAttribute("decay", decay), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); // decay = jmin(jmax(xmlState->getIntAttribute("decay", decay), MidiConstants::midiMinValue), MidiConstants::midiMaxValue);
sustain = jmin(jmax(xmlState->getIntAttribute("sustain", sustain), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); // sustain = jmin(jmax(xmlState->getIntAttribute("sustain", sustain), MidiConstants::midiMinValue), MidiConstants::midiMaxValue);
release = jmin(jmax(xmlState->getIntAttribute("release", release), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); // release = jmin(jmax(xmlState->getIntAttribute("release", release), MidiConstants::midiMinValue), MidiConstants::midiMaxValue);
filterCutOff = jmin(jmax(xmlState->getIntAttribute("filterCutOff", filterCutOff), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); // filterCutOff = jmin(jmax(xmlState->getIntAttribute("filterCutOff", filterCutOff), MidiConstants::midiMinValue), MidiConstants::midiMaxValue);
filterResonance = jmin(jmax(xmlState->getIntAttribute("filterResonance", filterResonance), MidiConstants::midiMinValue), MidiConstants::midiMaxValue); // filterResonance = jmin(jmax(xmlState->getIntAttribute("filterResonance", filterResonance), MidiConstants::midiMinValue), MidiConstants::midiMaxValue);
} }
void Params::acceptMidiControlEvent(int controller, int value) { //void Params::acceptMidiControlEvent(int controller, int value) {
switch(static_cast<fluid_midi_control_change>(controller)) { // switch(static_cast<fluid_midi_control_change>(controller)) {
case SOUND_CTRL2: // MIDI CC 71 Timbre/Harmonic Intensity (filter resonance) // case SOUND_CTRL2: // MIDI CC 71 Timbre/Harmonic Intensity (filter resonance)
filterResonance = value; // filterResonance = value;
break; // break;
case SOUND_CTRL3: // MIDI CC 72 Release time // case SOUND_CTRL3: // MIDI CC 72 Release time
release = value; // release = value;
break; // break;
case SOUND_CTRL4: // MIDI CC 73 Attack time // case SOUND_CTRL4: // MIDI CC 73 Attack time
attack = value; // attack = value;
break; // break;
case SOUND_CTRL5: // MIDI CC 74 Brightness (cutoff frequency, FILTERFC) // case SOUND_CTRL5: // MIDI CC 74 Brightness (cutoff frequency, FILTERFC)
filterCutOff = value; // filterCutOff = value;
break; // break;
case SOUND_CTRL6: // MIDI CC 75 Decay Time // case SOUND_CTRL6: // MIDI CC 75 Decay Time
decay = value; // decay = value;
break; // break;
case SOUND_CTRL10: // MIDI CC 79 undefined // case SOUND_CTRL10: // MIDI CC 79 undefined
sustain = value; // sustain = value;
break; // break;
default: // default:
break; // break;
} // }
} //}
void Params::setSoundFontPath(const String& value) { void Params::setSoundFontPath(const String& value) {
soundFontPath = value; soundFontPath = value;
@ -89,64 +89,64 @@ void Params::setSoundFontPath(const String& value) {
String& Params::getSoundFontPath() { String& Params::getSoundFontPath() {
return soundFontPath; return soundFontPath;
} }
int Params::getPreset() { //int Params::getPreset() {
return preset; // return preset;
} //}
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;
} //}
int Params::getDecay() { //int Params::getDecay() {
return decay; // return decay;
} //}
int Params::getSustain() { //int Params::getSustain() {
return sustain; // return sustain;
} //}
int Params::getRelease() { //int Params::getRelease() {
return release; // return release;
} //}
int Params::getFilterCutOff() { //int Params::getFilterCutOff() {
return filterCutOff; // return filterCutOff;
} //}
int Params::getFilterResonance() { //int Params::getFilterResonance() {
return filterResonance; // return filterResonance;
} //}
void Params::setPreset(int value) { //void Params::setPreset(int value) {
preset = value; // preset = value;
} //}
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;
} //}
void Params::setDecay(int value) { //void Params::setDecay(int value) {
decay = value; // decay = value;
} //}
void Params::setSustain(int value) { //void Params::setSustain(int value) {
sustain = value; // sustain = value;
} //}
void Params::setRelease(int value) { //void Params::setRelease(int value) {
release = value; // release = value;
} //}
void Params::setFilterCutOff(int value) { //void Params::setFilterCutOff(int value) {
filterCutOff = value; // filterCutOff = value;
} //}
void Params::setFilterResonance(int value) { //void Params::setFilterResonance(int value) {
filterResonance = value; // filterResonance = value;
} //}

View File

@ -9,51 +9,51 @@ class Params: public SharesParams {
public: public:
Params() noexcept; Params() noexcept;
virtual void setAttributesOnXml(XmlElement& xml) override; virtual void setAttributesOnXml(shared_ptr<XmlElement> xml) override;
virtual void loadAttributesFromXml(shared_ptr<XmlElement> xmlState) override; virtual void loadAttributesFromXml(shared_ptr<XmlElement> xmlState) override;
virtual void acceptMidiControlEvent(int controller, int value) override; // virtual void acceptMidiControlEvent(int controller, int value) override;
virtual void setSoundFontPath(const String& value) override; virtual void setSoundFontPath(const String& value) override;
virtual String& getSoundFontPath() override; virtual String& getSoundFontPath() override;
virtual int getPreset() override; // virtual int getPreset() override;
virtual void setPreset(int value) override; // virtual void setPreset(int value) override;
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;
virtual int getDecay() override; // virtual int getDecay() override;
virtual void setDecay(int value) override; // virtual void setDecay(int value) override;
virtual int getSustain() override; // virtual int getSustain() override;
virtual void setSustain(int value) override; // virtual void setSustain(int value) override;
virtual int getRelease() override; // virtual int getRelease() override;
virtual void setRelease(int value) override; // virtual void setRelease(int value) override;
virtual int getFilterCutOff() override; // virtual int getFilterCutOff() override;
virtual void setFilterCutOff(int value) override; // virtual void setFilterCutOff(int value) override;
virtual int getFilterResonance() override; // virtual int getFilterResonance() override;
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;
int bank; // int bank;
int attack; // int attack;
int decay; // int decay;
int sustain; // int sustain;
int release; // int release;
int filterCutOff; // int filterCutOff;
int filterResonance; // int filterResonance;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Params) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Params)
}; };

View File

@ -17,11 +17,11 @@ JuicySFAudioProcessorEditor::JuicySFAudioProcessorEditor(JuicySFAudioProcessor&
: AudioProcessorEditor{&p}, : AudioProcessorEditor{&p},
processor{p}, processor{p},
valueTreeState{valueTreeState}, valueTreeState{valueTreeState},
sharedParams{p.sharedParams}, sharedParams{p.getSharedParams()},
midiKeyboard{p.keyboardState, SurjectiveMidiKeyboardComponent::horizontalKeyboard}, midiKeyboard{p.keyboardState, SurjectiveMidiKeyboardComponent::horizontalKeyboard},
tablesComponent{p.getFluidSynthModel()}, tablesComponent{valueTreeState, p.getFluidSynthModel()},
filePicker{p.getFluidSynthModel()}, filePicker{valueTreeState, p.getFluidSynthModel()},
slidersComponent{p.sharedParams, valueTreeState, p.getFluidSynthModel()} slidersComponent{p.getSharedParams(), valueTreeState, p.getFluidSynthModel()}
{ {
// set resize limits for this plug-in // set resize limits for this plug-in
setResizeLimits( setResizeLimits(
@ -30,7 +30,7 @@ JuicySFAudioProcessorEditor::JuicySFAudioProcessorEditor(JuicySFAudioProcessor&
GuiConstants::maxWidth, GuiConstants::maxWidth,
GuiConstants::maxHeight); GuiConstants::maxHeight);
setSize(sharedParams->getUiWidth(), sharedParams->getUiHeight()); setSize(sharedParams.getUiWidth(), sharedParams.getUiHeight());
// processor.subscribeToStateChanges(this); // processor.subscribeToStateChanges(this);
@ -104,8 +104,8 @@ void JuicySFAudioProcessorEditor::resized()
tablesComponent.setBounds(rContent); tablesComponent.setBounds(rContent);
sharedParams->setUiWidth(getWidth()); sharedParams.setUiWidth(getWidth());
sharedParams->setUiHeight(getHeight()); sharedParams.setUiHeight(getHeight());
// Rectangle<int> r2 (getLocalBounds()); // Rectangle<int> r2 (getLocalBounds());
// r2.reduce(0, padding); // r2.reduce(0, padding);

View File

@ -28,7 +28,10 @@ class JuicySFAudioProcessorEditor : public AudioProcessorEditor,
public StateChangeSubscriber*/ public StateChangeSubscriber*/
{ {
public: public:
JuicySFAudioProcessorEditor (JuicySFAudioProcessor&, AudioProcessorValueTreeState& state); JuicySFAudioProcessorEditor(
JuicySFAudioProcessor&,
AudioProcessorValueTreeState& state
);
~JuicySFAudioProcessorEditor(); ~JuicySFAudioProcessorEditor();
//============================================================================== //==============================================================================
@ -50,7 +53,7 @@ private:
JuicySFAudioProcessor& processor; JuicySFAudioProcessor& processor;
AudioProcessorValueTreeState& valueTreeState; AudioProcessorValueTreeState& valueTreeState;
shared_ptr<SharesParams> sharedParams; SharesParams& sharedParams;
SurjectiveMidiKeyboardComponent midiKeyboard; SurjectiveMidiKeyboardComponent midiKeyboard;
TablesComponent tablesComponent; TablesComponent tablesComponent;

View File

@ -26,14 +26,16 @@ AudioProcessor* JUCE_CALLTYPE createPluginFilter();
//============================================================================== //==============================================================================
//, sharedParams{static_pointer_cast<SharesParams>(make_shared<Params>())}
JuicySFAudioProcessor::JuicySFAudioProcessor() JuicySFAudioProcessor::JuicySFAudioProcessor()
: AudioProcessor{getBusesProperties()} : AudioProcessor{getBusesProperties()}
, sharedParams{static_pointer_cast<SharesParams>(make_shared<Params>())} , sharedParams{}
, valueTreeState{*this, nullptr, , valueTreeState{
{ "PARAMETERS" /* MYPLUGINSETTINGS */ }, *this,
createParameterLayout() nullptr,
} { "MYPLUGINSETTINGS" },
, fluidSynthModel{sharedParams} createParameterLayout()}
, fluidSynthModel{valueTreeState, sharedParams}
//, fluidSynthModel{*this} //, fluidSynthModel{*this}
//, pluginEditor(nullptr) //, pluginEditor(nullptr)
{ {
@ -45,9 +47,15 @@ AudioProcessorValueTreeState::ParameterLayout JuicySFAudioProcessor::createParam
// for (int i = 1; i < 9; ++i) // for (int i = 1; i < 9; ++i)
// params.push_back (std::make_unique<AudioParameterInt> (String (i), String (i), 0, i, 0)); // params.push_back (std::make_unique<AudioParameterInt> (String (i), String (i), 0, i, 0));
// make_unique<AudioParameter>("soundfontPath", "filepath to soundfont", 0, 127, 0, "A" ),
// 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" ),
// 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>("attack", "volume envelope attack time", 0, 127, 0, "A" ), make_unique<AudioParameterInt>("attack", "volume envelope attack time", 0, 127, 0, "A" ),
make_unique<AudioParameterInt>("decay", "volume envelope sustain attentuation", 0, 127, 0, "D" ), make_unique<AudioParameterInt>("decay", "volume envelope sustain attentuation", 0, 127, 0, "D" ),
make_unique<AudioParameterInt>("sustain", "volume envelope decay time", 0, 127, 0, "S" ), make_unique<AudioParameterInt>("sustain", "volume envelope decay time", 0, 127, 0, "S" ),
@ -70,7 +78,7 @@ JuicySFAudioProcessor::~JuicySFAudioProcessor()
void JuicySFAudioProcessor::initialiseSynth() { void JuicySFAudioProcessor::initialiseSynth() {
fluidSynthModel.initialise(); fluidSynthModel.initialise();
fluidSynth = fluidSynthModel.getSynth(); // fluidSynth = fluidSynthModel.getSynth();
const int numVoices = 8; const int numVoices = 8;
@ -352,8 +360,11 @@ void JuicySFAudioProcessor::getStateInformation (MemoryBlock& destData)
// as intermediaries to make it easy to save and load complex data. // as intermediaries to make it easy to save and load complex data.
// Create an outer XML element.. // Create an outer XML element..
XmlElement xml{"MYPLUGINSETTINGS"}; // XmlElement xml{"MYPLUGINSETTINGS"};
sharedParams->setAttributesOnXml(xml); // sharedParams->setAttributesOnXml(xml);
auto state{valueTreeState.copyState()};
shared_ptr<XmlElement> xml{state.createXml()};
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++) {
@ -361,12 +372,12 @@ void JuicySFAudioProcessor::getStateInformation (MemoryBlock& destData)
// } // }
// Store the values of all our parameters, using their param ID as the XML attribute // Store the values of all our parameters, using their param ID as the XML attribute
for (auto* param : getParameters()) // for (auto* param : getParameters())
if (auto* p = dynamic_cast<AudioProcessorParameterWithID*> (param)) // if (auto* p = dynamic_cast<AudioProcessorParameterWithID*> (param))
xml.setAttribute (p->paramID, p->getValue()); // xml->setAttribute (p->paramID, p->getValue());
// then use this helper function to stuff it into the binary blob and return it.. // then use this helper function to stuff it into the binary blob and return it..
copyXmlToBinary (xml, destData); copyXmlToBinary (*xml, destData);
} }
void JuicySFAudioProcessor::setStateInformation (const void* data, int sizeInBytes) void JuicySFAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
@ -375,40 +386,42 @@ void JuicySFAudioProcessor::setStateInformation (const void* data, int sizeInByt
// whose contents will have been created by the getStateInformation() call. // whose contents will have been created by the getStateInformation() call.
// This getXmlFromBinary() helper function retrieves our XML from the binary blob.. // This getXmlFromBinary() helper function retrieves our XML from the binary blob..
shared_ptr<XmlElement> xmlState{getXmlFromBinary(data, sizeInBytes)}; shared_ptr<XmlElement> xmlState{getXmlFromBinary(data, sizeInBytes)};
// unique_ptr<XmlElement> xmlState{getXmlFromBinary(data, sizeInBytes)};
if (xmlState != nullptr) if (xmlState.get() != nullptr) {
{
// make sure that it's actually our type of XML object.. // make sure that it's actually our type of XML object..
if (xmlState->hasTagName ("MYPLUGINSETTINGS")) // if (xmlState->hasTagName ("MYPLUGINSETTINGS")) {
{ if (xmlState->hasTagName(valueTreeState.state.getType())) {
valueTreeState.replaceState(ValueTree::fromXml(*xmlState));
// list<StateChangeSubscriber*>::iterator p; // list<StateChangeSubscriber*>::iterator p;
// for(p = stateChangeSubscribers.begin(); p != stateChangeSubscribers.end(); p++) { // for(p = stateChangeSubscribers.begin(); p != stateChangeSubscribers.end(); p++) {
// (*p)->setStateInformation(xmlState); // (*p)->setStateInformation(xmlState);
// } // }
// 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..
for (auto* param : getParameters())
if (auto* p = dynamic_cast<AudioProcessorParameterWithID*> (param)) // for (auto* param : getParameters())
p->setValue ((float) xmlState->getDoubleAttribute (p->paramID, p->getValue())); // if (auto* p = dynamic_cast<AudioProcessorParameterWithID*> (param))
// p->setValue ((float) xmlState->getDoubleAttribute (p->paramID, p->getValue()));
fluidSynthModel.onFileNameChanged( //
sharedParams->getSoundFontPath(), // fluidSynthModel.onFileNameChanged(
sharedParams->getBank(), // sharedParams->getSoundFontPath(),
sharedParams->getPreset()); // sharedParams->getBank(),
// sharedParams->getPreset());
AudioProcessorEditor* editor{getActiveEditor()}; //
if (editor != nullptr) { // AudioProcessorEditor* editor{getActiveEditor()};
editor->setSize( // if (editor != nullptr) {
sharedParams->getUiWidth(), // editor->setSize(
sharedParams->getUiHeight()); // sharedParams->getUiWidth(),
// sharedParams->getUiHeight());
jassert(dynamic_cast<ExposesComponents*> (editor) != nullptr); //
ExposesComponents* exposesComponents = dynamic_cast<ExposesComponents*> (editor); // jassert(dynamic_cast<ExposesComponents*> (editor) != nullptr);
exposesComponents->getFilePicker().setDisplayedFilePath(sharedParams->getSoundFontPath()); // ExposesComponents* exposesComponents = dynamic_cast<ExposesComponents*> (editor);
} // exposesComponents->getFilePicker().setDisplayedFilePath(sharedParams->getSoundFontPath());
// }
// const String& currentSoundFontAbsPath = fluidSynthModel->getCurrentSoundFontAbsPath(); // const String& currentSoundFontAbsPath = fluidSynthModel->getCurrentSoundFontAbsPath();
// if (currentSoundFontAbsPath.isNotEmpty()) { // if (currentSoundFontAbsPath.isNotEmpty()) {
@ -431,8 +444,12 @@ bool JuicySFAudioProcessor::supportsDoublePrecisionProcessing() const {
return false; return false;
} }
FluidSynthModel* JuicySFAudioProcessor::getFluidSynthModel() { FluidSynthModel& JuicySFAudioProcessor::getFluidSynthModel() {
return &fluidSynthModel; return fluidSynthModel;
}
SharesParams& JuicySFAudioProcessor::getSharedParams() {
return sharedParams;
} }
//============================================================================== //==============================================================================

View File

@ -14,6 +14,7 @@
#include "FluidSynthModel.h" #include "FluidSynthModel.h"
#include "StateChangeSubscriber.h" #include "StateChangeSubscriber.h"
#include "SharesParams.h" #include "SharesParams.h"
#include "Params.h"
#include <list> #include <list>
using namespace std; using namespace std;
@ -62,18 +63,18 @@ public:
bool supportsDoublePrecisionProcessing() const override; bool supportsDoublePrecisionProcessing() const override;
FluidSynthModel* getFluidSynthModel(); FluidSynthModel& getFluidSynthModel();
SharesParams& getSharedParams();
MidiKeyboardState keyboardState; MidiKeyboardState keyboardState;
shared_ptr<SharesParams> sharedParams;
// void subscribeToStateChanges(StateChangeSubscriber* subscriber); // void subscribeToStateChanges(StateChangeSubscriber* subscriber);
// void unsubscribeFromStateChanges(StateChangeSubscriber* subscriber); // void unsubscribeFromStateChanges(StateChangeSubscriber* subscriber);
private: private:
void initialiseSynth(); void initialiseSynth();
Params sharedParams;
AudioProcessorValueTreeState valueTreeState; AudioProcessorValueTreeState valueTreeState;
FluidSynthModel fluidSynthModel; FluidSynthModel fluidSynthModel;

View File

@ -1,6 +1,6 @@
// // http://www.synthfont.com/Tutorial6.html
// Created by Alex Birch on 17/09/2017. // a bank can hold many (128) presets
// // bank 128 is reserved for percussion
#pragma once #pragma once

View File

@ -13,35 +13,35 @@ class SharesParams {
public: public:
virtual ~SharesParams() {} virtual ~SharesParams() {}
virtual void setAttributesOnXml(XmlElement& xml) = 0; virtual void setAttributesOnXml(shared_ptr<XmlElement> xml) = 0;
virtual void loadAttributesFromXml(shared_ptr<XmlElement> xmlState) = 0; virtual void loadAttributesFromXml(shared_ptr<XmlElement> xmlState) = 0;
virtual void acceptMidiControlEvent(int controller, int value) = 0; // virtual void acceptMidiControlEvent(int controller, int value) = 0;
virtual void setSoundFontPath(const String& value) = 0; virtual void setSoundFontPath(const String& value) = 0;
virtual String& getSoundFontPath() = 0; virtual String& getSoundFontPath() = 0;
virtual int getPreset() = 0; // virtual int getPreset() = 0;
virtual void setPreset(int value) = 0; // virtual void setPreset(int value) = 0;
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;
virtual int getDecay() = 0; // virtual int getDecay() = 0;
virtual void setDecay(int value) = 0; // virtual void setDecay(int value) = 0;
virtual int getSustain() = 0; // virtual int getSustain() = 0;
virtual void setSustain(int value) = 0; // virtual void setSustain(int value) = 0;
virtual int getRelease() = 0; // virtual int getRelease() = 0;
virtual void setRelease(int value) = 0; // virtual void setRelease(int value) = 0;
virtual int getFilterCutOff() = 0; // virtual int getFilterCutOff() = 0;
virtual void setFilterCutOff(int value) = 0; // virtual void setFilterCutOff(int value) = 0;
virtual int getFilterResonance() = 0; // virtual int getFilterResonance() = 0;
virtual void setFilterResonance(int value) = 0; // virtual void setFilterResonance(int value) = 0;
}; };

View File

@ -24,7 +24,7 @@ std::function<void()> SlidersComponent::makeSliderListener(Slider& slider, int c
s << slider.getComponentID() << ", controller " << controller << ", value " << slider.getValue() << ", xmlReleaseValue " << value; s << slider.getComponentID() << ", controller " << controller << ", value " << slider.getValue() << ", xmlReleaseValue " << value;
DEBUG_PRINT(s); DEBUG_PRINT(s);
// slider.setValue(slider.getValue(), NotificationType::dontSendNotification); // slider.setValue(slider.getValue(), NotificationType::dontSendNotification);
fluidSynthModel->setControllerValue(controller, slider.getValue()); fluidSynthModel.setControllerValue(controller, slider.getValue());
// callback(); // callback();
}; };
} }
@ -115,9 +115,9 @@ void SlidersComponent::acceptMidiControlEvent(int controller, int value) {
// } // }
SlidersComponent::SlidersComponent( SlidersComponent::SlidersComponent(
shared_ptr<SharesParams> sharedParams, SharesParams& sharedParams,
AudioProcessorValueTreeState& valueTreeState, AudioProcessorValueTreeState& valueTreeState,
FluidSynthModel* fluidSynthModel) FluidSynthModel& fluidSynthModel)
: sharedParams{sharedParams} : sharedParams{sharedParams}
, valueTreeState{valueTreeState} , valueTreeState{valueTreeState}
, fluidSynthModel{fluidSynthModel} , fluidSynthModel{fluidSynthModel}

View File

@ -13,9 +13,9 @@ class SlidersComponent : public Component,
{ {
public: public:
SlidersComponent( SlidersComponent(
shared_ptr<SharesParams> sharedParams, SharesParams& sharedParams,
AudioProcessorValueTreeState& valueTreeState, AudioProcessorValueTreeState& valueTreeState,
FluidSynthModel* fluidSynthModel); FluidSynthModel& fluidSynthModel);
~SlidersComponent(); ~SlidersComponent();
void resized() override; void resized() override;
@ -35,9 +35,9 @@ public:
private: private:
std::function<void()> makeSliderListener(Slider& slider, int controller); std::function<void()> makeSliderListener(Slider& slider, int controller);
shared_ptr<SharesParams> sharedParams; SharesParams& sharedParams;
AudioProcessorValueTreeState& valueTreeState; AudioProcessorValueTreeState& valueTreeState;
FluidSynthModel* fluidSynthModel; FluidSynthModel& fluidSynthModel;
GroupComponent envelopeGroup; GroupComponent envelopeGroup;

View File

@ -6,13 +6,15 @@
#include "SoundfontSynthSound.h" #include "SoundfontSynthSound.h"
#include "Util.h" #include "Util.h"
SoundfontSynthVoice::SoundfontSynthVoice(fluid_synth_t* synth) using namespace std;
: tailOff (0.0),
level(0.0), SoundfontSynthVoice::SoundfontSynthVoice(shared_ptr<fluid_synth_t> synth)
currentAngle(0.0), : tailOff(0.0)
angleDelta(0.0), , level(0.0)
midiNoteNumber(0), , currentAngle(0.0)
synth(synth) , angleDelta(0.0)
, midiNoteNumber(0)
, synth(synth)
{ {
} }
@ -26,7 +28,7 @@ void SoundfontSynthVoice::startNote(
int /*currentPitchWheelPosition*/) { int /*currentPitchWheelPosition*/) {
this->midiNoteNumber = midiNoteNumber; this->midiNoteNumber = midiNoteNumber;
DEBUG_PRINT ( juce::String::formatted("JUCE noteon: %d, %d\n", midiNoteNumber, velocity) ); DEBUG_PRINT ( juce::String::formatted("JUCE noteon: %d, %d\n", midiNoteNumber, velocity) );
fluid_synth_noteon(synth, 0, midiNoteNumber, static_cast<int>(velocity * 127)); fluid_synth_noteon(synth.get(), 0, midiNoteNumber, static_cast<int>(velocity * 127));
// currentAngle = 0.0; // currentAngle = 0.0;
// level = velocity * 0.15; // level = velocity * 0.15;
@ -59,7 +61,7 @@ void SoundfontSynthVoice::stopNote (float /*velocity*/, bool allowTailOff) {
// } // }
DEBUG_PRINT ( juce::String("JUCE noteoff\n") ); DEBUG_PRINT ( juce::String("JUCE noteoff\n") );
clearCurrentNote(); clearCurrentNote();
fluid_synth_noteoff(synth, 0, this->midiNoteNumber); fluid_synth_noteoff(synth.get(), 0, this->midiNoteNumber);
} }
// receives input as MIDI 0 to 16383, with 8192 being center // receives input as MIDI 0 to 16383, with 8192 being center

View File

@ -8,11 +8,11 @@
#include<fluidsynth.h> #include<fluidsynth.h>
#include "../JuceLibraryCode/JuceHeader.h" #include "../JuceLibraryCode/JuceHeader.h"
using std::shared_ptr; using namespace std;
class SoundfontSynthVoice : public SynthesiserVoice { class SoundfontSynthVoice : public SynthesiserVoice {
public: public:
SoundfontSynthVoice(fluid_synth_t* synth); SoundfontSynthVoice(shared_ptr<fluid_synth_t> synth);
bool canPlaySound (SynthesiserSound* sound) override; bool canPlaySound (SynthesiserSound* sound) override;
void startNote ( void startNote (
@ -35,5 +35,5 @@ private:
double angleDelta; double angleDelta;
int midiNoteNumber; int midiNoteNumber;
fluid_synth_t* synth; shared_ptr<fluid_synth_t> synth;
}; };

View File

@ -8,10 +8,13 @@ using namespace std;
using namespace placeholders; using namespace placeholders;
TablesComponent::TablesComponent( TablesComponent::TablesComponent(
FluidSynthModel* fluidSynthModel AudioProcessorValueTreeState& valueTreeState,
) : fluidSynthModel(fluidSynthModel), FluidSynthModel& fluidSynthModel
banksToPresets(fluidSynthModel->getBanks()), )
initialised(false) : valueTreeState{valueTreeState}
, fluidSynthModel{fluidSynthModel}
, banksToPresets{fluidSynthModel.getBanks()}
, initialised{false}
{ {
fluid_preset_t* currentPreset = getCurrentPreset(); fluid_preset_t* currentPreset = getCurrentPreset();
selectedBank = -1; selectedBank = -1;
@ -59,13 +62,13 @@ TablesComponent::TablesComponent(
initialised = true; initialised = true;
fluidSynthModel->addListener(this); fluidSynthModel.addListener(this);
} }
fluid_preset_t* TablesComponent::getCurrentPreset() { fluid_preset_t* TablesComponent::getCurrentPreset() {
fluid_synth_t* synth = fluidSynthModel->getSynth(); shared_ptr<fluid_synth_t> synth {fluidSynthModel.getSynth()};
return fluid_synth_get_channel_preset(synth, fluidSynthModel->getChannel()); return fluid_synth_get_channel_preset(synth.get(), fluidSynthModel.getChannel());
} }
Preset TablesComponent::getFirstPresetInBank(int bank) { Preset TablesComponent::getFirstPresetInBank(int bank) {
@ -108,13 +111,13 @@ void TablesComponent::onPresetSelected(int preset) {
} }
cout << "Preset " << preset << endl; cout << "Preset " << preset << endl;
// selectedPreset = preset; // selectedPreset = preset;
fluidSynthModel->changePreset(selectedBank, preset); fluidSynthModel.changePreset(selectedBank, preset);
} }
TablesComponent::~TablesComponent() { TablesComponent::~TablesComponent() {
delete presetTable; delete presetTable;
delete banks; delete banks;
fluidSynthModel->removeListener(this); fluidSynthModel.removeListener(this);
} }
vector<string> TablesComponent::mapBanks(const BanksToPresets &banksToPresets) { vector<string> TablesComponent::mapBanks(const BanksToPresets &banksToPresets) {
@ -165,7 +168,7 @@ bool TablesComponent::keyPressed(const KeyPress &key) {
} }
void TablesComponent::fontChanged(FluidSynthModel *, const String &) { void TablesComponent::fontChanged(FluidSynthModel *, const String &) {
banksToPresets = fluidSynthModel->getBanks(); banksToPresets = fluidSynthModel.getBanks();
fluid_preset_t* currentPreset = getCurrentPreset(); fluid_preset_t* currentPreset = getCurrentPreset();

View File

@ -20,7 +20,8 @@ class TablesComponent : public Component,
{ {
public: public:
TablesComponent( TablesComponent(
FluidSynthModel* fluidSynthModel AudioProcessorValueTreeState& valueTreeState,
FluidSynthModel& fluidSynthModel
); );
~TablesComponent(); ~TablesComponent();
@ -30,7 +31,8 @@ public:
void fontChanged(FluidSynthModel *, const String &) override; void fontChanged(FluidSynthModel *, const String &) override;
private: private:
FluidSynthModel* fluidSynthModel; AudioProcessorValueTreeState& valueTreeState;
FluidSynthModel& fluidSynthModel;
int selectedBank; int selectedBank;
Pills* banks; Pills* banks;