Initial version of MIDI Trigger patch override UI

This commit is contained in:
Robin Gareus 2022-02-08 23:08:23 +01:00
parent f57bef7c93
commit ba32ee0e87
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
4 changed files with 238 additions and 3 deletions

View File

@ -23,14 +23,15 @@
#include "pbd/unwind.h"
#include "evoral/midi_events.h"
#include "evoral/PatchChange.h"
#include "evoral/midi_events.h"
#include "midi++/midnam_patch.h"
#include "ardour/instrument_info.h"
#include "ardour/midi_track.h"
#include "ardour/plugin_insert.h"
#include "ardour/triggerbox.h"
#include "gtkmm2ext/menu_elems.h"
#include "gtkmm2ext/utils.h"
@ -248,6 +249,148 @@ PatchBankList::set_active_pgm (uint8_t p)
/* ****************************************************************************/
PatchChangeTab::PatchChangeTab (boost::shared_ptr<Route> r, boost::shared_ptr<MIDITrigger> t, int channel)
: PatchBankList (r)
, _enable_btn (_("Override Patch Changes"), ArdourWidgets::ArdourButton::led_default_elements)
, _channel (channel)
, _bank (0)
, _ignore_callback (false)
, _trigger (t)
{
if (_trigger->patch_change_set (_channel)) {
_bank = _trigger->patch_change (_channel).bank ();
_enable_btn.set_active (true);
} else {
_enable_btn.set_active (false);
}
Box* box;
box = manage (new HBox ());
box->set_border_width (2);
box->set_spacing (4);
box->pack_start (_enable_btn, false, false);
box->pack_start (*manage (new Label (_("Bank:"))), false, false);
box->pack_start (_bank_select, true, true);
box->pack_start (*manage (new Label (_("MSB:"))), false, false);
box->pack_start (_bank_msb_spin, false, false);
box->pack_start (*manage (new Label (_("LSB:"))), false, false);
box->pack_start (_bank_lsb_spin, false, false);
pack_start (*box, false, false);
_program_table.set_spacings (1);
pack_start (_program_table, true, true);
set_spacing (4);
show_all ();
_enable_btn.signal_clicked.connect (sigc::mem_fun (*this, &PatchChangeTab::enable_toggle));
_trigger->PropertyChanged.connect (_trigger_connection, invalidator (*this), boost::bind (&PatchChangeTab::trigger_property_changed, this, _1), gui_context ());
if (!boost::dynamic_pointer_cast<MidiTrack> (_route)) {
processors_changed ();
}
refill_banks ();
update_sensitivity ();
}
void
PatchChangeTab::enable_toggle ()
{
if (_ignore_callback) {
return;
}
if (_enable_btn.get_active ()) {
_trigger->unset_patch_change (_channel);
} else {
select_program (program ());
}
update_sensitivity ();
}
void
PatchChangeTab::update_sensitivity ()
{
bool en = _trigger->patch_change_set (_channel);
_program_table.set_sensitive (en);
_bank_select.set_sensitive (en);
_bank_msb_spin.set_sensitive (en);
_bank_lsb_spin.set_sensitive (en);
}
void
PatchChangeTab::trigger_property_changed (PBD::PropertyChange const& what_changed)
{
if (what_changed.contains (Properties::patch_change)) {
PBD::Unwinder<bool> uw (_ignore_callback, true);
_enable_btn.set_active (_trigger->patch_change_set (_channel));
refill_banks ();
}
}
void
PatchChangeTab::select_bank (uint32_t bank)
{
_bank = bank;
select_program (program ());
}
void
PatchChangeTab::select_program (uint8_t pgm)
{
if (pgm > 127) {
return;
}
Evoral::PatchChange<MidiBuffer::TimeType> pc (0, _channel, pgm, _bank);
_trigger->set_patch_change (pc);
}
void
PatchChangeTab::refresh ()
{
refill_banks ();
}
void
PatchChangeTab::refill_banks ()
{
refill (_channel);
set_active_pgm (program ());
}
int
PatchChangeTab::bank (uint8_t c) const
{
assert (c == _channel);
if (_trigger->patch_change_set (_channel)) {
return _trigger->patch_change (_channel).bank ();
}
return _bank;
}
uint8_t
PatchChangeTab::program () const
{
if (_trigger->patch_change_set (_channel)) {
return _trigger->patch_change (_channel).program ();
}
return 0;
}
void
PatchChangeTab::instrument_info_changed ()
{
refill_banks ();
}
void
PatchChangeTab::processors_changed ()
{
}
/* ****************************************************************************/
PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
: PatchBankList (r)
, _channel (-1)
@ -277,7 +420,7 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
pack_start (_program_table, true, true);
if (!boost::dynamic_pointer_cast<MidiTrack> (_route)) {
pack_start ( *manage (new Label (_("Note: Patch Selection is volatile (only Midi-Tracks retain bank/patch selection)."))), false, false);
pack_start (*manage (new Label (_("Note: Patch Selection is volatile (only Midi-Tracks retain bank/patch selection)."))), false, false);
}
box = manage (new HBox ());
@ -657,6 +800,29 @@ PatchChangeWidget::program (uint8_t chn) const
/* ***************************************************************************/
PatchChangeTriggerDialog::PatchChangeTriggerDialog (boost::shared_ptr<Route> r, boost::shared_ptr<MIDITrigger> t)
: ArdourDialog (string_compose (_("Select Patch for \"%1\""), t->name ()), false, false)
{
for (uint32_t chn = 0; chn < 16; ++chn) {
_w[chn] = manage (new PatchChangeTab (r, t, chn));
_notebook.append_page (*_w[chn], string_compose (_("Chn %1"), chn + 1));
}
_notebook.signal_switch_page ().connect (sigc::mem_fun (*this, &PatchChangeTriggerDialog::on_switch_page));
_notebook.set_current_page (0);
get_vbox ()->add (_notebook);
_notebook.show_all ();
}
void
PatchChangeTriggerDialog::on_switch_page (GtkNotebookPage*, guint page_num)
{
_w[page_num]->refresh ();
}
/* ***************************************************************************/
PatchChangeGridDialog::PatchChangeGridDialog (boost::shared_ptr<ARDOUR::Route> r)
: ArdourDialog (string_compose (_("Select Patch for \"%1\""), r->name()), false, false)
, w (r)

View File

@ -20,11 +20,12 @@
#define __gtkardour_patch_change_widget_h__
#include <gtkmm/box.h>
#include <gtkmm/notebook.h>
#include <gtkmm/spinbutton.h>
#include <gtkmm/table.h>
#include "pbd/signals.h"
#include "midi++/midnam_patch.h"
#include "pbd/signals.h"
#include "ardour/route.h"
@ -34,6 +35,10 @@
#include "ardour_dialog.h"
#include "pianokeyboard.h"
namespace ARDOUR {
class MIDITrigger;
};
class PatchBankList : virtual public sigc::trackable
{
public:
@ -69,6 +74,39 @@ private:
PBD::ScopedConnection _route_connection;
};
class PatchChangeTab : public Gtk::VBox, public PatchBankList
{
public:
PatchChangeTab (boost::shared_ptr<ARDOUR::Route>, boost::shared_ptr<ARDOUR::MIDITrigger>, int channel);
void refresh ();
protected:
int bank (uint8_t) const;
uint8_t program () const;
/* Implement PatchBankList */
void select_bank (uint32_t);
void select_program (uint8_t);
void instrument_info_changed ();
void processors_changed ();
private:
void refill_banks ();
void trigger_property_changed (PBD::PropertyChange const&);
void enable_toggle ();
void update_sensitivity ();
ArdourWidgets::ArdourButton _enable_btn;
int _channel;
int _bank;
bool _ignore_callback;
boost::shared_ptr<ARDOUR::MIDITrigger> _trigger;
PBD::ScopedConnection _trigger_connection;
};
class PatchChangeWidget : public Gtk::VBox, public PatchBankList
{
public:
@ -129,6 +167,18 @@ private:
void note_off_event_handler (int);
};
class PatchChangeTriggerDialog : public ArdourDialog
{
public:
PatchChangeTriggerDialog (boost::shared_ptr<ARDOUR::Route>, boost::shared_ptr<ARDOUR::MIDITrigger>);
private:
void on_switch_page (GtkNotebookPage*, guint page_num);
Gtk::Notebook _notebook;
PatchChangeTab* _w[16];
};
class PatchChangeGridDialog : public ArdourDialog
{
public:

View File

@ -42,6 +42,7 @@
#include "ardour_ui.h"
#include "gui_thread.h"
#include "keyboard.h"
#include "patch_change_widget.h"
#include "public_editor.h"
#include "region_view.h"
#include "trigger_jump_dialog.h"
@ -201,6 +202,19 @@ TriggerUI::choose_color ()
_color_dialog.hide ();
}
void
TriggerUI::choose_patch ()
{
/* XXX can we get a shared_from (owner()) ? */
SessionObject* obj = trigger ()->box ().owner ();
Session* s = AudioEngine::instance ()->session ();
boost::shared_ptr<Stripable> stripable = s->stripable_by_id (obj->id ());
assert (boost::dynamic_pointer_cast<MIDITrigger> (trigger ()) != 0);
PatchChangeTriggerDialog pcd (boost::dynamic_pointer_cast<Route> (stripable), boost::dynamic_pointer_cast<MIDITrigger> (trigger ()));
pcd.run ();
}
void
TriggerUI::choose_sample (bool allow_multiple_select)
{
@ -442,11 +456,15 @@ TriggerUI::context_menu ()
#if DOUBLE_CLICK_IS_NOT_OBVIOUS_ENOUGH
items.push_back (MenuElem (_("Edit..."), sigc::mem_fun (*this, &TriggerUI::edit_trigger)));
#endif
if (boost::dynamic_pointer_cast<MIDITrigger> (trigger ())) {
items.push_back (MenuElem (_("Select Patch.."), sigc::mem_fun (*this, &TriggerUI::choose_patch)));
}
items.push_back (SeparatorElem());
items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &TriggerUI::choose_color)));
items.push_back (SeparatorElem());
items.push_back (MenuElem (_("Clear"), sigc::mem_fun (*this, &TriggerUI::clear_trigger)));
_context_menu->popup (1, gtk_get_current_event_time ());
}

View File

@ -69,6 +69,7 @@ public:
ARDOUR::TriggerBox& triggerbox() const { return trigger()->box(); }
void choose_color ();
void choose_patch ();
void choose_sample (bool allow_multiple_select);
void sample_chosen (int r);