progress moving table model to be managed by fluidsynth, de-generalizing and decoupling table component

This commit is contained in:
Alex Birch 2019-07-13 00:16:35 +01:00
parent e02188b7f4
commit e1a8df9e8f
No known key found for this signature in database
GPG Key ID: 305EB1F98D44ACBA
6 changed files with 155 additions and 39 deletions

View File

@ -27,12 +27,12 @@ FilePicker::FilePicker(
setOpaque (true); setOpaque (true);
// setDisplayedFilePath(fluidSynthModel.getCurrentSoundFontAbsPath()); // setDisplayedFilePath(fluidSynthModel.getCurrentSoundFontAbsPath());
setDisplayedFilePath(""); setDisplayedFilePath(valueTreeState.state.getChildWithName("soundFont").getProperty("path", ""));
addAndMakeVisible (fileChooser); addAndMakeVisible (fileChooser);
fileChooser.addListener (this); fileChooser.addListener (this);
valueTreeState.state.addListener(this); valueTreeState.state.addListener(this);
valueTreeState.state.getChildWithName("soundFont").sendPropertyChangeMessage("path"); // valueTreeState.state.getChildWithName("soundFont").sendPropertyChangeMessage("path");
} }
FilePicker::~FilePicker() { FilePicker::~FilePicker() {
fileChooser.removeListener (this); fileChooser.removeListener (this);
@ -65,7 +65,7 @@ void FilePicker::valueTreePropertyChanged(ValueTree& treeWhosePropertyHasChanged
// if (&treeWhosePropertyHasChanged == &valueTree) { // if (&treeWhosePropertyHasChanged == &valueTree) {
if (property == StringRef("path")) { if (property == StringRef("path")) {
String soundFontPath{treeWhosePropertyHasChanged.getProperty("path", "")}; String soundFontPath{treeWhosePropertyHasChanged.getProperty("path", "")};
DEBUG_PRINT(soundFontPath); // DEBUG_PRINT(soundFontPath);
// if (soundFontPath.isNotEmpty()) { // if (soundFontPath.isNotEmpty()) {
// loadFont(soundFontPath); // loadFont(soundFontPath);
// } // }

View File

@ -339,6 +339,42 @@ void FluidSynthModel::loadFont(const String &absPath) {
currentSoundFontAbsPath = absPath; currentSoundFontAbsPath = absPath;
sfont_id++; sfont_id++;
fluid_synth_sfload(synth.get(), absPath.toStdString().c_str(), 1); 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() { FluidSynthModel::Listener::~Listener() {

View File

@ -46,6 +46,10 @@ JuicySFAudioProcessor::JuicySFAudioProcessor()
valueTreeState.state.appendChild({ "soundFont", { valueTreeState.state.appendChild({ "soundFont", {
{ "path", "" }, { "path", "" },
}, {} }, nullptr); }, {} }, 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.setProperty("soundFontPath", "", nullptr);
// valueTreeState.state.appendChild({ "soundFontPath", {} }, nullptr); // valueTreeState.state.appendChild({ "soundFontPath", {} }, nullptr);

View File

@ -15,17 +15,18 @@ using namespace std;
This class shows how to implement a TableListBoxModel to show in a TableListBox. This class shows how to implement a TableListBoxModel to show in a TableListBox.
*/ */
TableComponent::TableComponent( TableComponent::TableComponent(
const vector<string> &columns, AudioProcessorValueTreeState& valueTreeState,
const vector<vector<string>> &rows, // const vector<string> &columns,
const function<void (int)> &onRowSelected, const vector<vector<string>> &rows,
const function<int (const vector<string>&)> &rowToIDMapper, const function<void (int)> &onRowSelected,
int initiallySelectedRow // const function<int (const vector<string>&)> &rowToIDMapper,
int initiallySelectedRow
) )
: font (14.0f), : font (14.0f)
columns(columns), , columns(columns)
rows(rows), , rows(rows)
onRowSelected(onRowSelected), , onRowSelected(onRowSelected)/*,
rowToIDMapper(rowToIDMapper) rowToIDMapper(rowToIDMapper)*/
{ {
// Create our table component and add it to this component.. // Create our table component and add it to this component..
addAndMakeVisible (table); addAndMakeVisible (table);
@ -38,31 +39,81 @@ TableComponent::TableComponent(
int columnIx = 1; int columnIx = 1;
// Add some columns to the table header, based on the column list in our database.. // 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 // for (auto &column : columns) // access by reference to avoid copying
{ // {
const int colWidth{ columnIx == 1 ? 30 : 200 }; // const int colWidth{ columnIx == 1 ? 30 : 200 };
table.getHeader().addColumn ( // table.getHeader().addColumn (
String(column), // String(column),
columnIx++, // columnIx++,
colWidth, // column width // colWidth, // column width
30, // min width // 30, // min width
400, // max width // 400, // max width
TableHeaderComponent::defaultFlags // 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.setWantsKeyboardFocus(false);
table.selectRow(initiallySelectedRow); table.selectRow(initiallySelectedRow);
// we could now change some initial settings.. // 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 // 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 // un-comment this line to have a go of stretch-to-fit mode
// table.getHeader().setStretchToFitActive (true); // table.getHeader().setStretchToFitActive (true);
// table.setMultipleSelectionEnabled (false); // 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<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// int value{castParam->get()};
// } else if (parameterID == "preset") {
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (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<vector<string>>& rows, int initiallySelectedRow) { void TableComponent::setRows(const vector<vector<string>>& rows, int initiallySelectedRow) {
@ -148,10 +199,8 @@ void TableComponent::sortOrderChanged (
// This is overloaded from TableListBoxModel, and should choose the best width for the specified // This is overloaded from TableListBoxModel, and should choose the best width for the specified
// column. // column.
int TableComponent::getColumnAutoSizeWidth (int columnId) { int TableComponent::getColumnAutoSizeWidth (int columnId) {
// if (columnId == 5)
// return 100; // (this is the ratings column, containing a custom combobox component)
if (columnId == 1) if (columnId == 1)
return 30; // (this is the ratings column, containing a custom combobox component) return 30;
int widest = 32; int widest = 32;
@ -201,7 +250,13 @@ void TableComponent::selectedRowsChanged (int row) {
if (row < 0) { if (row < 0) {
return; 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<AudioParameterInt*> (param) != nullptr);
AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
*castParam = newPreset;
} }
bool TableComponent::keyPressed(const KeyPress &key) { bool TableComponent::keyPressed(const KeyPress &key) {

View File

@ -16,15 +16,19 @@
using namespace std; using namespace std;
class TableComponent : public Component, class TableComponent : public Component,
public TableListBoxModel { public TableListBoxModel,
public ValueTree::Listener/*,
public AudioProcessorValueTreeState::Listener */ {
public: public:
TableComponent( TableComponent(
const vector<string> &columns, AudioProcessorValueTreeState& valueTreeState,
// const vector<string> &columns,
const vector<vector<string>> &rows, const vector<vector<string>> &rows,
const function<void (int)> &onRowSelected, const function<void (int)> &onRowSelected,
const function<int (const vector<string>&)> &rowToIDMapper, // const function<int (const vector<string>&)> &rowToIDMapper,
int initiallySelectedRow int initiallySelectedRow
); );
~TableComponent();
int getNumRows() override; int getNumRows() override;
@ -56,7 +60,22 @@ public:
bool keyPressed(const KeyPress &key) override; 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: private:
AudioProcessorValueTreeState& valueTreeState;
TableListBox table; // the table component itself TableListBox table; // the table component itself
Font font; Font font;
@ -64,7 +83,7 @@ private:
vector<vector<string>> rows; vector<vector<string>> rows;
function<void (int)> onRowSelected; function<void (int)> onRowSelected;
function<int (const vector<string>&)> rowToIDMapper; // function<int (const vector<string>&)> rowToIDMapper;
// A comparator used to sort our data when the user clicks a column header // A comparator used to sort our data when the user clicks a column header
class DataSorter { class DataSorter {

View File

@ -20,20 +20,22 @@ TablesComponent::TablesComponent(
selectedBank = -1; selectedBank = -1;
int selectedPreset = -1; int selectedPreset = -1;
if (currentPreset != nullptr) { if (currentPreset != nullptr) {
selectedBank = fluid_preset_get_banknum(currentPreset); selectedBank = fluid_preset_get_banknum(currentPreset);
selectedPreset = fluid_preset_get_num(currentPreset); selectedPreset = fluid_preset_get_num(currentPreset);
} }
auto rowToPresetMapper = [this](const vector<string> &row) { // auto rowToPresetMapper = [this](const vector<string> &row) {
return stoi(row[0]); // return stoi(row[0]);
}; // };
auto itemToBankMapper = [](const string &item) { auto itemToBankMapper = [](const string &item) {
return stoi(item); return stoi(item);
}; };
presetTable = new TableComponent( presetTable = new TableComponent(
{"#", "Name"}, // {"#", "Name"},
mapPresets( mapPresets(
banksToPresets, banksToPresets,
selectedBank selectedBank
@ -41,7 +43,7 @@ TablesComponent::TablesComponent(
[this](int preset){ [this](int preset){
this->onPresetSelected(preset); this->onPresetSelected(preset);
}, },
rowToPresetMapper, // rowToPresetMapper,
presetToIndexMapper(selectedPreset) presetToIndexMapper(selectedPreset)
); );
banks = new Pills( banks = new Pills(