diff options
25 files changed, 614 insertions, 195 deletions
diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript index d215470b52..06ecf2d0f2 100644 --- a/gtk2_ardour/SConscript +++ b/gtk2_ardour/SConscript @@ -100,6 +100,7 @@ control_point.cc automation_line.cc automation_time_axis.cc automation_controller.cc +midi_port_dialog.cc midi_time_axis.cc midi_streamview.cc axis_view.cc diff --git a/gtk2_ardour/midi_port_dialog.cc b/gtk2_ardour/midi_port_dialog.cc new file mode 100644 index 0000000000..2bb686d70b --- /dev/null +++ b/gtk2_ardour/midi_port_dialog.cc @@ -0,0 +1,55 @@ +#include <string> +#include <sigc++/bind.h> +#include <gtkmm/stock.h> + +#include <pbd/convert.h> +#include <gtkmm2ext/utils.h> + +#include "midi_port_dialog.h" + +#include "i18n.h" + +using namespace std; +using namespace PBD; +using namespace Gtk; +using namespace Gtkmm2ext; +using namespace sigc; + +static const char* mode_strings[] = { "duplex", "output", "input", (char*) 0 }; + +MidiPortDialog::MidiPortDialog () + : ArdourDialog ("midi_port_dialog"), + port_label (_("Port name")) + +{ + vector<string> str = internationalize (PACKAGE, mode_strings); + set_popdown_strings (port_mode_combo, str); + port_mode_combo.set_active_text (str.front()); + + hpacker.pack_start (port_label); + hpacker.pack_start (port_name); + hpacker.pack_start (port_mode_combo); + + port_label.show (); + port_name.show (); + port_mode_combo.show (); + hpacker.show (); + + get_vbox()->pack_start (hpacker); + + port_name.signal_activate().connect (mem_fun (*this, &MidiPortDialog::entry_activated)); + + add_button (Stock::ADD, RESPONSE_ACCEPT); + add_button (Stock::CANCEL, RESPONSE_CANCEL); +} + +void +MidiPortDialog::entry_activated () +{ + response (RESPONSE_ACCEPT); +} + +MidiPortDialog::~MidiPortDialog () +{ + +} diff --git a/gtk2_ardour/midi_port_dialog.h b/gtk2_ardour/midi_port_dialog.h new file mode 100644 index 0000000000..a76400e91b --- /dev/null +++ b/gtk2_ardour/midi_port_dialog.h @@ -0,0 +1,21 @@ +#include <gtkmm/box.h> +#include <gtkmm/label.h> +#include <gtkmm/entry.h> +#include <gtkmm/comboboxtext.h> + +#include "ardour_dialog.h" + +class MidiPortDialog : public ArdourDialog +{ + public: + MidiPortDialog (); + ~MidiPortDialog (); + + Gtk::HBox hpacker; + Gtk::Label port_label; + Gtk::Entry port_name; + Gtk::ComboBoxText port_mode_combo; + + private: + void entry_activated (); +}; diff --git a/gtk2_ardour/option_editor.cc b/gtk2_ardour/option_editor.cc index ad34e8ed0b..93cccfcbf3 100644 --- a/gtk2_ardour/option_editor.cc +++ b/gtk2_ardour/option_editor.cc @@ -26,6 +26,8 @@ #include <ardour/sndfilesource.h> #include <ardour/crossfade.h> #include <midi++/manager.h> +#include <midi++/factory.h> +#include <midi++/port_request.h> #include <gtkmm2ext/stop_signal.h> #include <gtkmm2ext/utils.h> #include <gtkmm2ext/window_title.h> @@ -40,6 +42,7 @@ #include "utils.h" #include "editing.h" #include "option_editor.h" +#include "midi_port_dialog.h" #include "i18n.h" @@ -75,8 +78,10 @@ OptionEditor::OptionEditor (ARDOUR_UI& uip, PublicEditor& ed, Mixer_UI& mixui) /* MIDI */ - mmc_device_id_adjustment (0.0, 0.0, (double) 0x7f, 1.0, 16.0), - mmc_device_id_spinner (mmc_device_id_adjustment), + mmc_receive_device_id_adjustment (0.0, 0.0, (double) 0x7f, 1.0, 16.0), + mmc_receive_device_id_spinner (mmc_receive_device_id_adjustment), + mmc_send_device_id_adjustment (0.0, 0.0, (double) 0x7f, 1.0, 16.0), + mmc_send_device_id_spinner (mmc_send_device_id_adjustment), /* Click */ @@ -363,46 +368,131 @@ OptionEditor::smpte_offset_chosen() } } - void OptionEditor::setup_midi_options () { HBox* hbox; + Label* label; + + midi_port_table.set_row_spacings (6); + midi_port_table.set_col_spacings (10); + + redisplay_midi_ports (); + + mmc_receive_device_id_adjustment.signal_value_changed().connect (mem_fun (*this, &OptionEditor::mmc_receive_device_id_adjusted)); + mmc_send_device_id_adjustment.signal_value_changed().connect (mem_fun (*this, &OptionEditor::mmc_send_device_id_adjusted)); + + hbox = manage (new HBox); + hbox->set_border_width (6); + hbox->pack_start (midi_port_table, true, false); + + midi_packer.pack_start (*hbox, false, false); + midi_packer.pack_start (add_midi_port_button, false, false); + + hbox = manage (new HBox); + hbox->set_border_width (6); + hbox->set_spacing (6); + label = (manage (new Label (_("Inbound MMC Device ID")))); + hbox->pack_start (mmc_receive_device_id_spinner, false, false); + hbox->pack_start (*label, false, false); + midi_packer.pack_start (*hbox, false, false); + + hbox = manage (new HBox); + hbox->set_border_width (6); + hbox->set_spacing (6); + label = (manage (new Label (_("Outbound MMC Device ID")))); + hbox->pack_start (mmc_send_device_id_spinner, false, false); + hbox->pack_start (*label, false, false); + midi_packer.pack_start (*hbox, false, false); + + add_midi_port_button.signal_clicked().connect (mem_fun (*this, &OptionEditor::add_midi_port)); +} + +void +OptionEditor::redisplay_midi_ports () +{ MIDI::Manager::PortMap::const_iterator i; const MIDI::Manager::PortMap& ports = MIDI::Manager::instance()->get_midi_ports(); int n; - ToggleButton* tb; - RadioButton* rb; - Gtk::Table* table = manage (new Table (ports.size() + 4, 10)); + /* remove all existing widgets */ - table->set_row_spacings (6); - table->set_col_spacings (10); + // XXX broken in gtkmm 2.10 + // midi_port_table.clear (); - table->attach (*(manage (new Label (_("Port")))), 0, 1, 0, 1); - table->attach (*(manage (new Label (_("Offline")))), 1, 2, 0, 1); - table->attach (*(manage (new Label (_("Trace\nInput")))), 2, 3, 0, 1); - table->attach (*(manage (new Label (_("Trace\nOutput")))), 3, 4, 0, 1); - table->attach (*(manage (new Label (_("MTC")))), 4, 5, 0, 1); - table->attach (*(manage (new Label (_("MMC")))), 6, 7, 0, 1); - table->attach (*(manage (new Label (_("MIDI Parameter\nControl")))), 8, 9, 0, 1); + for (vector<Widget*>::iterator w = midi_port_table_widgets.begin(); w != midi_port_table_widgets.end(); ++w) { + midi_port_table.remove (**w); + } - table->attach (*(manage (new HSeparator())), 0, 9, 1, 2); - table->attach (*(manage (new VSeparator())), 5, 6, 0, 8); - table->attach (*(manage (new VSeparator())), 7, 8, 0, 8); - - table->attach (*(manage (new Label (_("MMC Device ID")))), 9, 10, 0, 1); - table->attach (mmc_device_id_spinner, 9, 10, 1, 2); - - mmc_device_id_adjustment.signal_value_changed().connect (mem_fun (*this, &OptionEditor::mmc_device_id_adjusted)); + midi_port_table_widgets.clear (); - for (n = 0, i = ports.begin(); i != ports.end(); ++n, ++i) { + midi_port_table.resize (ports.size() + 4, 11); + + Gtk::Label* label; - pair<MIDI::Port*,vector<RadioButton*> > newpair; + label = (manage (new Label (_("Port")))); + label->show (); + midi_port_table_widgets.push_back (label); + midi_port_table.attach (*label, 0, 1, 0, 1); + label = (manage (new Label (_("Offline")))); + label->show (); + midi_port_table_widgets.push_back (label); + midi_port_table.attach (*label, 1, 2, 0, 1); + label = (manage (new Label (_("Trace\nInput")))); + label->show (); + midi_port_table_widgets.push_back (label); + midi_port_table.attach (*label, 2, 3, 0, 1); + label = (manage (new Label (_("Trace\nOutput")))); + label->show (); + midi_port_table_widgets.push_back (label); + midi_port_table.attach (*label, 3, 4, 0, 1); + label = (manage (new Label (_("MTC")))); + label->show (); + midi_port_table_widgets.push_back (label); + midi_port_table.attach (*label, 4, 5, 0, 1); + label = (manage (new Label (_("MMC")))); + label->show (); + midi_port_table_widgets.push_back (label); + midi_port_table.attach (*label, 6, 7, 0, 1); + label = (manage (new Label (_("MIDI Parameter\nControl")))); + label->show (); + midi_port_table_widgets.push_back (label); + midi_port_table.attach (*label, 8, 9, 0, 1); + + Gtk::HSeparator* hsep = (manage (new HSeparator())); + hsep->show (); + midi_port_table_widgets.push_back (hsep); + midi_port_table.attach (*hsep, 0, 9, 1, 2); + Gtk::VSeparator* vsep = (manage (new VSeparator())); + vsep->show (); + midi_port_table_widgets.push_back (vsep); + midi_port_table.attach (*vsep, 5, 6, 0, 8); + vsep = (manage (new VSeparator())); + vsep->show (); + midi_port_table_widgets.push_back (vsep); + midi_port_table.attach (*vsep, 7, 8, 0, 8); + + for (n = 0, i = ports.begin(); i != ports.end(); ++n, ++i) { - newpair.first = i->second; + ToggleButton* tb; + RadioButton* rb; + Button* bb; - table->attach (*(manage (new Label (i->first))), 0, 1, n+2, n+3,FILL|EXPAND, FILL ); + /* the remove button. create early so we can pass it to various callbacks */ + + bb = manage (new Button (Stock::REMOVE)); + bb->set_name ("OptionEditorToggleButton"); + bb->show (); + midi_port_table_widgets.push_back (bb); + midi_port_table.attach (*bb, 9, 10, n+2, n+3, FILL|EXPAND, FILL); + bb->signal_clicked().connect (bind (mem_fun(*this, &OptionEditor::remove_midi_port), i->second)); + bb->set_sensitive (port_removable (i->second)); + + label = (manage (new Label (i->first))); + label->show (); + midi_port_table_widgets.push_back (label); + midi_port_table.attach (*label, 0, 1, n+2, n+3,FILL|EXPAND, FILL ); + tb = manage (new ToggleButton (_("online"))); tb->set_name ("OptionEditorToggleButton"); @@ -416,25 +506,32 @@ OptionEditor::setup_midi_options () set_size_request_to_display_given_text (*tb, _("online"), 15, 12); } - tb->set_active (!(*i).second->input()->offline()); - tb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::port_online_toggled), (*i).second, tb)); - (*i).second->input()->OfflineStatusChanged.connect (bind (mem_fun(*this, &OptionEditor::map_port_online), (*i).second, tb)); - table->attach (*tb, 1, 2, n+2, n+3, FILL|EXPAND, FILL); + if (i->second->input()) { + tb->set_active (!i->second->input()->offline()); + tb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::port_online_toggled), i->second, tb)); + i->second->input()->OfflineStatusChanged.connect (bind (mem_fun(*this, &OptionEditor::map_port_online), (*i).second, tb)); + } + tb->show (); + midi_port_table_widgets.push_back (tb); + midi_port_table.attach (*tb, 1, 2, n+2, n+3, FILL|EXPAND, FILL); tb = manage (new ToggleButton ()); tb->set_name ("OptionEditorToggleButton"); tb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::port_trace_in_toggled), (*i).second, tb)); tb->set_size_request (10, 10); - table->attach (*tb, 2, 3, n+2, n+3, FILL|EXPAND, FILL); + tb->show (); + midi_port_table_widgets.push_back (tb); + midi_port_table.attach (*tb, 2, 3, n+2, n+3, FILL|EXPAND, FILL); tb = manage (new ToggleButton ()); tb->set_name ("OptionEditorToggleButton"); tb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::port_trace_out_toggled), (*i).second, tb)); tb->set_size_request (10, 10); - table->attach (*tb, 3, 4, n+2, n+3, FILL|EXPAND, FILL); + tb->show (); + midi_port_table_widgets.push_back (tb); + midi_port_table.attach (*tb, 3, 4, n+2, n+3, FILL|EXPAND, FILL); rb = manage (new RadioButton ()); - newpair.second.push_back (rb); rb->set_name ("OptionEditorToggleButton"); if (n == 0) { mtc_button_group = rb->get_group(); @@ -442,99 +539,154 @@ OptionEditor::setup_midi_options () rb->set_group (mtc_button_group); } - table->attach (*rb, 4, 5, n+2, n+3, FILL|EXPAND, FILL); - rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::mtc_port_chosen), (*i).second, rb)); + rb->show (); + midi_port_table_widgets.push_back (rb); + midi_port_table.attach (*rb, 4, 5, n+2, n+3, FILL|EXPAND, FILL); + rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::mtc_port_chosen), (*i).second, rb, bb)); - if (Config->get_mtc_port_name() == i->first) { + if (session && i->second == session->mtc_port()) { rb->set_active (true); } rb = manage (new RadioButton ()); - newpair.second.push_back (rb); rb->set_name ("OptionEditorToggleButton"); if (n == 0) { mmc_button_group = rb->get_group(); } else { rb->set_group (mmc_button_group); } - table->attach (*rb, 6, 7, n+2, n+3, FILL|EXPAND, FILL); - rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::mmc_port_chosen), (*i).second, rb)); + rb->show (); + midi_port_table_widgets.push_back (rb); + midi_port_table.attach (*rb, 6, 7, n+2, n+3, FILL|EXPAND, FILL); + rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::mmc_port_chosen), (*i).second, rb, bb)); - if (Config->get_mmc_port_name() == i->first) { + if (session && i->second == session->mmc_port()) { rb->set_active (true); } rb = manage (new RadioButton ()); - newpair.second.push_back (rb); rb->set_name ("OptionEditorToggleButton"); if (n == 0) { midi_button_group = rb->get_group(); } else { rb->set_group (midi_button_group); } - table->attach (*rb, 8, 9, n+2, n+3, FILL|EXPAND, FILL); - rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::midi_port_chosen), (*i).second, rb)); + rb->show (); + midi_port_table_widgets.push_back (rb); + midi_port_table.attach (*rb, 8, 9, n+2, n+3, FILL|EXPAND, FILL); + rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::midi_port_chosen), (*i).second, rb, bb)); - if (Config->get_midi_port_name() == i->first) { + if (session && i->second == session->midi_port()) { rb->set_active (true); } - - port_toggle_buttons.insert (newpair); + } - table->show_all (); + midi_port_table.show(); +} - hbox = manage (new HBox); - hbox->set_border_width (6); - hbox->pack_start (*table, true, false); - midi_packer.pack_start (*hbox, false, false); +void +OptionEditor::remove_midi_port (MIDI::Port* port) +{ + MIDI::Manager::instance()->remove_port (port); + redisplay_midi_ports (); +} + +void +OptionEditor::add_midi_port () +{ + MidiPortDialog dialog; + + dialog.set_position (WIN_POS_MOUSE); + dialog.set_transient_for (*this); + + dialog.show (); + + int ret = dialog.run (); + + switch (ret) { + case RESPONSE_ACCEPT: + break; + default: + return; + break; + } + + Glib::ustring mode = dialog.port_mode_combo.get_active_text(); + std::string smod; + + if (mode == _("input")) { + smod = X_("input"); + } else if (mode == (_("output"))) { + smod = X_("output"); + } else { + smod = "duplex"; + } + + MIDI::PortRequest req (X_("ardour"), + dialog.port_name.get_text(), + smod, + MIDI::PortFactory::default_port_type()); + + if (MIDI::Manager::instance()->add_port (req) != 0) { + redisplay_midi_ports (); + } +} + +bool +OptionEditor::port_removable (MIDI::Port *port) +{ + if (!session) { + return true; + } + + if (port == session->mtc_port() || + port == session->mmc_port() || + port == session->midi_port()) { + return false; + } + return true; } void -OptionEditor::mtc_port_chosen (MIDI::Port *port, Gtk::RadioButton* rb) +OptionEditor::mtc_port_chosen (MIDI::Port *port, Gtk::RadioButton* rb, Gtk::Button* bb) { if (session) { if (rb->get_active()) { - if (port) { - session->set_mtc_port (port->name()); - Config->set_mtc_port_name (port->name()); - } else { - session->set_mtc_port (""); - } - rb->set_active (true); + session->set_mtc_port (port->name()); + Config->set_mtc_port_name (port->name()); + } else { + session->set_mtc_port (""); } + bb->set_sensitive (port_removable (port)); } } void -OptionEditor::mmc_port_chosen (MIDI::Port* port, Gtk::RadioButton* rb) +OptionEditor::mmc_port_chosen (MIDI::Port* port, Gtk::RadioButton* rb, Gtk::Button* bb) { if (session) { if (rb->get_active()) { - if (port) { - session->set_mmc_port (port->name()); - Config->set_mtc_port_name (port->name()); - } else { - session->set_mmc_port (""); - } - rb->set_active (true); + session->set_mmc_port (port->name()); + Config->set_mtc_port_name (port->name()); + } else { + session->set_mmc_port (""); } + bb->set_sensitive (port_removable (port)); } } void -OptionEditor::midi_port_chosen (MIDI::Port* port, Gtk::RadioButton* rb) +OptionEditor::midi_port_chosen (MIDI::Port* port, Gtk::RadioButton* rb, Gtk::Button* bb) { if (session) { if (rb->get_active()) { - if (port) { - session->set_midi_port (port->name()); - Config->set_midi_port_name (port->name()); - } else { - session->set_midi_port (""); - } - rb->set_active (true); + session->set_midi_port (port->name()); + Config->set_midi_port_name (port->name()); + } else { + session->set_midi_port (""); } + bb->set_sensitive (port_removable (port)); } } @@ -565,12 +717,22 @@ OptionEditor::map_port_online (MIDI::Port* port, ToggleButton* tb) } void -OptionEditor::mmc_device_id_adjusted () +OptionEditor::mmc_receive_device_id_adjusted () +{ + uint8_t id = (uint8_t) mmc_receive_device_id_spinner.get_value(); + + if (id != Config->get_mmc_receive_device_id()) { + Config->set_mmc_receive_device_id (id); + } +} + +void +OptionEditor::mmc_send_device_id_adjusted () { - uint8_t id = (uint8_t) mmc_device_id_spinner.get_value(); + uint8_t id = (uint8_t) mmc_send_device_id_spinner.get_value(); - if (id != Config->get_mmc_device_id()) { - Config->set_mmc_device_id (id); + if (id != Config->get_mmc_send_device_id()) { + Config->set_mmc_send_device_id (id); } } diff --git a/gtk2_ardour/option_editor.h b/gtk2_ardour/option_editor.h index 7754b0555d..a234f1d752 100644 --- a/gtk2_ardour/option_editor.h +++ b/gtk2_ardour/option_editor.h @@ -110,18 +110,29 @@ class OptionEditor : public Gtk::Dialog Gtk::RadioButton::Group mmc_button_group; Gtk::RadioButton::Group midi_button_group; - Gtk::Adjustment mmc_device_id_adjustment; - Gtk::SpinButton mmc_device_id_spinner; + Gtk::Table midi_port_table; + std::vector<Gtk::Widget*> midi_port_table_widgets; + Gtk::Adjustment mmc_receive_device_id_adjustment; + Gtk::SpinButton mmc_receive_device_id_spinner; + Gtk::Adjustment mmc_send_device_id_adjustment; + Gtk::SpinButton mmc_send_device_id_spinner; + Gtk::Button add_midi_port_button; + + void add_midi_port (); + void remove_midi_port (MIDI::Port*); + void redisplay_midi_ports (); void port_online_toggled (MIDI::Port*,Gtk::ToggleButton*); void port_trace_in_toggled (MIDI::Port*,Gtk::ToggleButton*); void port_trace_out_toggled (MIDI::Port*,Gtk::ToggleButton*); - void mmc_port_chosen (MIDI::Port*,Gtk::RadioButton*); - void mtc_port_chosen (MIDI::Port*,Gtk::RadioButton*); - void midi_port_chosen (MIDI::Port*,Gtk::RadioButton*); + void mmc_port_chosen (MIDI::Port*,Gtk::RadioButton*, Gtk::Button*); + void mtc_port_chosen (MIDI::Port*,Gtk::RadioButton*, Gtk::Button*); + void midi_port_chosen (MIDI::Port*,Gtk::RadioButton*, Gtk::Button*); + bool port_removable (MIDI::Port*); - void mmc_device_id_adjusted (); + void mmc_receive_device_id_adjusted (); + void mmc_send_device_id_adjusted (); void map_port_online (MIDI::Port*, Gtk::ToggleButton*); diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h index 3051a0b44b..4d5579a9a0 100644 --- a/libs/ardour/ardour/configuration_vars.h +++ b/libs/ardour/ardour/configuration_vars.h @@ -36,7 +36,8 @@ CONFIG_VARIABLE (bool, send_mtc, "send-mtc", false) CONFIG_VARIABLE (bool, send_mmc, "send-mmc", false) CONFIG_VARIABLE (bool, mmc_control, "mmc-control", false) CONFIG_VARIABLE (bool, midi_feedback, "midi-feedback", false) -CONFIG_VARIABLE (uint8_t, mmc_device_id, "mmc-device-id", 0) +CONFIG_VARIABLE (uint8_t, mmc_receive_device_id, "mmc-receive-device-id", 0) +CONFIG_VARIABLE (uint8_t, mmc_send_device_id, "mmc-send-device-id", 0) /* control surfaces */ diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 63be24d9f7..9cfdf1187e 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -744,7 +744,8 @@ class Session : public PBD::StatefulDestructible void deliver_midi (MIDI::Port*, MIDI::byte*, int32_t size); - void set_mmc_device_id (uint32_t id); + void set_mmc_receive_device_id (uint32_t id); + void set_mmc_send_device_id (uint32_t id); /* Scrubbing */ diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index 7f88766b63..ba3e6401e6 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -88,97 +88,66 @@ Session::use_config_midi_ports () int Session::set_mtc_port (string port_tag) { -#if 0 - MIDI::byte old_device_id = 0; - bool reset_id = false; + MTC_Slave *ms; if (port_tag.length() == 0) { - if (_mmc_port == 0) { + + if (_slave && ((ms = dynamic_cast<MTC_Slave*> (_slave)) != 0)) { + error << _("Ardour is slaved to MTC - port cannot be reset") << endmsg; + return -1; + } + + if (_mtc_port == 0) { return 0; } - _mmc_port = 0; + + _mtc_port = 0; goto out; } MIDI::Port* port; if ((port = MIDI::Manager::instance()->port (port_tag)) == 0) { + error << string_compose (_("unknown port %1 requested for MTC"), port_tag) << endl; return -1; } - _mmc_port = port; + _mtc_port = port; - if (mmc) { - old_device_id = mmc->device_id(); - reset_id = true; - delete mmc; + if (_slave && ((ms = dynamic_cast<MTC_Slave*> (_slave)) != 0)) { + ms->rebind (*port); } - mmc = new MIDI::MachineControl (*_mmc_port, 1.0, - MMC_CommandSignature, - MMC_ResponseSignature); - - if (reset_id) { - mmc->set_device_id (old_device_id); - } - - mmc->Play.connect - (mem_fun (*this, &Session::mmc_deferred_play)); - mmc->DeferredPlay.connect - (mem_fun (*this, &Session::mmc_deferred_play)); - mmc->Stop.connect - (mem_fun (*this, &Session::mmc_stop)); - mmc->FastForward.connect - (mem_fun (*this, &Session::mmc_fast_forward)); - mmc->Rewind.connect - (mem_fun (*this, &Session::mmc_rewind)); - mmc->Pause.connect - (mem_fun (*this, &Session::mmc_pause)); - mmc->RecordPause.connect - (mem_fun (*this, &Session::mmc_record_pause)); - mmc->RecordStrobe.connect - (mem_fun (*this, &Session::mmc_record_strobe)); - mmc->RecordExit.connect - (mem_fun (*this, &Session::mmc_record_exit)); - mmc->Locate.connect - (mem_fun (*this, &Session::mmc_locate)); - mmc->Step.connect - (mem_fun (*this, &Session::mmc_step)); - mmc->Shuttle.connect - (mem_fun (*this, &Session::mmc_shuttle)); - mmc->TrackRecordStatusChange.connect - (mem_fun (*this, &Session::mmc_record_enable)); - - - /* also handle MIDI SPP because its so common */ - - _mmc_port->input()->start.connect (mem_fun (*this, &Session::spp_start)); - _mmc_port->input()->contineu.connect (mem_fun (*this, &Session::spp_continue)); - _mmc_port->input()->stop.connect (mem_fun (*this, &Session::spp_stop)); - - Config->set_mmc_port_name (port_tag); + Config->set_mtc_port_name (port_tag); out: - MMC_PortChanged(); /* EMIT SIGNAL */ + MTC_PortChanged(); /* EMIT SIGNAL */ change_midi_ports (); set_dirty(); -#endif return 0; } void -Session::set_mmc_device_id (uint32_t device_id) +Session::set_mmc_receive_device_id (uint32_t device_id) { if (mmc) { - mmc->set_device_id (device_id); + mmc->set_receive_device_id (device_id); + } +} + +void +Session::set_mmc_send_device_id (uint32_t device_id) +{ + if (mmc) { + mmc->set_send_device_id (device_id); } } int Session::set_mmc_port (string port_tag) { -#if 0 - MIDI::byte old_device_id = 0; + MIDI::byte old_recv_device_id = 0; + MIDI::byte old_send_device_id = 0; bool reset_id = false; if (port_tag.length() == 0) { @@ -198,7 +167,8 @@ Session::set_mmc_port (string port_tag) _mmc_port = port; if (mmc) { - old_device_id = mmc->device_id(); + old_recv_device_id = mmc->receive_device_id(); + old_recv_device_id = mmc->send_device_id(); reset_id = true; delete mmc; } @@ -208,7 +178,8 @@ Session::set_mmc_port (string port_tag) MMC_ResponseSignature); if (reset_id) { - mmc->set_device_id (old_device_id); + mmc->set_receive_device_id (old_recv_device_id); + mmc->set_send_device_id (old_send_device_id); } mmc->Play.connect @@ -248,7 +219,6 @@ Session::set_mmc_port (string port_tag) Config->set_mmc_port_name (port_tag); out: -#endif MMC_PortChanged(); /* EMIT SIGNAL */ change_midi_ports (); set_dirty(); @@ -438,7 +408,7 @@ Session::setup_midi_control () mmc_buffer[0] = 0xf0; // SysEx mmc_buffer[1] = 0x7f; // Real Time SysEx ID for MMC - mmc_buffer[2] = 0x7f; // "broadcast" device ID + mmc_buffer[2] = mmc->send_device_id(); mmc_buffer[3] = 0x6; // MCC /* Set up the qtr frame message */ diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index a7c8dc0200..48fb932b30 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -2872,10 +2872,16 @@ Session::config_changed (const char* parameter_name) //poke_midi_thread (); - } else if (PARAM_IS ("mmc-device-id")) { + } else if (PARAM_IS ("mmc-device-id") || PARAM_IS ("mmc-receive-id")) { if (mmc) { - mmc->set_device_id (Config->get_mmc_device_id()); + mmc->set_receive_device_id (Config->get_mmc_receive_device_id()); + } + + } else if (PARAM_IS ("mmc-send-id")) { + + if (mmc) { + mmc->set_send_device_id (Config->get_mmc_send_device_id()); } } else if (PARAM_IS ("midi-control")) { diff --git a/libs/midi++2/midi++/alsa_rawmidi.h b/libs/midi++2/midi++/alsa_rawmidi.h index 8e50609fbe..54b86edd70 100644 --- a/libs/midi++2/midi++/alsa_rawmidi.h +++ b/libs/midi++2/midi++/alsa_rawmidi.h @@ -37,6 +37,13 @@ class ALSA_RawMidiPort : public MIDI::FD_MidiPort ALSA_RawMidiPort (MIDI::PortRequest &req) : FD_MidiPort (req, "/dev/snd", "midi") {} virtual ~ALSA_RawMidiPort () {} + + static std::string typestring; + + protected: + std::string get_typestring () const { + return typestring; + } }; } // namespace MIDI diff --git a/libs/midi++2/midi++/alsa_sequencer.h b/libs/midi++2/midi++/alsa_sequencer.h index 7fe880fe63..b54486416a 100644 --- a/libs/midi++2/midi++/alsa_sequencer.h +++ b/libs/midi++2/midi++/alsa_sequencer.h @@ -30,8 +30,9 @@ namespace MIDI { -class ALSA_SequencerMidiPort : public Port +class PortRequest; +class ALSA_SequencerMidiPort : public Port { public: ALSA_SequencerMidiPort (PortRequest &req); @@ -41,6 +42,13 @@ class ALSA_SequencerMidiPort : public Port virtual int selectable() const; + static std::string typestring; + + protected: + std::string get_typestring () const { + return typestring; + } + protected: /* Direct I/O */ int write (byte *msg, size_t msglen, timestamp_t timestamp); diff --git a/libs/midi++2/midi++/coremidi_midiport.h b/libs/midi++2/midi++/coremidi_midiport.h index 30e07e01a5..91eccea4a5 100644 --- a/libs/midi++2/midi++/coremidi_midiport.h +++ b/libs/midi++2/midi++/coremidi_midiport.h @@ -32,14 +32,24 @@ namespace MIDI { -class CoreMidi_MidiPort:public Port { - public: - CoreMidi_MidiPort(PortRequest & req); - virtual ~ CoreMidi_MidiPort(); - - virtual int selectable() const { - return -1; - } +namespace PortRequest; + +class CoreMidi_MidiPort:public Port +{ + public: + CoreMidi_MidiPort(PortRequest & req); + virtual ~ CoreMidi_MidiPort(); + + virtual int selectable() const { + return -1; + } + static std::string typestring; + + protected: + std::string get_typestring () const { + return typestring; + } + protected: /* Direct I/O */ int write (byte *msg, size_t msglen, timestamp_t timestamp); diff --git a/libs/midi++2/midi++/factory.h b/libs/midi++2/midi++/factory.h index df7f35e073..9954ea72fe 100644 --- a/libs/midi++2/midi++/factory.h +++ b/libs/midi++2/midi++/factory.h @@ -23,6 +23,7 @@ #include <string> #include <midi++/port.h> +#include <midi++/port_request.h> namespace MIDI { @@ -31,6 +32,11 @@ class PortFactory { Port *create_port (PortRequest &req, void* data); static bool ignore_duplicate_devices (Port::Type); + static int get_known_ports (std::vector<PortSet>&); + static std::string default_port_type (); + static Port::Type string_to_type (const std::string&); + static std::string mode_to_string (int); + static int string_to_mode (const std::string&); }; } // namespace MIDI diff --git a/libs/midi++2/midi++/fd_midiport.h b/libs/midi++2/midi++/fd_midiport.h index 8a1af55967..34e2e27a1a 100644 --- a/libs/midi++2/midi++/fd_midiport.h +++ b/libs/midi++2/midi++/fd_midiport.h @@ -48,6 +48,13 @@ class FD_MidiPort : public Port virtual int selectable() const; static std::vector<std::string *> *list_devices (); + static std::string typestring; + + protected: + std::string get_typestring () const { + return typestring; + } + protected: int _fd; virtual void open (PortRequest &req); diff --git a/libs/midi++2/midi++/fifomidi.h b/libs/midi++2/midi++/fifomidi.h index 57d1502c45..ea644dde06 100644 --- a/libs/midi++2/midi++/fifomidi.h +++ b/libs/midi++2/midi++/fifomidi.h @@ -37,6 +37,13 @@ class FIFO_MidiPort : public MIDI::FD_MidiPort FIFO_MidiPort (PortRequest &req); ~FIFO_MidiPort () {}; + static std::string typestring; + + protected: + std::string get_typestring () const { + return typestring; + } + private: void open (PortRequest &req); }; diff --git a/libs/midi++2/midi++/jack.h b/libs/midi++2/midi++/jack.h index c20b2693f1..1f25609aac 100644 --- a/libs/midi++2/midi++/jack.h +++ b/libs/midi++2/midi++/jack.h @@ -47,6 +47,13 @@ public: virtual void cycle_start(nframes_t nframes); + static std::string typestring; + + protected: + std::string get_typestring () const { + return typestring; + } + protected: /* Direct I/O */ int write(byte *msg, size_t msglen, timestamp_t timestamp); diff --git a/libs/midi++2/midi++/manager.h b/libs/midi++2/midi++/manager.h index 80de408ee1..eef52abe52 100644 --- a/libs/midi++2/midi++/manager.h +++ b/libs/midi++2/midi++/manager.h @@ -50,10 +50,9 @@ class Manager { void cycle_end(); Port *add_port (PortRequest &); - int remove_port (std::string port); + int remove_port (Port*); Port *port (std::string name); - Port *port (size_t number); size_t nports () { return ports_by_device.size(); } diff --git a/libs/midi++2/midi++/mmc.h b/libs/midi++2/midi++/mmc.h index bc23beb0a1..6abbed8207 100644 --- a/libs/midi++2/midi++/mmc.h +++ b/libs/midi++2/midi++/mmc.h @@ -91,8 +91,10 @@ class MachineControl : public sigc::trackable Port &port() { return _port; } - void set_device_id (byte id); - byte device_id () const { return _device_id; } + void set_receive_device_id (byte id); + void set_send_device_id (byte id); + byte receive_device_id () const { return _receive_device_id; } + byte send_device_id () const { return _send_device_id; } static bool is_mmc (byte *sysex_buf, size_t len); @@ -244,7 +246,8 @@ class MachineControl : public sigc::trackable byte resume; private: - byte _device_id; + byte _receive_device_id; + byte _send_device_id; MIDI::Port &_port; void process_mmc_message (Parser &p, byte *, size_t len); diff --git a/libs/midi++2/midi++/nullmidi.h b/libs/midi++2/midi++/nullmidi.h index 1474da77ed..6ed94db71c 100644 --- a/libs/midi++2/midi++/nullmidi.h +++ b/libs/midi++2/midi++/nullmidi.h @@ -55,6 +55,13 @@ class Null_MidiPort : public Port } virtual int selectable() const { return -1; } + + static std::string typestring; + + protected: + std::string get_typestring () const { + return typestring; + } }; } // namespace MIDI diff --git a/libs/midi++2/midi++/port_request.h b/libs/midi++2/midi++/port_request.h index 0cb4ffded6..dfde87a63c 100644 --- a/libs/midi++2/midi++/port_request.h +++ b/libs/midi++2/midi++/port_request.h @@ -53,6 +53,13 @@ struct PortRequest { const std::string &xtype); }; +struct PortSet { + PortSet (std::string str) : owner (str) { } + + std::string owner; + std::list<PortRequest> ports; +}; + } // namespace MIDI #endif // __midi_port_request_h__ diff --git a/libs/midi++2/midifactory.cc b/libs/midi++2/midifactory.cc index de4a246bcf..9d98d9f6a7 100644 --- a/libs/midi++2/midifactory.cc +++ b/libs/midi++2/midifactory.cc @@ -18,6 +18,10 @@ */ #include <cassert> + +#include <pbd/error.h> +#include <pbd/convert.h> + #include <midi++/types.h> #include <midi++/factory.h> #include <midi++/nullmidi.h> @@ -25,20 +29,32 @@ #ifdef WITH_JACK_MIDI #include <midi++/jack.h> + +std::string MIDI::JACK_MidiPort::typestring = "jack"; #endif // WITH_JACK_MIDI +std::string MIDI::Null_MidiPort::typestring = "null"; +std::string MIDI::FIFO_MidiPort::typestring = "fifo"; + #ifdef WITH_ALSA #include <midi++/alsa_sequencer.h> #include <midi++/alsa_rawmidi.h> + +std::string MIDI::ALSA_SequencerMidiPort::typestring = "alsa/sequencer"; +std::string MIDI::ALSA_RawMidiPort::typestring = "alsa/raw"; + #endif // WITH_ALSA #ifdef WITH_COREMIDI #include <midi++/coremidi_midiport.h> -#endif // WITH_COREMIDI +std::string MIDI::CoreMidi_MidiPort::typestring = "coremidi"; + +#endif // WITH_COREMIDI using namespace std; using namespace MIDI; +using namespace PBD; // FIXME: void* data pointer, filthy Port * @@ -114,3 +130,88 @@ PortFactory::ignore_duplicate_devices (Port::Type type) return ret; } +int +PortFactory::get_known_ports (vector<PortSet>& ports) +{ + int n = 0; +#ifdef WITH_ALSA + n += ALSA_SequencerMidiPort::discover (ports); +#endif // WITH_ALSA + +#if WITH_COREMIDI + n += CoreMidi_MidiPort::discover (ports); +#endif // WITH_COREMIDI + + return n; +} + +std::string +PortFactory::default_port_type () +{ +#ifdef WITH_JACK_MIDI + return "jack"; +#endif + +#ifdef WITH_ALSA + return "alsa/sequencer"; +#endif + +#ifdef WITH_COREMIDI + return "coremidi"; +#endif // WITH_COREMIDI + + PBD::fatal << "programming error: no default port type defined in midifactory.cc" << endmsg; + /*NOTREACHED*/ + return ""; +} + +Port::Type +PortFactory::string_to_type (const string& xtype) +{ + if (0){ +#ifdef WITH_ALSA + } else if (strings_equal_ignore_case (xtype, ALSA_RawMidiPort::typestring)) { + return Port::ALSA_RawMidi; + } else if (strings_equal_ignore_case (xtype, ALSA_SequencerMidiPort::typestring)) { + return Port::ALSA_Sequencer; +#endif +#ifdef WITH_COREMIDI + } else if (strings_equal_ignore_case (xtype, CoreMidi_MidiPort::typestring)) { + return Port::CoreMidi_MidiPort; +#endif + } else if (strings_equal_ignore_case (xtype, Null_MidiPort::typestring)) { + return Port::Null; + } else if (strings_equal_ignore_case (xtype, FIFO_MidiPort::typestring)) { + return Port::FIFO; +#ifdef WITH_JACK_MIDI + } else if (strings_equal_ignore_case (xtype, JACK_MidiPort::typestring)) { + return Port::JACK_Midi; +#endif + } + + return Port::Unknown; +} + +string +PortFactory::mode_to_string (int mode) +{ + if (mode == O_RDONLY) { + return "input"; + } else if (mode == O_WRONLY) { + return "output"; + } + + return "duplex"; +} + +int +PortFactory::string_to_mode (const string& str) +{ + if (strings_equal_ignore_case (str, "output") || strings_equal_ignore_case (str, "out")) { + return O_WRONLY; + } else if (strings_equal_ignore_case (str, "input") || strings_equal_ignore_case (str, "in")) { + return O_RDONLY; + } + + return O_RDWR; +} diff --git a/libs/midi++2/midimanager.cc b/libs/midi++2/midimanager.cc index 970674232d..ee73bdad86 100644 --- a/libs/midi++2/midimanager.cc +++ b/libs/midi++2/midimanager.cc @@ -126,44 +126,43 @@ Manager::add_port (PortRequest &req) } int -Manager::remove_port (string name) +Manager::remove_port (Port* port) { PortMap::iterator res; - if ((res = ports_by_device.find (name)) == ports_by_device.end()) { - return -1; + for (res = ports_by_device.begin(); res != ports_by_device.end(); ) { + PortMap::iterator tmp; + tmp = res; + ++tmp; + if (res->second == port) { + ports_by_device.erase (res); + } + res = tmp; } - - ports_by_device.erase (res); - ports_by_device.erase ((*res).second->name()); - - delete (*res).second; - return 0; -} - -Port * -Manager::port (string name) -{ - PortMap::iterator res; - for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) { - if (name == (*res).first) { - return (*res).second; - } + for (res = ports_by_tag.begin(); res != ports_by_tag.end(); ) { + PortMap::iterator tmp; + tmp = res; + ++tmp; + if (res->second == port) { + ports_by_tag.erase (res); + } + res = tmp; } + + delete port; return 0; } Port * -Manager::port (size_t portnum) - +Manager::port (string name) { PortMap::iterator res; for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) { - if ((*res).second->number() == portnum) { + if (name == (*res).first) { return (*res).second; } } diff --git a/libs/midi++2/mmc.cc b/libs/midi++2/mmc.cc index 28d6393fb4..1ede281c28 100644 --- a/libs/midi++2/mmc.cc +++ b/libs/midi++2/mmc.cc @@ -202,7 +202,8 @@ MachineControl::MachineControl (Port &p, float version, build_mmc_cmd_map (); - _device_id = 0; + _receive_device_id = 0; + _send_device_id = 0x7f; if ((parser = _port.input()) != 0) { parser->mmc.connect @@ -214,10 +215,15 @@ MachineControl::MachineControl (Port &p, float version, } void -MachineControl::set_device_id (byte id) +MachineControl::set_receive_device_id (byte id) +{ + _receive_device_id = id & 0x7f; +} +void +MachineControl::set_send_device_id (byte id) { - _device_id = id & 0x7f; + _send_device_id = id & 0x7f; } bool @@ -258,14 +264,14 @@ MachineControl::process_mmc_message (Parser &p, byte *msg, size_t len) */ #if 0 - cerr << "*** me = " << (int) _device_id << " MMC message: len = " << len << "\n\t"; + cerr << "*** me = " << (int) _receive_device_id << " MMC message: len = " << len << "\n\t"; for (size_t i = 0; i < len; i++) { cerr << hex << (int) msg[i] << dec << ' '; } cerr << endl; #endif - if (msg[1] != 0x7f && msg[1] != _device_id) { + if (msg[1] != 0x7f && msg[1] != _receive_device_id) { return; } diff --git a/libs/pbd/convert.cc b/libs/pbd/convert.cc index 832c54acd8..07fcc09ace 100644 --- a/libs/pbd/convert.cc +++ b/libs/pbd/convert.cc @@ -233,5 +233,21 @@ length2string (const int64_t frames, const double sample_rate) return duration_str; } +static bool +chars_equal_ignore_case(char x, char y) +{ + static std::locale loc; + return toupper(x, loc) == toupper(y, loc); +} + +bool +strings_equal_ignore_case (const string& a, const string& b) +{ + if (a.length() == b.length()) { + return std::equal (a.begin(), a.end(), b.begin(), chars_equal_ignore_case); + } + return false; +} + } // namespace PBD diff --git a/libs/pbd/pbd/convert.h b/libs/pbd/pbd/convert.h index 55006529ae..00176659cf 100644 --- a/libs/pbd/pbd/convert.h +++ b/libs/pbd/pbd/convert.h @@ -35,6 +35,7 @@ void url_decode (std::string&); std::string length2string (const int64_t frames, const double sample_rate); std::vector<std::string> internationalize (const char *, const char **); +bool strings_equal_ignore_case (const std::string& a, const std::string& b); } //namespace PBD |