From 037248a7d6611c54e00d158a291a146f8fa29138 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 19 Apr 2020 16:32:33 +0200 Subject: Support MIDNAM with Performances in PatchSelector #7536 Some modern keyboards spread out patches over various banks, and group them using explicit "PatchMIDICommands". A given PatchBank does not have a common MIDI Bank. Previously those PatchBanks were not listed in the MIDI Patch Selector, which is based on MIDI Bank + Program grid. The current view is some sort of compromise, retaining a per MIDI-bank view, but allowing Monatages/performance mappings. The Patch Change *dialog*, or dropdown is more useful for those sparse modern mappings. --- gtk2_ardour/patch_change_widget.cc | 113 +++++++++++++++++++++++++++++++------ gtk2_ardour/patch_change_widget.h | 1 - 2 files changed, 95 insertions(+), 19 deletions(-) (limited to 'gtk2_ardour') diff --git a/gtk2_ardour/patch_change_widget.cc b/gtk2_ardour/patch_change_widget.cc index f5d77eb8cb..16e9aa8c4a 100644 --- a/gtk2_ardour/patch_change_widget.cc +++ b/gtk2_ardour/patch_change_widget.cc @@ -17,6 +17,8 @@ */ #include +#include + #include #include "pbd/unwind.h" @@ -213,12 +215,27 @@ PatchChangeWidget::select_channel (uint8_t chn) refill_banks (); } + +/* allow to sort bank-name by use-count */ +template +static std::multimap flip_map (std::map const& src) +{ + std::multimap dst; + + for (typename std::map::const_iterator it = src.begin(); it != src.end(); ++it) { + dst.insert (std::pair (it->second, it->first)); + } + + return dst; +} + void PatchChangeWidget::refill_banks () { cancel_audition (); using namespace Menu_Helpers; using namespace Gtkmm2ext; + using namespace MIDI::Name; _current_patch_bank.reset (); _bank_select.clear_items (); @@ -231,35 +248,89 @@ PatchChangeWidget::refill_banks () _bank_lsb_spin.set_value (b & 127); } - boost::shared_ptr cns = _info.get_patches (_channel); + typedef std::map BankName; + typedef std::map BankSet; + + bool bank_set = false; + std::bitset<128> unset_notes; + BankSet generic_banks; + + unset_notes.set (); + + boost::shared_ptr cns = _info.get_patches (_channel); if (cns) { - for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = cns->patch_banks().begin(); i != cns->patch_banks().end(); ++i) { - std::string n = (*i)->name (); - if ((*i)->number () == UINT16_MAX) { + const ChannelNameSet::PatchBanks& patch_banks = cns->patch_banks (); + for (ChannelNameSet::PatchBanks::const_iterator bank = patch_banks.begin (); bank != patch_banks.end (); ++bank) { + if ((*bank)->number () != UINT16_MAX) { + continue; + } + /* no shared MIDI bank for this PatchBanks, + * iterate over all programs in the patchbank, collect "" + */ + const PatchNameList& patches = (*bank)->patch_name_list (); + for (PatchNameList::const_iterator patch = patches.begin (); patch != patches.end (); ++patch) { + + BankName& bn (generic_banks[(*patch)->bank_number ()]); + ++bn[(*bank)->name ()]; + + if ((*patch)->bank_number () != b) { + continue; + } + const std::string n = (*patch)->name (); + MIDI::Name::PatchPrimaryKey const& key = (*patch)->patch_primary_key (); + + const uint8_t pgm = key.program(); + _program_btn[pgm].set_text (n); + set_tooltip (_program_btn[pgm], string_compose (_("%1 (Pgm-%2)"), + Gtkmm2ext::markup_escape_text (n), (int)(pgm +1))); + unset_notes.reset (pgm); + } + } + + for (ChannelNameSet::PatchBanks::const_iterator bank = patch_banks.begin (); bank != patch_banks.end (); ++bank) { + if ((*bank)->number () == UINT16_MAX) { continue; } - _bank_select.AddMenuElem (MenuElemNoMnemonic (n, sigc::bind (sigc::mem_fun (*this, &PatchChangeWidget::select_bank), (*i)->number ()))); - if ((*i)->number () == b) { - _current_patch_bank = *i; + generic_banks.erase ((*bank)->number ()); + std::string n = (*bank)->name (); + _bank_select.AddMenuElem (MenuElemNoMnemonic (n, sigc::bind (sigc::mem_fun (*this, &PatchChangeWidget::select_bank), (*bank)->number ()))); + if ((*bank)->number () == b) { + _current_patch_bank = *bank; _bank_select.set_text (n); } } + + for (BankSet::const_iterator i = generic_banks.begin(); i != generic_banks.end(); ++i) { + std::string n = string_compose (_("Bank %1"), (i->first) + 1); +#if 1 + typedef std::multimap BankByCnt; + BankByCnt bc (flip_map (i->second)); + unsigned int cnt = 0; // pick top three + for (BankByCnt::reverse_iterator j = bc.rbegin(); j != bc.rend() && cnt < 3; ++j, ++cnt) { + n += " (" + j->second + ")"; + if (n.size () > 64) { + break; + } + } + if (bc.size () > cnt) { + n += " (...)"; + } +#endif + _bank_select.AddMenuElem (MenuElemNoMnemonic (n, sigc::bind (sigc::mem_fun (*this, &PatchChangeWidget::select_bank), i->first))); + if (i->first == b) { + _bank_select.set_text (n); + bank_set = true; + } + } } - if (!_current_patch_bank) { - std::string n = string_compose (_("Bank %1"), b); + if (!_current_patch_bank && !bank_set) { + std::string n = string_compose (_("Bank %1"), b + 1); _bank_select.AddMenuElem (MenuElemNoMnemonic (n, sigc::bind (sigc::mem_fun (*this, &PatchChangeWidget::select_bank), b))); _bank_select.set_text (n); } - refill_program_list (); -} - -void -PatchChangeWidget::refill_program_list () -{ - std::bitset<128> unset_notes; - unset_notes.set (); + /* refill_program_list */ if (_current_patch_bank) { const MIDI::Name::PatchNameList& patches = _current_patch_bank->patch_name_list (); @@ -275,6 +346,8 @@ PatchChangeWidget::refill_program_list () } } + bool shade = unset_notes.count () != 128; + for (uint8_t pgm = 0; pgm < 128; ++pgm) { if (!unset_notes.test (pgm)) { _program_btn[pgm].set_name (X_("patch change button")); @@ -282,7 +355,11 @@ PatchChangeWidget::refill_program_list () } std::string n = string_compose (_("Pgm-%1"), (int)(pgm +1)); _program_btn[pgm].set_text (n); - _program_btn[pgm].set_name (X_("patch change dim button")); + if (shade) { + _program_btn[pgm].set_name (X_("patch change dim button")); + } else { + _program_btn[pgm].set_name (X_("patch change button")); + } set_tooltip (_program_btn[pgm], n); } diff --git a/gtk2_ardour/patch_change_widget.h b/gtk2_ardour/patch_change_widget.h index 35fc46e35e..d9c1e77279 100644 --- a/gtk2_ardour/patch_change_widget.h +++ b/gtk2_ardour/patch_change_widget.h @@ -73,7 +73,6 @@ private: void bankpatch_changed (uint8_t); void refill_banks (); - void refill_program_list (); void instrument_info_changed (); void processors_changed (); -- cgit v1.2.3