missing part of lincoln's patch
[ardour.git] / libs / ardour / port.cc
index f3e0739e83031e57d32edf904b7f003f233058fa..efdd297f5e9bd531f5efa84e28a88f132d6048fc 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2002-2006 Paul Davis 
+    Copyright (C) 2009 Paul Davis
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 
 */
 
-#include <ardour/port.h>
+#ifdef WAF_BUILD
+#include "libardour-config.h"
+#endif
 
-using namespace ARDOUR;
-using namespace std;
-
-AudioEngine* Port::engine = 0;
+#include "ardour/port.h"
+#include "ardour/audioengine.h"
+#include "pbd/failed_constructor.h"
+#include "pbd/error.h"
+#include "pbd/compose.h"
+#include <stdexcept>
 
-Port::Port (const std::string& name, Flags flgs)
-       : _flags (flgs)
-       , _name (name)
-       , _metering (0)
-       , _last_monitor (false)
-{
-}
-
-Port::~Port ()
-{
-       drop_references ();
-       disconnect_all ();
-}
+#include "i18n.h"
 
-void
-Port::reset ()
-{
-       _last_monitor = false;
-}
+using namespace std;
+using namespace ARDOUR;
 
-void
-Port::set_engine (AudioEngine* e) 
-{
-       engine = e;
-}
+AudioEngine* Port::_engine = 0;
+nframes_t Port::_buffer_size = 0;
+bool Port::_connecting_blocked = false;
 
-int
-Port::connect (Port& other)
+/** @param n Port short name */
+Port::Port (std::string const & n, DataType t, Flags f)
+       : _last_monitor (false)
+       , _name (n)
+       , _flags (f)
 {
-       /* caller must hold process lock */
 
-       pair<set<Port*>::iterator,bool> result;
+       /* Unfortunately we have to pass the DataType into this constructor so that we can
+          create the right kind of JACK port; aside from this we'll use the virtual function type ()
+          to establish type.
+       */
 
-       result = _connections.insert (&other);
+       assert (_name.find_first_of (':') == std::string::npos);
 
-       if (result.second) {
-               other.GoingAway.connect (sigc::bind (mem_fun (*this, &Port::port_going_away), &other));
-               return 0;
-       } else {
-               return 1;
+       if ((_jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0)) == 0) {
+               throw failed_constructor ();
        }
 }
 
-int
-Port::disconnect (Port& other)
+/** Port destructor */
+Port::~Port ()
 {
-       /* caller must hold process lock */
-       
-       for (set<Port*>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
-               if ((*i) == &other) {
-                       _connections.erase (i);
-                       return 0;
-               }
-       }
-
-       return -1;
+       jack_port_unregister (_engine->jack (), _jack_port);
 }
 
+/** @return true if this port is connected to anything */
+bool
+Port::connected () const
+{
+       return (jack_port_connected (_jack_port) != 0);
+}
 
 int
 Port::disconnect_all ()
 {
-       /* caller must hold process lock */
-
+       jack_port_disconnect (_engine->jack(), _jack_port);
        _connections.clear ();
-       return 0;
-}
 
-void
-Port::set_latency (nframes_t val)
-{
-       _latency = val;
+       return 0;
 }
 
+/** @param o Port name
+ * @return true if this port is connected to o, otherwise false.
+ */
 bool
-Port::connected() const
+Port::connected_to (std::string const & o) const
 {
-       /* caller must hold process lock */
-       return !_connections.empty();
+       return jack_port_connected_to (_jack_port, _engine->make_port_name_non_relative(o).c_str ());
 }
 
-bool
-Port::connected_to (const string& portname) const
+/** @param o Filled in with port full names of ports that we are connected to */
+int
+Port::get_connections (std::vector<std::string> & c) const
 {
-       /* caller must hold process lock */
+       int n = 0;
 
-       for (set<Port*>::const_iterator p = _connections.begin(); p != _connections.end(); ++p) {
-               if ((*p)->name() == portname) {
-                       return true;
+       const char** jc = jack_port_get_connections (_jack_port);
+       if (jc) {
+               for (int i = 0; jc[i]; ++i) {
+                       c.push_back (jc[i]);
+                       ++n;
                }
+
+               jack_free (jc);
        }
 
-       return false;
+       return n;
 }
 
 int
-Port::get_connections (vector<string>& names) const
+Port::connect (std::string const & other)
 {
        /* caller must hold process lock */
-       int i = 0;
-       set<Port*>::const_iterator p;
 
-       for (i = 0, p = _connections.begin(); p != _connections.end(); ++p, ++i) {
-               names.push_back ((*p)->name());
-       }
+       std::string const other_shrt = _engine->make_port_name_non_relative (other);
+       std::string const this_shrt = _engine->make_port_name_non_relative (_name);
 
-       return i;
-}
+       int r = 0;
 
-void
-Port::port_going_away (Port* p)
-{
-       /* caller must hold process lock */
+       if (_connecting_blocked) {
+               return r;
+       }
 
-       disconnect (*p);
-}
+       if (sends_output ()) {
+               r = jack_connect (_engine->jack (), this_shrt.c_str (), other_shrt.c_str ());
+       } else {
+               r = jack_connect (_engine->jack (), other_shrt.c_str (), this_shrt.c_str());
+       }
 
+       if (r == 0) {
+               _connections.insert (other);
+       }
 
-//-------------------------------------
+       return r;
+}
 
 int
-PortFacade::set_name (const std::string& str)
+Port::disconnect (std::string const & other)
 {
-       int ret;
+       /* caller must hold process lock */
 
-       if (_ext_port) {
-               if ((ret = _ext_port->set_name (str)) == 0) {
-                       _name = _ext_port->name();
-               }
-       } else {
-               _name = str;
-               ret = 0;
-       }
+       std::string const other_shrt = _engine->make_port_name_non_relative (other);
+       std::string const this_shrt = _engine->make_port_name_non_relative (_name);
 
-       return ret;
-}
+       int r = 0;
 
-string
-PortFacade::short_name ()  const
-{
-       if (_ext_port) {
-               return _ext_port->short_name(); 
+       if (sends_output ()) {
+               r = jack_disconnect (_engine->jack (), this_shrt.c_str (), other_shrt.c_str ());
        } else {
-               return _name;
+               r = jack_disconnect (_engine->jack (), other_shrt.c_str (), this_shrt.c_str ());
+       }
+
+       if (r == 0) {
+               _connections.erase (other);
        }
+
+        return r;
 }
 
 
-int
-PortFacade::reestablish ()
+bool
+Port::connected_to (Port* o) const
 {
-       if (_ext_port) {
-               return _ext_port->reestablish ();
-       } else {
-               return 0;
-       }
+       return connected_to (o->name ());
 }
 
-
 int
-PortFacade::reconnect()
+Port::connect (Port* o)
 {
-       if (_ext_port) {
-               return _ext_port->reconnect ();
-       } else {
-               return 0;
-       }
+       return connect (o->name ());
 }
 
-void
-PortFacade::set_latency (nframes_t val)
+int
+Port::disconnect (Port* o)
 {
-       if (_ext_port) {
-               _ext_port->set_latency (val);
-       } else {
-               _latency = val;
-       }
+       return disconnect (o->name ());
 }
 
-nframes_t
-PortFacade::latency() const
+void
+Port::set_engine (AudioEngine* e)
 {
-       if (_ext_port) {
-               return _ext_port->latency();
-       } else {
-               return _latency;
-       }
+       _engine = e;
 }
 
-nframes_t
-PortFacade::total_latency() const
+void
+Port::ensure_monitor_input (bool yn)
 {
-       if (_ext_port) {
-               return _ext_port->total_latency();
-       } else {
-               return _latency;
-       }
+       jack_port_ensure_monitor (_jack_port, yn);
 }
 
 bool
-PortFacade::monitoring_input() const
+Port::monitoring_input () const
 {
-       if (_ext_port) {
-               return _ext_port->monitoring_input ();
-       } else {
-               return false;
-       }
+       return jack_port_monitoring_input (_jack_port);
 }
 
 void
-PortFacade::ensure_monitor_input (bool yn)
+Port::reset ()
 {
-       if (_ext_port) {
-               _ext_port->ensure_monitor_input (yn);
-       }
+       _last_monitor = false;
+
+       // XXX
+       // _metering = 0;
+       // reset_meters ();
 }
 
 void
-PortFacade::request_monitor_input (bool yn)
+Port::recompute_total_latency () const
 {
-       if (_ext_port) {
-               _ext_port->request_monitor_input (yn);
-       } 
+#ifdef HAVE_JACK_RECOMPUTE_LATENCY
+       jack_client_t* jack = _engine->jack();
+
+       if (!jack) {
+               return;
+       }
+
+       jack_recompute_total_latency (jack, _jack_port);
+#endif
 }
 
-int
-PortFacade::connect (Port& other)
+nframes_t
+Port::total_latency () const
 {
-       int ret;
-       
-       if (_ext_port) {
-               ret = _ext_port->connect (other);
-       } else {
-               ret = 0;
-       }
+       jack_client_t* jack = _engine->jack();
 
-       if (ret == 0) {
-               ret = Port::connect (other);
+       if (!jack) {
+               return 0;
        }
 
-       return ret;
+       return jack_port_get_total_latency (jack, _jack_port);
 }
 
 int
-PortFacade::connect (const std::string& other)
+Port::reestablish ()
 {
-       PortConnectableByName* pcn;
+       jack_client_t* jack = _engine->jack();
 
-       if (!_ext_port) {
+       if (!jack) {
                return -1;
        }
-               
-       pcn = dynamic_cast<PortConnectableByName*>(_ext_port);
 
-       if (pcn) {
-               return pcn->connect (other);
-       } else {
-               return -1;
-       }
-}
+       cerr << "RE-REGISTER: " << _name.c_str() << endl;
+       _jack_port = jack_port_register (jack, _name.c_str(), type().to_jack_type(), _flags, 0);
 
-
-int
-PortFacade::disconnect (Port& other)
-{
-       int reta;
-       int retb;
-       
-       if (_ext_port) {
-               reta = _ext_port->disconnect (other);
-       } else {
-               reta = 0;
+       if (_jack_port == 0) {
+               PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
+               return -1;
        }
 
-       retb = Port::disconnect (other);
+       reset ();
 
-       return reta || retb;
+       return 0;
 }
 
-int 
-PortFacade::disconnect_all ()
-{
-       int reta = 0;
-       int retb = 0;
-
-       if (_ext_port) {
-               reta = _ext_port->disconnect_all ();
-       } 
-
-       retb = Port::disconnect_all ();
 
-       return reta || retb;
-}
-               
 int
-PortFacade::disconnect (const std::string& other)
+Port::reconnect ()
 {
-       PortConnectableByName* pcn;
+       /* caller must hold process lock; intended to be used only after reestablish() */
 
-       if (!_ext_port) {
-               return -1;
+       for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
+               if (connect (*i)) {
+                       return -1;
+               }
        }
-               
-       pcn = dynamic_cast<PortConnectableByName*>(_ext_port);
 
-       if (pcn) {
-               return pcn->disconnect (other);
-       } else {
-               return -1;
-       }
+       return 0;
 }
 
-bool
-PortFacade::connected () const 
+/** @param n Short port name (no JACK client name) */
+int
+Port::set_name (std::string const & n)
 {
-       if (Port::connected()) {
-               return true;
+       if (n == _name) {
+               return 0;
        }
 
-       if (_ext_port) {
-               return _ext_port->connected();
-       }
+       int const r = jack_port_set_name (_jack_port, n.c_str());
 
-       return false;
-}
-bool
-PortFacade::connected_to (const std::string& portname) const 
-{
-       if (Port::connected_to (portname)) {
-               return true;
-       }
-
-       if (_ext_port) {
-               return _ext_port->connected_to (portname);
+       if (r == 0) {
+               _name = n;
        }
 
-       return false;
-
+       return r;
 }
 
-int
-PortFacade::get_connections (vector<string>& names) const 
+void
+Port::request_monitor_input (bool yn)
 {
-       int i = 0;
-
-       if (_ext_port) {
-               i = _ext_port->get_connections (names);
-       }
-
-       i += Port::get_connections (names);
-
-       return i;
+       jack_port_request_monitor (_jack_port, yn);
 }
 
 void
-PortFacade::reset ()
+Port::set_latency (nframes_t n)
+{
+       jack_port_set_latency (_jack_port, n);
+}
+
+bool
+Port::physically_connected () const
 {
-       Port::reset ();
+       const char** jc = jack_port_get_connections (_jack_port);
+
+       if (jc) {
+               for (int i = 0; jc[i]; ++i) {
 
-       if (_ext_port) {
-               _ext_port->reset ();
+                        jack_port_t* port = jack_port_by_name (_engine->jack(), jc[i]);
+                        
+                        if (port && (jack_port_flags (port) & JackPortIsPhysical)) {
+                                jack_free (jc);
+                                return true;
+                        }
+               }
+                
+               jack_free (jc);
        }
+
+        return false;
 }