13
0

GenericMidi: Partially working IO selectors.

2 remaining problems:
*  IO selectors are not updated if you change the connection outside the dialog.
*  occasional crash on the next startup, after a connection is made from the menu.
This commit is contained in:
Ben Loftis 2015-12-02 18:31:43 -06:00
parent e1064701a5
commit 16a100703b
2 changed files with 190 additions and 3 deletions

View File

@ -24,6 +24,7 @@
#include <glibmm/threads.h>
#include "ardour/types.h"
#include "ardour/port.h"
#include "control_protocol/control_protocol.h"
@ -53,8 +54,9 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
int set_active (bool yn);
static bool probe() { return true; }
MIDI::Port* input_port () const { return _input_port; }
MIDI::Port* output_port () const { return _output_port; }
ARDOUR::Port* input_port () const { return ((ARDOUR::Port*) _input_port); }
ARDOUR::Port* output_port () const { return ((ARDOUR::Port*) _output_port); }
void set_feedback_interval (ARDOUR::microseconds_t);
int set_feedback (bool yn);
@ -100,6 +102,7 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
return _threshold;
}
PBD::Signal0<void> ConnectionChange;
private:
MIDI::Port* _input_port;
MIDI::Port* _output_port;

View File

@ -27,8 +27,16 @@
#include <gtkmm/adjustment.h>
#include <gtkmm/spinbutton.h>
#include <gtkmm/table.h>
#include <gtkmm/liststore.h>
#include "pbd/unwind.h"
#include "ardour/audioengine.h"
#include "ardour/port.h"
#include "ardour/midi_port.h"
#include "gtkmm2ext/gtk_ui.h"
#include "gtkmm2ext/gui_thread.h"
#include "gtkmm2ext/utils.h"
#include "generic_midi_control_protocol.h"
@ -50,10 +58,32 @@ private:
Gtk::Adjustment threshold_adjustment;
Gtk::SpinButton threshold_spinner;
Gtk::ComboBox input_combo;
Gtk::ComboBox output_combo;
void binding_changed ();
void bank_changed ();
void motorised_changed ();
void threshold_changed ();
void update_port_combos ();
PBD::ScopedConnection connection_change_connection;
void connection_handler ();
struct MidiPortColumns : public Gtk::TreeModel::ColumnRecord {
MidiPortColumns() {
add (short_name);
add (full_name);
}
Gtk::TreeModelColumn<std::string> short_name;
Gtk::TreeModelColumn<std::string> full_name;
};
MidiPortColumns midi_port_columns;
bool ignore_active_change;
Glib::RefPtr<Gtk::ListStore> build_midi_port_list (std::vector<std::string> const & ports, bool for_input);
void active_port_changed (Gtk::ComboBox*,bool for_input);
};
using namespace PBD;
@ -129,7 +159,29 @@ GMCPGUI::GMCPGUI (GenericMidiControlProtocol& p)
int n = 0;
Label* label = manage (new Label (_("MIDI Bindings:")));
// MIDI input and output selectors
input_combo.pack_start (midi_port_columns.short_name);
output_combo.pack_start (midi_port_columns.short_name);
input_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &GMCPGUI::active_port_changed), &input_combo, true));
output_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &GMCPGUI::active_port_changed), &output_combo, false));
Label* label = manage (new Gtk::Label);
label->set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Incoming MIDI on:")));
label->set_alignment (1.0, 0.5);
table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
table->attach (input_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
n++;
label = manage (new Gtk::Label);
label->set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Outgoing MIDI on:")));
label->set_alignment (1.0, 0.5);
table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
table->attach (output_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
n++;
//MIDI binding file selector...
label = manage (new Label (_("MIDI Bindings:")));
label->set_alignment (0, 0.5);
table->attach (*label, 0, 1, n, n + 1);
table->attach (map_combo, 1, 2, n, n + 1);
@ -173,6 +225,14 @@ GMCPGUI::GMCPGUI (GenericMidiControlProtocol& p)
pack_start (*table, false, false);
binding_changed ();
/* update the port connection combos */
update_port_combos ();
/* catch future changes to connection state */
cp.ConnectionChange.connect (connection_change_connection, invalidator (*this), boost::bind (&GMCPGUI::connection_handler, this), gui_context());
}
GMCPGUI::~GMCPGUI ()
@ -216,3 +276,127 @@ GMCPGUI::threshold_changed ()
{
cp.set_threshold (threshold_adjustment.get_value());
}
void
GMCPGUI::connection_handler ()
{
/* ignore all changes to combobox active strings here, because we're
updating them to match a new ("external") reality - we were called
because port connections have changed.
*/
PBD::Unwinder<bool> ici (ignore_active_change, true);
update_port_combos ();
}
void
GMCPGUI::update_port_combos ()
{
vector<string> midi_inputs;
vector<string> midi_outputs;
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsTerminal), midi_inputs);
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsTerminal), midi_outputs);
Glib::RefPtr<Gtk::ListStore> input = build_midi_port_list (midi_inputs, true);
Glib::RefPtr<Gtk::ListStore> output = build_midi_port_list (midi_outputs, false);
bool input_found = false;
bool output_found = false;
int n;
input_combo.set_model (input);
output_combo.set_model (output);
Gtk::TreeModel::Children children = input->children();
Gtk::TreeModel::Children::iterator i;
i = children.begin();
++i; /* skip "Disconnected" */
for (n = 1; i != children.end(); ++i, ++n) {
string port_name = (*i)[midi_port_columns.full_name];
if (cp.input_port()->connected_to (port_name)) {
input_combo.set_active (n);
input_found = true;
break;
}
}
if (!input_found) {
input_combo.set_active (0); /* disconnected */
}
children = output->children();
i = children.begin();
++i; /* skip "Disconnected" */
for (n = 1; i != children.end(); ++i, ++n) {
string port_name = (*i)[midi_port_columns.full_name];
if (cp.output_port()->connected_to (port_name)) {
output_combo.set_active (n);
output_found = true;
break;
}
}
if (!output_found) {
output_combo.set_active (0); /* disconnected */
}
}
Glib::RefPtr<Gtk::ListStore>
GMCPGUI::build_midi_port_list (vector<string> const & ports, bool for_input)
{
Glib::RefPtr<Gtk::ListStore> store = ListStore::create (midi_port_columns);
TreeModel::Row row;
row = *store->append ();
row[midi_port_columns.full_name] = string();
row[midi_port_columns.short_name] = _("Disconnected");
for (vector<string>::const_iterator p = ports.begin(); p != ports.end(); ++p) {
row = *store->append ();
row[midi_port_columns.full_name] = *p;
std::string pn = ARDOUR::AudioEngine::instance()->get_pretty_name_by_name (*p);
if (pn.empty ()) {
pn = (*p).substr ((*p).find (':') + 1);
}
row[midi_port_columns.short_name] = pn;
}
return store;
}
void
GMCPGUI::active_port_changed (Gtk::ComboBox* combo, bool for_input)
{
if (ignore_active_change) {
return;
}
TreeModel::iterator active = combo->get_active ();
string new_port = (*active)[midi_port_columns.full_name];
if (new_port.empty()) {
if (for_input) {
cp.input_port()->disconnect_all ();
} else {
cp.output_port()->disconnect_all ();
}
return;
}
if (for_input) {
if (!cp.input_port()->connected_to (new_port)) {
cp.input_port()->disconnect_all ();
cp.input_port()->connect (new_port);
}
} else {
if (!cp.output_port()->connected_to (new_port)) {
cp.output_port()->disconnect_all ();
cp.output_port()->connect (new_port);
}
}
}