X-Git-Url: https://main.carlh.net/gitweb/?p=ardour.git;a=blobdiff_plain;f=libs%2Fardour%2Fio.cc;h=f535467cbe664874408bf32454546d030124b54e;hp=2cc213f7975932624527f6ee58cd1c850aa14c01;hb=c8c6bca6587450ff64303dbc994a4cd28d6ce7aa;hpb=f4b5f4c72ee60b6f509e307c5bfd164108d1f30b diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index 2cc213f797..f535467cbe 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -16,7 +16,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include @@ -39,11 +38,12 @@ #include "ardour/debug.h" #include "ardour/io.h" #include "ardour/port.h" +#include "ardour/profile.h" #include "ardour/route.h" #include "ardour/session.h" #include "ardour/user_bundle.h" -#include "i18n.h" +#include "pbd/i18n.h" #define BLOCK_PROCESS_CALLBACK() Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock()) @@ -99,6 +99,9 @@ IO::~IO () void IO::disconnect_check (boost::shared_ptr a, boost::shared_ptr b) { + if (_session.state_of_the_state () & Session::Deletion) { + return; + } /* 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, @@ -112,7 +115,7 @@ IO::disconnect_check (boost::shared_ptr a, boost::shared_ptr b) * ::disconnect() */ if (_ports.contains (a) || _ports.contains (b)) { - changed (IOChange (IOChange::ConnectionsChanged), this); /* EMIT SIGNAL */ + changed (IOChange (IOChange::ConnectionsChanged), this); /* EMIT SIGNAL */ } } else { /* we didn't get the lock, so assume that we're inside @@ -298,7 +301,7 @@ IO::remove_port (boost::shared_ptr port, void* src) } _session.set_dirty (); - + return 0; } @@ -320,12 +323,12 @@ IO::add_port (string destination, void* src, DataType type) ChanCount before = _ports.count (); ChanCount after = before; after.set (type, after.get (type) + 1); - + bool const r = PortCountChanging (after); /* EMIT SIGNAL */ if (r) { return -1; } - + IOChange change; { @@ -338,7 +341,7 @@ IO::add_port (string destination, void* src, DataType type) /* Create a new port */ string portname = build_legal_port_name (type); - + if (_direction == Input) { if ((our_port = _session.engine().register_input_port (type, portname)) == 0) { error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg; @@ -354,7 +357,7 @@ IO::add_port (string destination, void* src, DataType type) change.before = _ports.count (); _ports.add (our_port); } - + PortCountChanged (n_ports()); /* EMIT SIGNAL */ change.type = IOChange::ConfigurationChanged; change.after = _ports.count (); @@ -368,6 +371,7 @@ IO::add_port (string destination, void* src, DataType type) } } + apply_pretty_name (); setup_bundle (); _session.set_dirty (); @@ -401,6 +405,7 @@ IO::ensure_ports_locked (ChanCount count, bool clear, bool& changed) #endif boost::shared_ptr port; + vector > deleted_ports; changed = false; @@ -414,11 +419,30 @@ IO::ensure_ports_locked (ChanCount count, bool clear, bool& changed) assert(port); _ports.remove(port); + + /* hold a reference to the port so that we can ensure + * that this thread, and not a JACK notification thread, + * holds the final reference. + */ + + deleted_ports.push_back (port); _session.engine().unregister_port (port); changed = true; } + /* this will drop the final reference to the deleted ports, + * which will in turn call their destructors, which will in + * turn call the backend to unregister them. + * + * There will no connect/disconnect or register/unregister + * callbacks from the backend until we get here, because + * they are driven by the Port destructor. The destructor + * will not execute until we drop the final reference, + * which all happens right .... here. + */ + deleted_ports.clear (); + /* create any necessary new ports */ while (n_ports().get(*t) < n) { @@ -525,9 +549,8 @@ IO::state (bool /*full_state*/) XMLNode* node = new XMLNode (state_node_name); char buf[64]; string str; - vector::iterator ci; int n; - LocaleGuard lg (X_("POSIX")); + LocaleGuard lg; Glib::Threads::Mutex::Lock lm (io_lock); node->add_property("name", _name); @@ -536,6 +559,10 @@ IO::state (bool /*full_state*/) node->add_property ("direction", enum_2_string (_direction)); node->add_property ("default-type", _default_type.to_string()); + if (!_pretty_name_prefix.empty ()) { + node->add_property("pretty-name", _pretty_name_prefix); + } + for (std::vector::iterator i = _bundles_connected.begin(); i != _bundles_connected.end(); ++i) { XMLNode* n = new XMLNode ("Bundle"); n->add_property ("name", (*i)->bundle->name ()); @@ -551,6 +578,8 @@ IO::state (bool /*full_state*/) pnode->add_property (X_("name"), i->name()); if (i->get_connections (connections)) { + vector::const_iterator ci; + std::sort (connections.begin(), connections.end()); for (n = 0, ci = connections.begin(); ci != connections.end(); ++ci, ++n) { @@ -573,7 +602,7 @@ IO::state (bool /*full_state*/) snprintf (buf, sizeof (buf), "%" PRId64, _user_latency); node->add_property (X_("user-latency"), buf); - + return *node; } @@ -586,9 +615,9 @@ IO::set_state (const XMLNode& node, int version) */ assert (version >= 3000); - const XMLProperty* prop; + XMLProperty const * prop; XMLNodeConstIterator iter; - LocaleGuard lg (X_("POSIX")); + LocaleGuard lg; /* force use of non-localized representation of decimal point, since we use it a lot in XML files and so forth. @@ -618,6 +647,11 @@ IO::set_state (const XMLNode& node, int version) return -1; } + // after create_ports, updates names + if ((prop = node.property ("pretty-name")) != 0) { + set_pretty_name (prop->value()); + } + if (connecting_legal) { if (make_connections (node, version, false)) { @@ -642,9 +676,9 @@ IO::set_state (const XMLNode& node, int version) int IO::set_state_2X (const XMLNode& node, int version, bool in) { - const XMLProperty* prop; + XMLProperty const * prop; XMLNodeConstIterator iter; - LocaleGuard lg (X_("POSIX")); + LocaleGuard lg; /* force use of non-localized representation of decimal point, since we use it a lot in XML files and so forth. @@ -692,13 +726,16 @@ IO::set_state_2X (const XMLNode& node, int version, bool in) int IO::connecting_became_legal () { - int ret; + int ret = 0; assert (pending_state_node); connection_legal_c.disconnect (); - ret = make_connections (*pending_state_node, pending_state_node_version, pending_state_node_in); + // it's not required for TracksLive, as long as TracksLive's session does all the connections when it's being loaded + if (!Profile->get_trx() ) { + ret = make_connections (*pending_state_node, pending_state_node_version, pending_state_node_in); + } delete pending_state_node; pending_state_node = 0; @@ -854,6 +891,7 @@ IO::get_port_counts (const XMLNode& node, int version, ChanCount& n, boost::shar for (iter = node.children().begin(); iter != node.children().end(); ++iter) { if ((*iter)->name() == X_("Bundle")) { + prop = (*iter)->property ("name"); if ((c = find_possible_bundle (prop->value())) != 0) { n = ChanCount::max (n, c->nchannels()); return 0; @@ -910,7 +948,7 @@ IO::make_connections (const XMLNode& node, int version, bool in) return make_connections_2X (node, version, in); } - const XMLProperty* prop; + XMLProperty const * prop; for (XMLNodeConstIterator i = node.children().begin(); i != node.children().end(); ++i) { @@ -971,15 +1009,15 @@ IO::prepare_for_reset (XMLNode& node, const std::string& name) the name of the thing we're applying it to. */ - XMLProperty* prop; + 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(); @@ -987,10 +1025,10 @@ IO::prepare_for_reset (XMLNode& node, const std::string& name) if (slash != string::npos) { /* port name is of form: / */ - + new_name = name; new_name += old.substr (old.find ('/')); - + prop->set_value (new_name); } } @@ -1002,7 +1040,7 @@ IO::prepare_for_reset (XMLNode& node, const std::string& name) int IO::make_connections_2X (const XMLNode& node, int /*version*/, bool in) { - const XMLProperty* prop; + XMLProperty const * prop; /* XXX: bundles ("connections" as was) */ @@ -1039,7 +1077,8 @@ IO::make_connections_2X (const XMLNode& node, int /*version*/, bool in) if (p != string::npos) { ports[x].replace (p, 4, "/audio_out"); } - nth(i)->connect (ports[x]); + if (NULL != nth(i).get()) + nth(i)->connect (ports[x]); } } @@ -1081,7 +1120,8 @@ IO::make_connections_2X (const XMLNode& node, int /*version*/, bool in) if (p != string::npos) { ports[x].replace (p, 3, "/audio_in"); } - nth(i)->connect (ports[x]); + if (NULL != nth(i).get()) + nth(i)->connect (ports[x]); } } @@ -1097,7 +1137,6 @@ int IO::set_ports (const string& str) { vector ports; - int i; int n; uint32_t nports; @@ -1114,14 +1153,10 @@ IO::set_ports (const string& str) } } - string::size_type start, end, ostart; - - ostart = 0; - start = 0; - end = 0; - i = 0; - - while ((start = str.find_first_of ('{', ostart)) != string::npos) { + string::size_type start = 0; + string::size_type end = 0; + string::size_type ostart = 0; + for (int i = 0; (start = str.find_first_of ('{', ostart)) != string::npos; ++i) { start += 1; if ((end = str.find_first_of ('}', start)) == string::npos) { @@ -1142,7 +1177,6 @@ IO::set_ports (const string& str) } ostart = end+1; - i++; } return 0; @@ -1157,7 +1191,6 @@ IO::parse_io_string (const string& str, vector& ports) return 0; } - pos = 0; opos = 0; ports.clear (); @@ -1179,7 +1212,6 @@ IO::parse_gain_string (const string& str, vector& ports) { string::size_type pos, opos; - pos = 0; opos = 0; ports.clear (); @@ -1221,6 +1253,31 @@ IO::set_name (const string& requested_name) return r; } +void +IO::set_pretty_name (const std::string& str) +{ + if (_pretty_name_prefix == str) { + return; + } + _pretty_name_prefix = str; + apply_pretty_name (); +} + +void +IO::apply_pretty_name () +{ + uint32_t pn = 1; + if (_pretty_name_prefix.empty ()) { + return; + } + for (PortSet::iterator i = _ports.begin (); i != _ports.end(); ++i, ++pn) { + (*i)->set_pretty_name (string_compose (("%1/%2 %3"), + _pretty_name_prefix, + _direction == Output ? _("Out") : _("In"), + pn)); + } +} + framecnt_t IO::latency () const { @@ -1542,13 +1599,13 @@ IO::bundle_channel_name (uint32_t c, uint32_t n, DataType t) const case 2: return c == 0 ? _("L") : _("R"); default: - snprintf (buf, sizeof(buf), _("%d"), (c + 1)); + snprintf (buf, sizeof(buf), "%d", (c + 1)); return buf; } } else { - snprintf (buf, sizeof(buf), _("%d"), (c + 1)); + snprintf (buf, sizeof(buf), "%d", (c + 1)); return buf; } @@ -1559,7 +1616,7 @@ IO::bundle_channel_name (uint32_t c, uint32_t n, DataType t) const string IO::name_from_state (const XMLNode& node) { - const XMLProperty* prop; + XMLProperty const * prop; if ((prop = node.property ("name")) != 0) { return prop->value(); @@ -1611,8 +1668,10 @@ IO::connected_to (boost::shared_ptr other) const for (i = 0; i < no; ++i) { for (j = 0; j < ni; ++j) { - if (nth(i)->connected_to (other->nth(j)->name())) { - return true; + if ((NULL != nth(i).get()) && (NULL != other->nth(j).get())) { + if (nth(i)->connected_to (other->nth(j)->name())) { + return true; + } } } } @@ -1636,7 +1695,7 @@ IO::connected_to (const string& str) const * Caller must hold process lock. */ void -IO::process_input (boost::shared_ptr proc, framepos_t start_frame, framepos_t end_frame, pframes_t nframes) +IO::process_input (boost::shared_ptr proc, framepos_t start_frame, framepos_t end_frame, double speed, pframes_t nframes) { /* don't read the data into new buffers - just use the port buffers directly */ @@ -1647,7 +1706,7 @@ IO::process_input (boost::shared_ptr proc, framepos_t start_frame, fr _buffers.get_backend_port_addresses (_ports, nframes); if (proc) { - proc->run (_buffers, start_frame, end_frame, nframes, true); + proc->run (_buffers, start_frame, end_frame, speed, nframes, true); } } @@ -1673,7 +1732,7 @@ IO::collect_input (BufferSet& bufs, pframes_t nframes, ChanCount offset) } for ( ; i != _ports.end(*t); ++i, ++b) { - Buffer& bb (i->get_buffer (nframes)); + const Buffer& bb (i->get_buffer (nframes)); b->read_from (bb, nframes); } } @@ -1682,12 +1741,14 @@ IO::collect_input (BufferSet& bufs, pframes_t nframes, ChanCount offset) void IO::copy_to_outputs (BufferSet& bufs, DataType type, pframes_t nframes, framecnt_t offset) { - // Copy any buffers 1:1 to outputs - PortSet::iterator o = _ports.begin(type); BufferSet::iterator i = bufs.begin(type); BufferSet::iterator prev = i; + assert(i != bufs.end(type)); // or second loop will crash + + // Copy any buffers 1:1 to outputs + while (i != bufs.end(type) && o != _ports.end (type)) { Buffer& port_buffer (o->get_buffer (nframes)); port_buffer.read_from (*i, nframes, offset);