merge changes to libmidi++ API from 2.0-ongoing
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 6 Aug 2007 14:19:19 +0000 (14:19 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 6 Aug 2007 14:19:19 +0000 (14:19 +0000)
git-svn-id: svn://localhost/ardour2/trunk@2256 d708f5d6-7413-0410-9779-e7cbd77b26cf

25 files changed:
gtk2_ardour/SConscript
gtk2_ardour/midi_port_dialog.cc [new file with mode: 0644]
gtk2_ardour/midi_port_dialog.h [new file with mode: 0644]
gtk2_ardour/option_editor.cc
gtk2_ardour/option_editor.h
libs/ardour/ardour/configuration_vars.h
libs/ardour/ardour/session.h
libs/ardour/session_midi.cc
libs/ardour/session_state.cc
libs/midi++2/midi++/alsa_rawmidi.h
libs/midi++2/midi++/alsa_sequencer.h
libs/midi++2/midi++/coremidi_midiport.h
libs/midi++2/midi++/factory.h
libs/midi++2/midi++/fd_midiport.h
libs/midi++2/midi++/fifomidi.h
libs/midi++2/midi++/jack.h
libs/midi++2/midi++/manager.h
libs/midi++2/midi++/mmc.h
libs/midi++2/midi++/nullmidi.h
libs/midi++2/midi++/port_request.h
libs/midi++2/midifactory.cc
libs/midi++2/midimanager.cc
libs/midi++2/mmc.cc
libs/pbd/convert.cc
libs/pbd/pbd/convert.h

index d215470b52751d134d57243a79f3196e9cb55acc..06ecf2d0f281aa1b9e5672497d431b9f22583c0a 100644 (file)
@@ -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 (file)
index 0000000..2bb686d
--- /dev/null
@@ -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 (file)
index 0000000..a76400e
--- /dev/null
@@ -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 ();
+};
index ad34e8ed0b38449ad117cff0686e1e7c7e4365d4..93cccfcbf35d6003db1ea79c377be7d15fdb249d 100644 (file)
@@ -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);
        }
 }
 
index 7754b0555dc747b9e25dc23f616c84199800a424..a234f1d7522be2a5fe2d204ef4ee54dc465a4649 100644 (file)
@@ -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*);
 
index 3051a0b44b9828b30544010a301f5831fcae4160..4d5579a9a08b0ad6d12d6dad9915b348de4c2d55 100644 (file)
@@ -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 */
 
index 63be24d9f797b926afe1bc4568c8f97d9b36ac62..9cfdf1187eacc68d85fe76fb3a63ad3cee2a0d23 100644 (file)
@@ -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 */
 
index 7f88766b631b8f22e1a2ff6d8a41480dea310262..ba3e6401e65e8820cff899a7c271b96fbeafe17a 100644 (file)
@@ -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 */
index a7c8dc0200dc458209b39b3b1fd94901cadad0c8..48fb932b305cc0fc6593fa7ede12c5e49e2c4644 100644 (file)
@@ -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")) {
index 8e50609fbe818bdc0ea8c04c37be6a63732c4e86..54b86edd70e5f77de73b1882e16e84aad70f9bd7 100644 (file)
@@ -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
index 7fe880fe636e025a76e6c83b143c5c7525725117..b54486416a6e63dbffd783d0be525c4715900563 100644 (file)
@@ -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);    
index 30e07e01a50b4ab41a20ef0f125078378f290c70..91eccea4a55bdaa50ff0ce2ea2997961d4fc2738 100644 (file)
 
 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);    
index df7f35e0738afbb08dd232911a7eaee72ae0b004..9954ea72fec7b98c49a5140511cbab9b20caa209 100644 (file)
@@ -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
index 8a1af55967a82e44e7b052d95c25ad7b6d79fd3f..34e2e27a1a40b85e5f16feffb6a524bf8d7e8922 100644 (file)
@@ -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);
index 57d1502c453d8804a59f414e98115c69f1f03ef5..ea644dde06be59f0e448dfb59c7deccbefc82d32 100644 (file)
@@ -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);
 };
index c20b2693f134f212dd6ab02f9f8f792066fd9f19..1f25609aacbaca3e46ceea9041d4f7a0cf9ed78a 100644 (file)
@@ -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);
index 80de408ee1bb8331afe66ed1095eca70e972c397..eef52abe521664e79f2f3dcd2b3d8eb64a432bed 100644 (file)
@@ -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(); }
 
index bc23beb0a1e6cf6410cef662a6913aa4ca6ccc0d..6abbed82077a5787e2f82d16ac58ddc8f99a3201 100644 (file)
@@ -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);
index 1474da77edf57d871273eb3cc3638661dc69e393..6ed94db71cc41f64907c8a0ddbbb70ba2371b430 100644 (file)
@@ -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
index 0cb4ffded662a8291935ea5a00a3d6d5960e52f8..dfde87a63c033aba534828a5d8017e82568f5ea8 100644 (file)
@@ -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__
index de4a246bcf0ab5b3e35d8084f414f2c557051484..9d98d9f6a7d0260f2bdd097a009f2fee0c50330b 100644 (file)
 */
 
 #include <cassert>
+
+#include <pbd/error.h>
+#include <pbd/convert.h>
+
 #include <midi++/types.h>
 #include <midi++/factory.h>
 #include <midi++/nullmidi.h>
 
 #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;
+}
index 970674232dae5a7b33141750634dcdaf09ee23db..ee73bdad868da206f90749d7b0692f4d30a3b2a9 100644 (file)
@@ -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;
                }
        }
index 28d6393fb453c154c0bc5707a3a3a9af24c19479..1ede281c289784c46ece9d2f85bee7ffdd49c0e1 100644 (file)
@@ -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;
        }
 
index 832c54acd84c186eb1cc21b55c01b87ee51cb2f3..07fcc09acefc61c3d5c265065cd98b98ee5e90af 100644 (file)
@@ -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
index 55006529aedc383e4a4dc0201bf3dcbe4bfd12a4..00176659cf61b805dcc52fe9e3979f8e1e591d02 100644 (file)
@@ -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