From e1a8df9e8f01c1dc537c1258f94f6b15e280cc91 Mon Sep 17 00:00:00 2001 From: Alex Birch Date: Sat, 13 Jul 2019 00:16:35 +0100 Subject: [PATCH] progress moving table model to be managed by fluidsynth, de-generalizing and decoupling table component --- Source/FilePicker.cpp | 6 +- Source/FluidSynthModel.cpp | 36 ++++++++++++ Source/PluginProcessor.cpp | 4 ++ Source/TableComponent.cpp | 109 ++++++++++++++++++++++++++++--------- Source/TableComponent.h | 27 +++++++-- Source/TablesComponent.cpp | 12 ++-- 6 files changed, 155 insertions(+), 39 deletions(-) diff --git a/Source/FilePicker.cpp b/Source/FilePicker.cpp index 46d1aa5..dbd6930 100644 --- a/Source/FilePicker.cpp +++ b/Source/FilePicker.cpp @@ -27,12 +27,12 @@ FilePicker::FilePicker( setOpaque (true); // setDisplayedFilePath(fluidSynthModel.getCurrentSoundFontAbsPath()); - setDisplayedFilePath(""); + setDisplayedFilePath(valueTreeState.state.getChildWithName("soundFont").getProperty("path", "")); addAndMakeVisible (fileChooser); fileChooser.addListener (this); valueTreeState.state.addListener(this); - valueTreeState.state.getChildWithName("soundFont").sendPropertyChangeMessage("path"); +// valueTreeState.state.getChildWithName("soundFont").sendPropertyChangeMessage("path"); } FilePicker::~FilePicker() { fileChooser.removeListener (this); @@ -65,7 +65,7 @@ void FilePicker::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasChanged // if (&treeWhosePropertyHasChanged == &valueTree) { if (property == StringRef("path")) { String soundFontPath{treeWhosePropertyHasChanged.getProperty("path", "")}; - DEBUG_PRINT(soundFontPath); + // DEBUG_PRINT(soundFontPath); // if (soundFontPath.isNotEmpty()) { // loadFont(soundFontPath); // } diff --git a/Source/FluidSynthModel.cpp b/Source/FluidSynthModel.cpp index 976352e..2d33629 100644 --- a/Source/FluidSynthModel.cpp +++ b/Source/FluidSynthModel.cpp @@ -339,6 +339,42 @@ void FluidSynthModel::loadFont(const String &absPath) { currentSoundFontAbsPath = absPath; sfont_id++; fluid_synth_sfload(synth.get(), absPath.toStdString().c_str(), 1); + 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); + + 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 > initialBankOffset) { + banks.appendChild({ "bank", { + { "num", bankOffset }, + }, {} }, nullptr); + } + 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; } FluidSynthModel::Listener::~Listener() { diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 8211184..e94fc05 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -46,6 +46,10 @@ JuicySFAudioProcessor::JuicySFAudioProcessor() valueTreeState.state.appendChild({ "soundFont", { { "path", "" }, }, {} }, nullptr); + // no properties, no subtrees (yet) + valueTreeState.state.appendChild({ "presets", {}, {} }, nullptr); + // no properties, no subtrees (yet) + valueTreeState.state.appendChild({ "banks", {}, {} }, nullptr); // valueTreeState.state.setProperty("soundFontPath", "", nullptr); // valueTreeState.state.appendChild({ "soundFontPath", {} }, nullptr); diff --git a/Source/TableComponent.cpp b/Source/TableComponent.cpp index 75487e5..219aad4 100644 --- a/Source/TableComponent.cpp +++ b/Source/TableComponent.cpp @@ -15,17 +15,18 @@ using namespace std; This class shows how to implement a TableListBoxModel to show in a TableListBox. */ TableComponent::TableComponent( - const vector &columns, - const vector> &rows, - const function &onRowSelected, - const function&)> &rowToIDMapper, - int initiallySelectedRow + AudioProcessorValueTreeState& valueTreeState, + // const vector &columns, + const vector> &rows, + const function &onRowSelected, + // const function&)> &rowToIDMapper, + int initiallySelectedRow ) - : font (14.0f), - columns(columns), - rows(rows), - onRowSelected(onRowSelected), - rowToIDMapper(rowToIDMapper) +: font (14.0f) +, columns(columns) +, rows(rows) +, onRowSelected(onRowSelected)/*, +rowToIDMapper(rowToIDMapper)*/ { // Create our table component and add it to this component.. addAndMakeVisible (table); @@ -38,31 +39,81 @@ TableComponent::TableComponent( int columnIx = 1; // Add some columns to the table header, based on the column list in our database.. - for (auto &column : columns) // access by reference to avoid copying - { - const int colWidth{ columnIx == 1 ? 30 : 200 }; - table.getHeader().addColumn ( - String(column), - columnIx++, - colWidth, // column width - 30, // min width - 400, // max width - TableHeaderComponent::defaultFlags - ); - } + // for (auto &column : columns) // access by reference to avoid copying + // { + // const int colWidth{ columnIx == 1 ? 30 : 200 }; + // table.getHeader().addColumn ( + // String(column), + // columnIx++, + // colWidth, // column width + // 30, // min width + // 400, // max width + // TableHeaderComponent::defaultFlags + // ); + // } + table.getHeader().addColumn ( + String("#"), + columnIx++, + 30, // column width + 30, // min width + 400, // max width + TableHeaderComponent::defaultFlags + ); + table.getHeader().addColumn ( + String("Name"), + columnIx++, + 200, // column width + 30, // min width + 400, // max width + TableHeaderComponent::defaultFlags + ); table.setWantsKeyboardFocus(false); table.selectRow(initiallySelectedRow); // we could now change some initial settings.. - table.getHeader().setSortColumnId (1, false); // sort ascending by ID column + table.getHeader().setSortColumnId(1, false); // sort ascending by ID column // table.getHeader().setColumnVisible (7, false); // hide the "length" column until the user shows it // un-comment this line to have a go of stretch-to-fit mode // table.getHeader().setStretchToFitActive (true); // table.setMultipleSelectionEnabled (false); + valueTreeState.state.addListener(this); +} + +TableComponent::~TableComponent() { + valueTreeState.state.removeListener(this); +} + +// void TableComponent::parameterChanged(const String& parameterID, float newValue) { +// // valueTreeState.getParameter +// RangedAudioParameter *param {valueTreeState.getParameter("bank")}; +// if (parameterID == "bank") { +// jassert(dynamic_cast (param) != nullptr); +// AudioParameterInt* castParam {dynamic_cast (param)}; +// int value{castParam->get()}; +// } else if (parameterID == "preset") { +// jassert(dynamic_cast (param) != nullptr); +// AudioParameterInt* castParam {dynamic_cast (param)}; +// int value{castParam->get()}; +// } +// } + +void TableComponent::valueTreePropertyChanged( + ValueTree& treeWhosePropertyHasChanged, + const Identifier& property) { + if (treeWhosePropertyHasChanged.getType() == StringRef("soundFont")) { + // if (&treeWhosePropertyHasChanged == &valueTree) { + if (property == StringRef("path")) { + String soundFontPath{treeWhosePropertyHasChanged.getProperty("path", "")}; + // DEBUG_PRINT(soundFontPath); + // if (soundFontPath.isNotEmpty()) { + // loadFont(soundFontPath); + // } + } + } } void TableComponent::setRows(const vector>& rows, int initiallySelectedRow) { @@ -148,10 +199,8 @@ void TableComponent::sortOrderChanged ( // This is overloaded from TableListBoxModel, and should choose the best width for the specified // column. int TableComponent::getColumnAutoSizeWidth (int columnId) { -// if (columnId == 5) -// return 100; // (this is the ratings column, containing a custom combobox component) if (columnId == 1) - return 30; // (this is the ratings column, containing a custom combobox component) + return 30; int widest = 32; @@ -201,7 +250,13 @@ void TableComponent::selectedRowsChanged (int row) { if (row < 0) { return; } - onRowSelected(rowToIDMapper(rows[row])); + // onRowSelected(rowToIDMapper(rows[row])); + // onRowSelected(stoi(rows[row][0])); + int newPreset{stoi(rows[row][0])}; + RangedAudioParameter *param {valueTreeState.getParameter("preset")}; + jassert(dynamic_cast (param) != nullptr); + AudioParameterInt* castParam {dynamic_cast (param)}; + *castParam = newPreset; } bool TableComponent::keyPressed(const KeyPress &key) { diff --git a/Source/TableComponent.h b/Source/TableComponent.h index d436f4c..7445e44 100644 --- a/Source/TableComponent.h +++ b/Source/TableComponent.h @@ -16,15 +16,19 @@ using namespace std; class TableComponent : public Component, - public TableListBoxModel { + public TableListBoxModel, + public ValueTree::Listener/*, + public AudioProcessorValueTreeState::Listener */ { public: TableComponent( - const vector &columns, + AudioProcessorValueTreeState& valueTreeState, + // const vector &columns, const vector> &rows, const function &onRowSelected, - const function&)> &rowToIDMapper, + // const function&)> &rowToIDMapper, int initiallySelectedRow ); + ~TableComponent(); int getNumRows() override; @@ -56,7 +60,22 @@ public: bool keyPressed(const KeyPress &key) override; +// virtual void parameterChanged (const String& parameterID, float newValue) override; + + virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, + const Identifier& property) override; + inline virtual void valueTreeChildAdded (ValueTree& parentTree, + ValueTree& childWhichHasBeenAdded) override {}; + inline virtual void valueTreeChildRemoved (ValueTree& parentTree, + ValueTree& childWhichHasBeenRemoved, + int indexFromWhichChildWasRemoved) override {}; + inline virtual void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved, + int oldIndex, int newIndex) override {}; + inline virtual void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) override {}; + inline virtual void valueTreeRedirected (ValueTree& treeWhichHasBeenChanged) override {}; private: + AudioProcessorValueTreeState& valueTreeState; + TableListBox table; // the table component itself Font font; @@ -64,7 +83,7 @@ private: vector> rows; function onRowSelected; - function&)> rowToIDMapper; +// function&)> rowToIDMapper; // A comparator used to sort our data when the user clicks a column header class DataSorter { diff --git a/Source/TablesComponent.cpp b/Source/TablesComponent.cpp index c64bddf..6e45cbb 100644 --- a/Source/TablesComponent.cpp +++ b/Source/TablesComponent.cpp @@ -20,20 +20,22 @@ TablesComponent::TablesComponent( selectedBank = -1; int selectedPreset = -1; + + if (currentPreset != nullptr) { selectedBank = fluid_preset_get_banknum(currentPreset); selectedPreset = fluid_preset_get_num(currentPreset); } - auto rowToPresetMapper = [this](const vector &row) { - return stoi(row[0]); - }; + // auto rowToPresetMapper = [this](const vector &row) { + // return stoi(row[0]); + // }; auto itemToBankMapper = [](const string &item) { return stoi(item); }; presetTable = new TableComponent( - {"#", "Name"}, + // {"#", "Name"}, mapPresets( banksToPresets, selectedBank @@ -41,7 +43,7 @@ TablesComponent::TablesComponent( [this](int preset){ this->onPresetSelected(preset); }, - rowToPresetMapper, + // rowToPresetMapper, presetToIndexMapper(selectedPreset) ); banks = new Pills(