Experimental GenericPluginUI MIDI patch select.

This commit is contained in:
Robin Gareus 2017-09-08 19:42:24 +02:00
parent c3e8cdb418
commit aa11cb96b3
2 changed files with 162 additions and 1 deletions

View File

@ -34,11 +34,19 @@
#include "pbd/xml++.h"
#include "pbd/failed_constructor.h"
#include "evoral/midi_events.h"
#include "evoral/PatchChange.hpp"
#include "midi++/midnam_patch.h"
#include "ardour/midi_patch_manager.h"
#include "ardour/midi_track.h"
#include "ardour/plugin.h"
#include "ardour/plugin_insert.h"
#include "ardour/session.h"
#include "ardour/value_as_string.h"
#include "gtkmm2ext/menu_elems.h"
#include "gtkmm2ext/utils.h"
#include "gtkmm2ext/doi.h"
@ -152,6 +160,13 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr<PluginInsert> pi, bool scrol
prefheight = 0;
build ();
if (insert->plugin()->has_midnam() && insert->plugin()->knows_bank_patch()) {
/* right now PC are sent via MIDI Track controls only */
if (dynamic_cast<MidiTrack*> (insert->owner())) {
build_midi_table ();
}
}
if (is_scrollable) {
scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
scroller.set_name ("PluginEditor");
@ -400,10 +415,11 @@ GenericPluginUI::automatic_layout (const std::vector<ControlUI*>& control_uis)
button_table->set_homogeneous (false);
button_table->set_row_spacings (2);
button_table->set_col_spacings (2);
button_table->set_border_width (5);
output_table->set_homogeneous (true);
output_table->set_row_spacings (2);
output_table->set_col_spacings (2);
button_table->set_border_width (5);
output_table->set_border_width (5);
@ -596,6 +612,143 @@ GenericPluginUI::custom_layout (const std::vector<ControlUI*>& control_uis)
}
}
void
GenericPluginUI::build_midi_table ()
{
Gtk::Table* pgm_table = manage (new Gtk::Table (8, 2));
pgm_table->set_homogeneous (true);
pgm_table->set_row_spacings (2);
pgm_table->set_col_spacings (2);
pgm_table->set_border_width (5);
Frame* frame = manage (new Frame);
frame->set_name ("BaseFrame");
frame->set_label (_("MIDI Progams (sent to track)"));
//frame->set_label (_("MIDI Progams (volatile)"));
frame->add (*pgm_table);
hpacker.pack_start (*frame, true, true);
for (uint8_t chn = 0; chn < 16; ++chn) {
int col = chn / 8;
int row = chn % 8;
ArdourDropdown* cui = manage (new ArdourWidgets::ArdourDropdown ());
// TODO set size_request
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 (*cui, col, col + 1, row, row+1, FILL|EXPAND, FILL);
}
midi_refill_patches ();
insert->plugin()->BankPatchChange.connect (
midi_connections, invalidator (*this),
boost::bind (&GenericPluginUI::midi_bank_patch_change, this, _1),
gui_context());
/* Note: possible race with MidiTimeAxisView::update_patch_selector()
* which uses this signal to update/re-register the midnam (also in gui context).
* MTAV does register before us, so the midnam should already be updated when
* we're notified.
*/
insert->plugin()->UpdateMidnam.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 ();
assert ((*i)->number () == key.bank());
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;
if (1) {
/* send to track */
MidiTrack* mt = dynamic_cast<MidiTrack*> (insert->owner());
if (!mt) {
return;
}
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 {
#if 0 // TODO inject directly to plugin..
const int cnt = insert->get_count();
for (int i=0; i < cnt; i++ ) {
boost::shared_ptr<LV2Plugin> lv2i = boost::dynamic_pointer_cast<LV2Plugin> (insert->plugin(i));
//lv2i->write_from_ui(port_index, format, buffer_size, (const uint8_t*)buffer);
}
#endif
}
}
GenericPluginUI::ControlUI::ControlUI (const Evoral::Parameter& p)
: param(p)
, automate_button (X_("")) // force creation of a label

View File

@ -303,6 +303,14 @@ private:
void scroller_size_request (Gtk::Requisition*);
Gtk::ScrolledWindow scroller;
void build_midi_table ();
void midi_refill_patches ();
void midi_bank_patch_change (uint8_t chn);
void midi_bank_patch_select (uint8_t chn, uint32_t bankpgm);
std::vector<ArdourWidgets::ArdourDropdown*> midi_pgmsel;
PBD::ScopedConnectionList midi_connections;
std::map<uint32_t, std::string> pgm_names;
};
class PluginUIWindow : public ArdourWindow