more work on RID and editor/mixer order matching; when a track/bus is hidden in the...
[ardour.git] / libs / ardour / io.cc
index 24bc587c0d4503a4fa52045bd9e6fc8883765a6c..01a4a64a389554e35da4f721b2f3c4497eb94a27 100644 (file)
 
 #include "ardour/audioengine.h"
 #include "ardour/buffer.h"
+#include "ardour/buffer_set.h"
 #include "ardour/debug.h"
 #include "ardour/io.h"
-#include "ardour/route.h"
 #include "ardour/port.h"
-#include "ardour/audio_port.h"
-#include "ardour/midi_port.h"
+#include "ardour/route.h"
 #include "ardour/session.h"
-#include "ardour/cycle_timer.h"
-#include "ardour/buffer_set.h"
-#include "ardour/meter.h"
-#include "ardour/amp.h"
 #include "ardour/user_bundle.h"
 
 #include "i18n.h"
@@ -63,23 +58,27 @@ PBD::Signal1<void,ChanCount> IO::PortCountChanged;
 /** @param default_type The type of port that will be created by ensure_io
  * and friends if no type is explicitly requested (to avoid breakage).
  */
-IO::IO (Session& s, const string& name, Direction dir, DataType default_type)
+IO::IO (Session& s, const string& name, Direction dir, DataType default_type, bool sendish)
        : SessionObject (s, name)
        , _direction (dir)
        , _default_type (default_type)
+       , _sendish (sendish)
 {
        _active = true;
+       Port::PostDisconnect.connect_same_thread (*this, boost::bind (&IO::disconnect_check, this, _1, _2));
        pending_state_node = 0;
        setup_bundle ();
 }
 
-IO::IO (Session& s, const XMLNode& node, DataType dt)
+IO::IO (Session& s, const XMLNode& node, DataType dt, bool sendish)
        : SessionObject(s, "unnamed io")
        , _direction (Input)
        , _default_type (dt)
+       , _sendish (sendish)
 {
        _active = true;
        pending_state_node = 0;
+       Port::PostDisconnect.connect_same_thread (*this, boost::bind (&IO::disconnect_check, this, _1, _2));
 
        set_state (node, Stateful::loading_state_version);
        setup_bundle ();
@@ -96,6 +95,31 @@ IO::~IO ()
        }
 }
 
+void
+IO::disconnect_check (boost::shared_ptr<Port> a, boost::shared_ptr<Port> b)
+{
+       /* this could be called from within our own ::disconnect() method(s)
+          or from somewhere that operates directly on a port. so, we don't
+          know for sure if we can take this lock or not. if we fail,
+          we assume that its safely locked by our own ::disconnect().
+       */
+
+       Glib::Mutex::Lock tm (io_lock, Glib::TRY_LOCK);
+
+       if (tm.locked()) {
+               /* we took the lock, so we cannot be here from inside
+                * ::disconnect()
+                */
+               if (_ports.contains (a) || _ports.contains (b)) {
+                       changed (IOChange (IOChange::ConnectionsChanged), this); /* EMIT SIGNAL */              
+               }
+       } else {
+               /* we didn't get the lock, so assume that we're inside
+                * ::disconnect(), and it will call changed() appropriately.
+                */
+       }
+}
+
 void
 IO::increment_port_buffer_offset (pframes_t offset)
 {
@@ -229,8 +253,8 @@ IO::remove_port (boost::shared_ptr<Port> port, void* src)
        ChanCount after = before;
        after.set (port->type(), after.get (port->type()) - 1);
 
-       bool const r = PortCountChanging (after); /* EMIT SIGNAL */
-       if (r) {
+       boost::optional<bool> const r = PortCountChanging (after); /* EMIT SIGNAL */
+       if (r.get_value_or (false)) {
                return -1;
        }
 
@@ -929,6 +953,44 @@ IO::make_connections (const XMLNode& node, int version, bool in)
        return 0;
 }
 
+void
+IO::prepare_for_reset (XMLNode& node, const std::string& name)
+{
+       /* reset name */
+       node.add_property ("name", name);
+
+       /* now find connections and reset the name of the port
+          in one so that when we re-use it it will match
+          the name of the thing we're applying it to.
+       */
+
+       XMLProperty* prop;
+       XMLNodeList children = node.children();
+
+       for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) {
+
+               if ((*i)->name() == "Port") {
+                       
+                       prop = (*i)->property (X_("name"));
+                       
+                       if (prop) {
+                               string new_name;
+                               string old = prop->value();
+                               string::size_type slash = old.find ('/');
+
+                               if (slash != string::npos) {
+                                       /* port name is of form: <IO-name>/<port-name> */
+                                       
+                                       new_name = name;
+                                       new_name += old.substr (old.find ('/'));
+                                       
+                                       prop->set_value (new_name);
+                               }
+                       }
+               }
+       }
+}
+
 
 int
 IO::make_connections_2X (const XMLNode& node, int /*version*/, bool in)
@@ -1252,6 +1314,7 @@ IO::disable_connecting ()
 int
 IO::enable_connecting ()
 {
+       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock());
        connecting_legal = true;
        boost::optional<int> r = ConnectingLegal ();
        return r.get_value_or (0);
@@ -1286,10 +1349,18 @@ IO::build_legal_port_name (DataType type)
           use the (new) translated name.
        */
 
-       if (_direction == Input) {
-               suffix += X_("_in");
+       if (_sendish) {
+               if (_direction == Input) {
+                       suffix += X_("_return");
+               } else {
+                       suffix += X_("_send");
+               }
        } else {
-               suffix += X_("_out");
+               if (_direction == Input) {
+                       suffix += X_("_in");
+               } else {
+                       suffix += X_("_out");
+               }
        }
 
        // allow up to 4 digits for the output port number, plus the slash, suffix and extra space
@@ -1548,7 +1619,9 @@ IO::connected_to (const string& str) const
        return false;
 }
 
-/** Caller must hold process lock */
+/** Call a processor's ::run() method, giving it our buffers
+ *  Caller must hold process lock.
+ */
 void
 IO::process_input (boost::shared_ptr<Processor> proc, framepos_t start_frame, framepos_t end_frame, pframes_t nframes)
 {