MIDI-Tracer: allow to directly trace physical ports
This commit is contained in:
parent
78ec9294e1
commit
0be3a509af
@ -46,6 +46,7 @@ using namespace Gtk;
|
||||
using namespace std;
|
||||
using namespace MIDI;
|
||||
using namespace Glib;
|
||||
using namespace ARDOUR;
|
||||
|
||||
MidiTracer::MidiTracer ()
|
||||
: ArdourWindow (_("MIDI Tracer"))
|
||||
@ -65,7 +66,15 @@ MidiTracer::MidiTracer ()
|
||||
{
|
||||
g_atomic_int_set (&_update_queued, 0);
|
||||
|
||||
ARDOUR::AudioEngine::instance()->PortRegisteredOrUnregistered.connect
|
||||
std::string portname (string_compose(X_("x-MIDI-tracer-%1"), ++window_count));
|
||||
boost::shared_ptr<ARDOUR::Port> port = AudioEngine::instance()->register_input_port (DataType::MIDI, portname, false, PortFlags (IsInput | Hidden | IsTerminal));
|
||||
tracer_port = boost::dynamic_pointer_cast<MidiPort> (port);
|
||||
|
||||
_midi_port_list = ListStore::create (_midi_port_cols);
|
||||
_midi_port_combo.set_model (_midi_port_list);
|
||||
_midi_port_combo.pack_start (_midi_port_cols.pretty_name);
|
||||
|
||||
AudioEngine::instance()->PortRegisteredOrUnregistered.connect
|
||||
(_manager_connection, invalidator (*this), boost::bind (&MidiTracer::ports_changed, this), gui_context());
|
||||
|
||||
VBox* vbox = manage (new VBox);
|
||||
@ -75,8 +84,8 @@ MidiTracer::MidiTracer ()
|
||||
pbox->set_spacing (6);
|
||||
pbox->pack_start (*manage (new Label (_("Port:"))), false, false);
|
||||
|
||||
_port_combo.signal_changed().connect (sigc::mem_fun (*this, &MidiTracer::port_changed));
|
||||
pbox->pack_start (_port_combo);
|
||||
_midi_port_combo.signal_changed().connect (sigc::mem_fun (*this, &MidiTracer::port_changed));
|
||||
pbox->pack_start (_midi_port_combo);
|
||||
pbox->show_all ();
|
||||
vbox->pack_start (*pbox, false, false);
|
||||
|
||||
@ -129,6 +138,7 @@ MidiTracer::MidiTracer ()
|
||||
MidiTracer::~MidiTracer()
|
||||
{
|
||||
disconnect ();
|
||||
AudioEngine::instance ()->unregister_port (tracer_port);
|
||||
}
|
||||
|
||||
void
|
||||
@ -148,25 +158,64 @@ MidiTracer::on_hide ()
|
||||
void
|
||||
MidiTracer::ports_changed ()
|
||||
{
|
||||
string const c = _port_combo.get_active_text ();
|
||||
_port_combo.clear ();
|
||||
|
||||
ARDOUR::PortManager::PortList pl;
|
||||
ARDOUR::AudioEngine::instance()->get_ports (ARDOUR::DataType::MIDI, pl);
|
||||
|
||||
if (pl.empty()) {
|
||||
_port_combo.set_active_text ("");
|
||||
return;
|
||||
TreeModel::iterator r = _midi_port_combo.get_active ();
|
||||
string cpn;
|
||||
if (r) {
|
||||
cpn = (*r)[_midi_port_cols.port_name];
|
||||
}
|
||||
|
||||
for (ARDOUR::PortManager::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
|
||||
_port_combo.append ((*i)->name());
|
||||
_midi_port_list->clear ();
|
||||
|
||||
PortManager::PortList pl;
|
||||
AudioEngine::instance()->get_ports (DataType::MIDI, pl);
|
||||
|
||||
std::vector<std::string> pp;
|
||||
AudioEngine::instance ()->get_physical_inputs (DataType::MIDI, pp, MidiPortFlags (0), MidiPortFlags (MidiPortControl | MidiPortVirtual));
|
||||
/* ideally we'd also list external (JACK) ports
|
||||
* however there is no convenient API
|
||||
* `PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)`
|
||||
* lists ALL ports and we'd need to filter any outputs (sinks), except our own sinks (which can be traced).
|
||||
*/
|
||||
|
||||
size_t nth = 0;
|
||||
size_t act = 0;
|
||||
|
||||
/* physical I/Os first */
|
||||
for (auto const& pn : pp) {
|
||||
if (!cpn.empty () && pn == cpn) {
|
||||
act = nth;
|
||||
}
|
||||
++nth;
|
||||
std::string ppn = AudioEngine::instance()->get_pretty_name_by_name (pn);
|
||||
if (ppn.empty ()) {
|
||||
ppn = pn.substr (pn.find (':') + 1);
|
||||
}
|
||||
TreeModel::Row row = *_midi_port_list->append ();
|
||||
row[_midi_port_cols.pretty_name] = string_compose (_("HW: %1"), ppn);
|
||||
row[_midi_port_cols.port_name] = pn;
|
||||
}
|
||||
|
||||
if (c.empty()) {
|
||||
_port_combo.set_active_text (pl.front()->name());
|
||||
} else {
|
||||
_port_combo.set_active_text (c);
|
||||
/* Ardour owned ports */
|
||||
for (auto const& p : pl) {
|
||||
if (p->flags() & Hidden) {
|
||||
continue;
|
||||
}
|
||||
std::string const& pn = p->name ();
|
||||
if (!cpn.empty () && pn == cpn) {
|
||||
act = nth;
|
||||
}
|
||||
++nth;
|
||||
std::string ppn = p->pretty_name (false);
|
||||
if (ppn.empty ()) {
|
||||
ppn = pn.substr (pn.find (':') + 1);
|
||||
}
|
||||
TreeModel::Row row = *_midi_port_list->append ();
|
||||
row[_midi_port_cols.pretty_name] = ppn;
|
||||
row[_midi_port_cols.port_name] = pn;
|
||||
}
|
||||
|
||||
if (nth > 0) {
|
||||
_midi_port_combo.set_active (act);
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,17 +226,29 @@ MidiTracer::port_changed ()
|
||||
|
||||
disconnect ();
|
||||
|
||||
if (_port_combo.get_active_text().empty()) {
|
||||
TreeModel::iterator r = _midi_port_combo.get_active ();
|
||||
if (!r) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<ARDOUR::Port> p = AudioEngine::instance()->get_port_by_name (_port_combo.get_active_text());
|
||||
std::string const pn = (*r)[_midi_port_cols.port_name];
|
||||
|
||||
boost::shared_ptr<ARDOUR::Port> p = AudioEngine::instance()->get_port_by_name (pn);
|
||||
|
||||
if (!p) {
|
||||
std::cerr << "port not found: " << _port_combo.get_active_text() << "\n";
|
||||
/* connect to external port */
|
||||
if (0 == tracer_port->connect (pn)) {
|
||||
_midi_parser = boost::shared_ptr<MIDI::Parser> (new MIDI::Parser);
|
||||
_midi_parser->any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3, _4));
|
||||
tracer_port->set_trace (_midi_parser.get ());
|
||||
} else {
|
||||
std::cerr << "CANNOT TRACE PORT " << pn << "\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<MidiPort> mp = boost::dynamic_pointer_cast<MidiPort> (p);
|
||||
|
||||
/* The inheritance hierarchy makes this messy. AsyncMIDIPort has two
|
||||
* available MIDI::Parsers what we could connect to, ::self_parser()
|
||||
* (from ARDOUR::MidiPort) and ::parser() from MIDI::Port. One day,
|
||||
@ -203,7 +264,7 @@ MidiTracer::port_changed ()
|
||||
|
||||
if (!async) {
|
||||
|
||||
boost::shared_ptr<ARDOUR::MidiPort> mp = boost::dynamic_pointer_cast<ARDOUR::MidiPort> (p);
|
||||
boost::shared_ptr<MidiPort> mp = boost::dynamic_pointer_cast<MidiPort> (p);
|
||||
if (mp) {
|
||||
if (mp->flags() & TransportMasterPort) {
|
||||
boost::shared_ptr<TransportMaster> tm = TransportMasterManager::instance().master_by_port(boost::dynamic_pointer_cast<ARDOUR::Port> (p));
|
||||
@ -211,10 +272,10 @@ MidiTracer::port_changed ()
|
||||
if (tm_midi) {
|
||||
tm_midi->transport_parser().any.connect_same_thread(_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3, _4));
|
||||
}
|
||||
}
|
||||
else {
|
||||
my_parser.any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3, _4));
|
||||
mp->set_trace (&my_parser);
|
||||
} else {
|
||||
_midi_parser = boost::shared_ptr<MIDI::Parser> (new MIDI::Parser);
|
||||
_midi_parser->any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3, _4));
|
||||
mp->set_trace (_midi_parser.get ());
|
||||
traced_port = mp;
|
||||
}
|
||||
}
|
||||
@ -229,10 +290,14 @@ MidiTracer::disconnect ()
|
||||
{
|
||||
_parser_connection.disconnect ();
|
||||
|
||||
tracer_port->disconnect_all ();
|
||||
tracer_port->set_trace (0);
|
||||
|
||||
if (traced_port) {
|
||||
traced_port->set_trace (0);
|
||||
traced_port.reset ();
|
||||
}
|
||||
_midi_parser.reset ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <gtkmm/adjustment.h>
|
||||
#include <gtkmm/spinbutton.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/liststore.h>
|
||||
#include <gtkmm/comboboxtext.h>
|
||||
#include <gtkmm/box.h>
|
||||
|
||||
@ -87,7 +88,22 @@ private:
|
||||
Gtk::CheckButton base_button;
|
||||
Gtk::CheckButton collect_button;
|
||||
Gtk::CheckButton delta_time_button;
|
||||
Gtk::ComboBoxText _port_combo;
|
||||
Gtk::ComboBox _midi_port_combo;
|
||||
|
||||
class MidiPortCols : public Gtk::TreeModelColumnRecord
|
||||
{
|
||||
public:
|
||||
MidiPortCols ()
|
||||
{
|
||||
add (pretty_name);
|
||||
add (port_name);
|
||||
}
|
||||
Gtk::TreeModelColumn<std::string> pretty_name;
|
||||
Gtk::TreeModelColumn<std::string> port_name;
|
||||
};
|
||||
|
||||
MidiPortCols _midi_port_cols;
|
||||
Glib::RefPtr<Gtk::ListStore> _midi_port_list;
|
||||
|
||||
void base_toggle ();
|
||||
void autoscroll_toggle ();
|
||||
@ -99,8 +115,9 @@ private:
|
||||
void disconnect ();
|
||||
PBD::ScopedConnection _parser_connection;
|
||||
PBD::ScopedConnection _manager_connection;
|
||||
MIDI::Parser my_parser;
|
||||
boost::shared_ptr<MIDI::Parser> _midi_parser;
|
||||
|
||||
boost::shared_ptr<ARDOUR::MidiPort> tracer_port;
|
||||
boost::shared_ptr<ARDOUR::MidiPort> traced_port;
|
||||
|
||||
static unsigned int window_count;
|
||||
|
Loading…
Reference in New Issue
Block a user