summaryrefslogtreecommitdiff
path: root/gtk2_ardour
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2020-04-19 16:32:33 +0200
committerRobin Gareus <robin@gareus.org>2020-04-19 16:32:33 +0200
commit037248a7d6611c54e00d158a291a146f8fa29138 (patch)
tree9823b2c37a5a8145f97045ef20d9fc122ab8d049 /gtk2_ardour
parentc32fef2660cccf822d39bae918670c655e9a7765 (diff)
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.
Diffstat (limited to 'gtk2_ardour')
-rw-r--r--gtk2_ardour/patch_change_widget.cc113
-rw-r--r--gtk2_ardour/patch_change_widget.h1
2 files changed, 95 insertions, 19 deletions
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 <bitset>
+#include <map>
+
#include <gtkmm/frame.h>
#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 <typename A, typename B>
+static std::multimap<B, A> flip_map (std::map<A, B> const& src)
+{
+ std::multimap<B,A> dst;
+
+ for (typename std::map<A, B>::const_iterator it = src.begin(); it != src.end(); ++it) {
+ dst.insert (std::pair<B, A> (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<MIDI::Name::ChannelNameSet> cns = _info.get_patches (_channel);
+ typedef std::map<std::string, unsigned int> BankName;
+ typedef std::map<uint16_t, BankName> BankSet;
+
+ bool bank_set = false;
+ std::bitset<128> unset_notes;
+ BankSet generic_banks;
+
+ unset_notes.set ();
+
+ boost::shared_ptr<ChannelNameSet> 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 "<ControlChange>"
+ */
+ 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 <unsigned int, std::string> 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 ();