Prepare PatchChangeWidget for Midi-Busses (use instrument-plugin)

This commit is contained in:
Robin Gareus 2017-09-09 18:17:42 +02:00
parent ba2114644d
commit 9e2251a619
2 changed files with 143 additions and 68 deletions

View file

@ -29,6 +29,7 @@
#include "ardour/instrument_info.h" #include "ardour/instrument_info.h"
#include "ardour/midi_track.h" #include "ardour/midi_track.h"
#include "ardour/plugin_insert.h"
#include "gtkmm2ext/menu_elems.h" #include "gtkmm2ext/menu_elems.h"
#include "widgets/tooltips.h" #include "widgets/tooltips.h"
@ -49,6 +50,7 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
, _program_table (/*rows*/ 16, /*cols*/ 8, true) , _program_table (/*rows*/ 16, /*cols*/ 8, true)
, _channel (-1) , _channel (-1)
, _ignore_spin_btn_signals (false) , _ignore_spin_btn_signals (false)
, _no_notifications (false)
, _info (r->instrument_info ()) , _info (r->instrument_info ())
, _audition_enable (_("Audition on Change"), ArdourWidgets::ArdourButton::led_default_elements) , _audition_enable (_("Audition on Change"), ArdourWidgets::ArdourButton::led_default_elements)
, _audition_start_spin (*manage (new Adjustment (48, 0, 127, 1, 16))) , _audition_start_spin (*manage (new Adjustment (48, 0, 127, 1, 16)))
@ -76,23 +78,25 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
_program_table.set_spacings (1); _program_table.set_spacings (1);
pack_start (_program_table, true, true); pack_start (_program_table, true, true);
if (boost::dynamic_pointer_cast<MidiTrack> (_route)) { if (!boost::dynamic_pointer_cast<MidiTrack> (_route)) {
box = manage (new HBox ()); pack_start ( *manage (new Label (_("Note: Patch Selection is volatile (only Midi-Tracks retain bank/patch selection)."))), false, false);
box->set_spacing (4);
box->pack_start (_audition_enable, false, false);
box->pack_start (*manage (new Label (_("Start Note:"))), false, false);
box->pack_start (_audition_start_spin, false, false);
box->pack_start (*manage (new Label (_("End Note:"))), false, false);
box->pack_start (_audition_end_spin, false, false);
box->pack_start (*manage (new Label (_("Velocity:"))), false, false);
box->pack_start (_audition_velocity, false, false);
Box* box2 = manage (new HBox ());
box2->pack_start (*box, true, false);
box2->set_border_width (2);
pack_start (*box2, false, false);
} }
box = manage (new HBox ());
box->set_spacing (4);
box->pack_start (_audition_enable, false, false);
box->pack_start (*manage (new Label (_("Start Note:"))), false, false);
box->pack_start (_audition_start_spin, false, false);
box->pack_start (*manage (new Label (_("End Note:"))), false, false);
box->pack_start (_audition_end_spin, false, false);
box->pack_start (*manage (new Label (_("Velocity:"))), false, false);
box->pack_start (_audition_velocity, false, false);
Box* box2 = manage (new HBox ());
box2->pack_start (*box, true, false);
box2->set_border_width (2);
pack_start (*box2, false, false);
for (uint8_t pgm = 0; pgm < 128; ++pgm) { for (uint8_t pgm = 0; pgm < 128; ++pgm) {
_program_btn[pgm].set_text_ellipsize (Pango::ELLIPSIZE_END); _program_btn[pgm].set_text_ellipsize (Pango::ELLIPSIZE_END);
_program_btn[pgm].set_layout_ellipsize_width (PANGO_SCALE * 112 * UIConfiguration::instance ().get_ui_scale ()); _program_btn[pgm].set_layout_ellipsize_width (PANGO_SCALE * 112 * UIConfiguration::instance ().get_ui_scale ());
@ -110,13 +114,11 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
_channel_select.AddMenuElem (MenuElemNoMnemonic (buf, sigc::bind (sigc::mem_fun (*this, &PatchChangeWidget::select_channel), chn))); _channel_select.AddMenuElem (MenuElemNoMnemonic (buf, sigc::bind (sigc::mem_fun (*this, &PatchChangeWidget::select_channel), chn)));
} }
if (boost::dynamic_pointer_cast<MidiTrack> (_route)) { piano_keyboard_set_monophonic (_piano, TRUE);
piano_keyboard_set_monophonic (_piano, TRUE); g_signal_connect (G_OBJECT (_piano), "note-on", G_CALLBACK (PatchChangeWidget::_note_on_event_handler), this);
g_signal_connect (G_OBJECT (_piano), "note-on", G_CALLBACK (PatchChangeWidget::_note_on_event_handler), this); g_signal_connect (G_OBJECT (_piano), "note-off", G_CALLBACK (PatchChangeWidget::_note_off_event_handler), this);
g_signal_connect (G_OBJECT (_piano), "note-off", G_CALLBACK (PatchChangeWidget::_note_off_event_handler), this); _pianomm->set_flags(Gtk::CAN_FOCUS);
_pianomm->set_flags(Gtk::CAN_FOCUS); pack_start (*_pianomm, false, false);
pack_start (*_pianomm, false, false);
}
_audition_start_spin.set_sensitive (false); _audition_start_spin.set_sensitive (false);
_audition_end_spin.set_sensitive (false); _audition_end_spin.set_sensitive (false);
@ -130,6 +132,12 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
_info.Changed.connect (_info_changed_connection, invalidator (*this), _info.Changed.connect (_info_changed_connection, invalidator (*this),
boost::bind (&PatchChangeWidget::instrument_info_changed, this), gui_context()); boost::bind (&PatchChangeWidget::instrument_info_changed, this), gui_context());
if (!boost::dynamic_pointer_cast<MidiTrack> (_route)) {
_route->processors_changed.connect (_route_connection, invalidator (*this),
boost::bind (&PatchChangeWidget::processors_changed, this), gui_context());
processors_changed ();
}
set_spacing (4); set_spacing (4);
show_all (); show_all ();
} }
@ -179,19 +187,30 @@ PatchChangeWidget::select_channel (uint8_t chn)
_channel_select.set_text (string_compose ("%1", (int)(chn + 1))); _channel_select.set_text (string_compose ("%1", (int)(chn + 1)));
_channel = chn; _channel = chn;
_no_notifications = false;
_ac_connections.drop_connections (); _ac_connections.drop_connections ();
boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true); if (boost::dynamic_pointer_cast<MidiTrack> (_route)) {
boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true); boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true);
boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true); boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true);
boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true);
bank_msb->Changed.connect (_ac_connections, invalidator (*this), bank_msb->Changed.connect (_ac_connections, invalidator (*this),
boost::bind (&PatchChangeWidget::bank_changed, this), gui_context ()); boost::bind (&PatchChangeWidget::bank_changed, this), gui_context ());
bank_lsb->Changed.connect (_ac_connections, invalidator (*this), bank_lsb->Changed.connect (_ac_connections, invalidator (*this),
boost::bind (&PatchChangeWidget::bank_changed, this), gui_context ()); boost::bind (&PatchChangeWidget::bank_changed, this), gui_context ());
program->Changed.connect (_ac_connections, invalidator (*this), program->Changed.connect (_ac_connections, invalidator (*this),
boost::bind (&PatchChangeWidget::program_changed, this), gui_context ()); boost::bind (&PatchChangeWidget::program_changed, this), gui_context ());
} else if (boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument())) {
if (pi->plugin()->knows_bank_patch ()) {
pi->plugin ()->BankPatchChange.connect (_ac_connections, invalidator (*this),
boost::bind (&PatchChangeWidget::bankpatch_changed, this, _1), gui_context ());
} else {
_no_notifications = true;
// TODO add note: instrument does not report changes.
}
}
refill_banks (); refill_banks ();
} }
@ -285,11 +304,24 @@ PatchChangeWidget::select_bank (uint32_t bank)
{ {
cancel_audition (); cancel_audition ();
boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, _channel, MIDI_CTL_MSB_BANK), true); if (boost::dynamic_pointer_cast<MidiTrack> (_route)) {
boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, _channel, MIDI_CTL_LSB_BANK), true); boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, _channel, MIDI_CTL_MSB_BANK), true);
boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, _channel, MIDI_CTL_LSB_BANK), true);
bank_msb->set_value (bank >> 7, PBD::Controllable::NoGroup);
bank_lsb->set_value (bank & 127, PBD::Controllable::NoGroup);
} else if (boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument())) {
uint8_t event[3];
event[0] = (MIDI_CMD_CONTROL | _channel);
event[1] = 0x00;
event[2] = bank >> 7;
pi->write_immediate_event (3, event);
event[1] = 0x20;
event[2] = bank & 127;
pi->write_immediate_event (3, event);
}
bank_msb->set_value (bank >> 7, PBD::Controllable::NoGroup);
bank_lsb->set_value (bank & 127, PBD::Controllable::NoGroup);
select_program (program (_channel)); select_program (program (_channel));
} }
@ -297,9 +329,23 @@ void
PatchChangeWidget::select_program (uint8_t pgm) PatchChangeWidget::select_program (uint8_t pgm)
{ {
cancel_audition (); cancel_audition ();
if (_no_notifications) {
program_changed ();
}
boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, _channel), true); if (pgm > 127) {
program->set_value (pgm, PBD::Controllable::NoGroup); return;
}
if (boost::dynamic_pointer_cast<MidiTrack> (_route)) {
boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, _channel), true);
program->set_value (pgm, PBD::Controllable::NoGroup);
} else if (boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument())) {
uint8_t event[2];
event[0] = (MIDI_CMD_PGM_CHANGE | _channel);
event[1] = pgm;
pi->write_immediate_event (2, event);
}
audition (); audition ();
} }
@ -312,6 +358,14 @@ PatchChangeWidget::bank_changed ()
refill_banks (); refill_banks ();
} }
void
PatchChangeWidget::bankpatch_changed (uint8_t chn)
{
if (chn == _channel) {
refill_banks ();
}
}
void void
PatchChangeWidget::program_changed () PatchChangeWidget::program_changed ()
{ {
@ -327,6 +381,17 @@ PatchChangeWidget::instrument_info_changed ()
refill_banks (); refill_banks ();
} }
void
PatchChangeWidget::processors_changed ()
{
assert (!boost::dynamic_pointer_cast<MidiTrack> (_route));
if (_route->the_instrument ()) {
set_sensitive (true);
} else {
set_sensitive (false);
}
}
/* ***** play notes *****/ /* ***** play notes *****/
void void
@ -364,22 +429,15 @@ PatchChangeWidget::cancel_audition ()
_note_queue_connection.disconnect(); _note_queue_connection.disconnect();
if (_audition_note_on) { if (_audition_note_on) {
boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (_route); note_off_event_handler (_audition_note_num);
uint8_t event[3];
event[0] = (MIDI_CMD_NOTE_OFF | _channel);
event[1] = _audition_note_num;
event[2] = 0;
mt->write_immediate_event (3, event);
piano_keyboard_set_note_off (_piano, _audition_note_num); piano_keyboard_set_note_off (_piano, _audition_note_num);
} }
_audition_note_on = false;
} }
void void
PatchChangeWidget::audition () PatchChangeWidget::audition ()
{ {
if (!boost::dynamic_pointer_cast<MidiTrack> (_route)) { if (!boost::dynamic_pointer_cast<MidiTrack> (_route) && !boost::dynamic_pointer_cast<PluginInsert> (_route)) {
return; return;
} }
if (_channel > 16) { if (_channel > 16) {
@ -403,23 +461,12 @@ PatchChangeWidget::audition ()
bool bool
PatchChangeWidget::audition_next () PatchChangeWidget::audition_next ()
{ {
boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (_route);
uint8_t event[3];
if (_audition_note_on) { if (_audition_note_on) {
event[0] = (MIDI_CMD_NOTE_OFF | _channel); note_off_event_handler (_audition_note_num);
event[1] = _audition_note_num;
event[2] = 0;
mt->write_immediate_event (3, event);
_audition_note_on = false;
piano_keyboard_set_note_off (_piano, _audition_note_num); piano_keyboard_set_note_off (_piano, _audition_note_num);
return ++_audition_note_num <= _audition_end_spin.get_value_as_int() && _audition_enable.get_active (); return ++_audition_note_num <= _audition_end_spin.get_value_as_int() && _audition_enable.get_active ();
} else { } else {
event[0] = (MIDI_CMD_NOTE_ON | _channel); note_on_event_handler (_audition_note_num);
event[1] = _audition_note_num;
event[2] = _audition_velocity.get_value_as_int ();
mt->write_immediate_event (3, event);
_audition_note_on = true;
piano_keyboard_set_note_on (_piano, _audition_note_num); piano_keyboard_set_note_on (_piano, _audition_note_num);
return true; return true;
} }
@ -442,26 +489,34 @@ PatchChangeWidget::note_on_event_handler (int note)
{ {
cancel_audition (); cancel_audition ();
_pianomm->grab_focus (); _pianomm->grab_focus ();
boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (_route);
uint8_t event[3]; uint8_t event[3];
event[0] = (MIDI_CMD_NOTE_ON | _channel); event[0] = (MIDI_CMD_NOTE_ON | _channel);
event[1] = note; event[1] = note;
event[2] = _audition_velocity.get_value_as_int (); event[2] = _audition_velocity.get_value_as_int ();
mt->write_immediate_event (3, event);
_audition_note_on = true; _audition_note_on = true;
_audition_note_num = note; _audition_note_num = note;
if (boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (_route)) {
mt->write_immediate_event (3, event);
} else if (boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument())) {
pi->write_immediate_event (3, event);
}
} }
void void
PatchChangeWidget::note_off_event_handler (int note) PatchChangeWidget::note_off_event_handler (int note)
{ {
boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (_route);
uint8_t event[3]; uint8_t event[3];
event[0] = (MIDI_CMD_NOTE_OFF | _channel); event[0] = (MIDI_CMD_NOTE_OFF | _channel);
event[1] = note; event[1] = note;
event[2] = 0; event[2] = 0;
mt->write_immediate_event (3, event);
_audition_note_on = false; _audition_note_on = false;
if (boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (_route)) {
mt->write_immediate_event (3, event);
} else if (boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument())) {
pi->write_immediate_event (3, event);
}
} }
/* ***** query info *****/ /* ***** query info *****/
@ -469,17 +524,33 @@ PatchChangeWidget::note_off_event_handler (int note)
int int
PatchChangeWidget::bank (uint8_t chn) const PatchChangeWidget::bank (uint8_t chn) const
{ {
boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true); if (boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (_route)) {
boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true); boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true);
boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true);
return ((int)bank_msb->get_value () << 7) + (int)bank_lsb->get_value(); return ((int)bank_msb->get_value () << 7) + (int)bank_lsb->get_value();
} else if (boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument())) {
uint32_t bankpatch = pi->plugin()->bank_patch (chn);
if (bankpatch != UINT32_MAX) {
return bankpatch >> 7;
}
}
return 0;
} }
uint8_t uint8_t
PatchChangeWidget::program (uint8_t chn) const PatchChangeWidget::program (uint8_t chn) const
{ {
boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true); if (boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (_route)) {
return program->get_value(); boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true);
return program->get_value();
} else if (boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument())) {
uint32_t bankpatch = pi->plugin()->bank_patch (chn);
if (bankpatch != UINT32_MAX) {
return bankpatch & 127;
}
}
return 255;
} }
/* ***************************************************************************/ /* ***************************************************************************/

View file

@ -24,6 +24,7 @@
#include <gtkmm/table.h> #include <gtkmm/table.h>
#include "pbd/signals.h" #include "pbd/signals.h"
#include "midi++/midnam_patch.h"
#include "ardour/route.h" #include "ardour/route.h"
@ -60,6 +61,7 @@ private:
uint8_t _channel; uint8_t _channel;
bool _ignore_spin_btn_signals; bool _ignore_spin_btn_signals;
bool _no_notifications;
void select_channel (uint8_t); void select_channel (uint8_t);
void select_bank (uint32_t); void select_bank (uint32_t);
@ -68,11 +70,13 @@ private:
void bank_changed (); void bank_changed ();
void program_changed (); void program_changed ();
void bankpatch_changed (uint8_t);
void refill_banks (); void refill_banks ();
void refill_program_list (); void refill_program_list ();
void instrument_info_changed (); void instrument_info_changed ();
void processors_changed ();
PBD::ScopedConnection _info_changed_connection; PBD::ScopedConnection _info_changed_connection;
PBD::ScopedConnection _route_connection; PBD::ScopedConnection _route_connection;