+}
+
+void
+GenericPluginUI::custom_layout (const std::vector<ControlUI*>& control_uis)
+{
+ Gtk::Table* layout = manage (new Gtk::Table ());
+
+ for (vector<ControlUI*>::const_iterator i = control_uis.begin(); i != control_uis.end(); ++i) {
+ ControlUI* cui = *i;
+ if (cui->x0 < 0 || cui->y0 < 0) {
+ continue;
+ }
+ layout->attach (*cui, cui->x0, cui->x1, cui->y0, cui->y1, FILL, SHRINK, 2, 2);
+ }
+ hpacker.pack_start (*layout, true, true);
+
+ if (plugin->has_inline_display () && plugin->inline_display_in_gui ()) {
+ PluginDisplay* pd = manage (new PluginDisplay (plugin, 300));
+ hpacker.pack_end (*pd, true, true);
+ }
+}
+
+void
+GenericPluginUI::build_midi_table ()
+{
+ Gtk::Table* pgm_table = manage (new Gtk::Table (8, 5));
+
+ pgm_table->set_homogeneous (false);
+ pgm_table->set_row_spacings (2);
+ pgm_table->set_col_spacings (2);
+ pgm_table->set_border_width (5);
+ pgm_table->set_col_spacing (2, 10);
+
+ Frame* frame = manage (new Frame);
+ frame->set_name ("BaseFrame");
+ if (dynamic_cast<MidiTrack*> (insert->owner())) {
+ frame->set_label (_("MIDI Programs (sent to track)"));
+ } else {
+ frame->set_label (_("MIDI Programs (volatile)"));
+ }
+ frame->add (*pgm_table);
+ hpacker.pack_start (*frame, false, false);
+
+ for (uint8_t chn = 0; chn < 16; ++chn) {
+ int col = 3 * (chn / 8);
+ int row = chn % 8;
+ ArdourDropdown* cui = manage (new ArdourWidgets::ArdourDropdown ());
+ cui->set_sizing_text ("Stereo Grand Piano");
+ cui->set_text_ellipsize (Pango::ELLIPSIZE_END);
+ cui->set_layout_ellipsize_width (PANGO_SCALE * 112 * UIConfiguration::instance ().get_ui_scale ());
+ midi_pgmsel.push_back (cui);
+ pgm_table->attach (*manage (new Label (string_compose ("C%1:", (int)(chn + 1)), ALIGN_RIGHT)), col, col + 1, row, row+1, FILL, SHRINK);
+ pgm_table->attach (*cui, col + 1, col + 2, row, row+1, SHRINK, SHRINK);
+ }
+
+ insert->plugin ()->read_midnam();
+
+ midi_refill_patches ();
+
+ insert->plugin()->BankPatchChange.connect (
+ midi_connections, invalidator (*this),
+ boost::bind (&GenericPluginUI::midi_bank_patch_change, this, _1),
+ gui_context());
+
+ insert->plugin()->UpdatedMidnam.connect (
+ midi_connections, invalidator (*this),
+ boost::bind (&GenericPluginUI::midi_refill_patches, this),
+ gui_context());
+}
+
+void
+GenericPluginUI::midi_refill_patches ()
+{
+ assert (midi_pgmsel.size() == 16);
+
+ pgm_names.clear ();
+
+ const std::string model = insert->plugin ()->midnam_model ();
+ std::string mode;
+ const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance().custom_device_mode_names_by_model (model);
+ if (device_modes.size() > 0) {
+ mode = device_modes.front();
+ }
+
+ for (uint8_t chn = 0; chn < 16; ++chn) {
+ midi_pgmsel[chn]->clear_items ();
+ boost::shared_ptr<MIDI::Name::ChannelNameSet> cns =
+ MIDI::Name::MidiPatchManager::instance().find_channel_name_set (model, mode, chn);
+
+ if (cns) {
+ using namespace Menu_Helpers;
+ using namespace Gtkmm2ext;
+
+ for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = cns->patch_banks().begin(); i != cns->patch_banks().end(); ++i) {
+ const MIDI::Name::PatchNameList& patches = (*i)->patch_name_list ();
+ for (MIDI::Name::PatchNameList::const_iterator j = patches.begin(); j != patches.end(); ++j) {
+ const std::string pgm = (*j)->name ();
+ MIDI::Name::PatchPrimaryKey const& key = (*j)->patch_primary_key ();
+ const uint32_t bp = (key.bank() << 7) | key.program();
+ midi_pgmsel[chn]->AddMenuElem (MenuElemNoMnemonic (pgm, sigc::bind (sigc::mem_fun (*this, &GenericPluginUI::midi_bank_patch_select), chn, bp)));
+ pgm_names[bp] = pgm;
+ }
+ }
+ }
+
+ midi_bank_patch_change (chn);
+ }
+}
+
+void
+GenericPluginUI::midi_bank_patch_change (uint8_t chn)
+{
+ assert (chn < 16 && midi_pgmsel.size() == 16);
+ uint32_t bankpgm = insert->plugin()->bank_patch (chn);
+ if (bankpgm == UINT32_MAX) {
+ midi_pgmsel[chn]->set_text (_("--Unset--"));
+ } else {
+ int bank = bankpgm >> 7;
+ int pgm = bankpgm & 127;
+ if (pgm_names.find (bankpgm) != pgm_names.end ()) {
+ midi_pgmsel[chn]->set_text (pgm_names[bankpgm]);
+ } else {
+ midi_pgmsel[chn]->set_text (string_compose ("Bank %1,%2 Pgm %3",
+ (bank >> 7) + 1, (bank & 127) + 1, pgm +1));
+ }
+ }
+}
+
+void
+GenericPluginUI::midi_bank_patch_select (uint8_t chn, uint32_t bankpgm)
+{
+ int bank = bankpgm >> 7;
+ int pgm = bankpgm & 127;
+ MidiTrack* mt = dynamic_cast<MidiTrack*> (insert->owner());
+ if (mt) {
+ /* send to track */
+ boost::shared_ptr<AutomationControl> bank_msb = mt->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true);
+ boost::shared_ptr<AutomationControl> bank_lsb = mt->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true);
+ boost::shared_ptr<AutomationControl> program = mt->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true);
+
+ bank_msb->set_value (bank >> 7, PBD::Controllable::NoGroup);
+ bank_lsb->set_value (bank & 127, PBD::Controllable::NoGroup);
+ program->set_value (pgm, PBD::Controllable::NoGroup);
+ } else {
+ uint8_t event[3];
+ event[0] = (MIDI_CMD_CONTROL | chn);
+ event[1] = 0x00;
+ event[2] = bank >> 7;
+ insert->write_immediate_event (3, event);
+
+ event[1] = 0x20;
+ event[2] = bank & 127;
+ insert->write_immediate_event (3, event);
+
+ event[0] = (MIDI_CMD_PGM_CHANGE | chn);
+ event[1] = pgm;
+ insert->write_immediate_event (2, event);
+ }