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.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
_bank_select.AddMenuElem (MenuElemNoMnemonic (n, sigc::bind (sigc::mem_fun (*this, &PatchChangeWidget::select_bank), (*i)->number ())));
|
||||
if ((*i)->number () == b) {
|
||||
_current_patch_bank = *i;
|
||||
/* 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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,6 @@ private:
|
||||
void bankpatch_changed (uint8_t);
|
||||
|
||||
void refill_banks ();
|
||||
void refill_program_list ();
|
||||
|
||||
void instrument_info_changed ();
|
||||
void processors_changed ();
|
||||
|
||||
Reference in New Issue
Block a user