X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fio.cc;h=a3549f0a1d3ff0895ae7c9fb9abe99435b3e0093;hb=34936f365404a42769cb85764ecf72ae065da651;hp=6d15d5847874acb0e42e8ae4efb3d56e2d716829;hpb=e9a8ccc7e2826d8fe91eff34ee8a0683a7f7aac6;p=ardour.git diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index 6d15d58478..a3549f0a1d 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -31,6 +31,8 @@ #include "pbd/replace_all.h" #include "pbd/unknown_type.h" #include "pbd/enumwriter.h" +#include "pbd/locale_guard.h" +#include "pbd/types_convert.h" #include "ardour/audioengine.h" #include "ardour/buffer.h" @@ -41,9 +43,10 @@ #include "ardour/profile.h" #include "ardour/route.h" #include "ardour/session.h" +#include "ardour/types_convert.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()) @@ -89,11 +92,14 @@ IO::~IO () { Glib::Threads::Mutex::Lock lm (io_lock); + DEBUG_TRACE (DEBUG::Ports, string_compose ("IO %1 unregisters %2 ports\n", name(), _ports.num_ports())); + BLOCK_PROCESS_CALLBACK (); for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) { _session.engine().unregister_port (*i); } + delete pending_state_node; pending_state_node = 0; } void @@ -142,7 +148,9 @@ IO::silence (framecnt_t nframes) /* io_lock, not taken: function must be called from Session::process() calltree */ for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) { - i->get_buffer(nframes).silence (nframes); + if (i->port_handle ()) { + i->get_buffer(nframes).silence (nframes); + } } } @@ -405,6 +413,7 @@ IO::ensure_ports_locked (ChanCount count, bool clear, bool& changed) #endif boost::shared_ptr port; + vector > deleted_ports; changed = false; @@ -418,11 +427,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) { @@ -527,25 +555,21 @@ XMLNode& IO::state (bool /*full_state*/) { XMLNode* node = new XMLNode (state_node_name); - char buf[64]; - string str; int n; - LocaleGuard lg; Glib::Threads::Mutex::Lock lm (io_lock); - node->add_property("name", _name); - id().print (buf, sizeof (buf)); - node->add_property("id", buf); - node->add_property ("direction", enum_2_string (_direction)); - node->add_property ("default-type", _default_type.to_string()); + node->set_property ("name", name()); + node->set_property ("id", id ()); + node->set_property ("direction", _direction); + node->set_property ("default-type", _default_type); if (!_pretty_name_prefix.empty ()) { - node->add_property("pretty-name", _pretty_name_prefix); + node->set_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 ()); + n->set_property ("name", (*i)->bundle->name ()); node->add_child_nocopy (*n); } @@ -554,8 +578,8 @@ IO::state (bool /*full_state*/) vector connections; XMLNode* pnode = new XMLNode (X_("Port")); - pnode->add_property (X_("type"), i->type().to_string()); - pnode->add_property (X_("name"), i->name()); + pnode->set_property (X_("type"), i->type()); + pnode->set_property (X_("name"), i->name()); if (i->get_connections (connections)) { vector::const_iterator ci; @@ -572,7 +596,7 @@ IO::state (bool /*full_state*/) XMLNode* cnode = new XMLNode (X_("Connection")); - cnode->add_property (X_("other"), _session.engine().make_port_name_relative (*ci)); + cnode->set_property (X_("other"), _session.engine().make_port_name_relative (*ci)); pnode->add_child_nocopy (*cnode); } } @@ -580,8 +604,7 @@ IO::state (bool /*full_state*/) node->add_child_nocopy (*pnode); } - snprintf (buf, sizeof (buf), "%" PRId64, _user_latency); - node->add_property (X_("user-latency"), buf); + node->set_property (X_("user-latency"), _user_latency); return *node; } @@ -595,10 +618,6 @@ IO::set_state (const XMLNode& node, int version) */ assert (version >= 3000); - XMLProperty const * prop; - XMLNodeConstIterator iter; - LocaleGuard lg; - /* force use of non-localized representation of decimal point, since we use it a lot in XML files and so forth. */ @@ -608,28 +627,27 @@ IO::set_state (const XMLNode& node, int version) return -1; } - if ((prop = node.property ("name")) != 0) { - set_name (prop->value()); + bool ignore_name = node.property ("ignore-name"); + std::string name; + if (node.get_property ("name", name) && !ignore_name) { + set_name (name); } - if ((prop = node.property (X_("default-type"))) != 0) { - _default_type = DataType(prop->value()); + if (node.get_property (X_("default-type"), _default_type)) { assert(_default_type != DataType::NIL); } set_id (node); - if ((prop = node.property ("direction")) != 0) { - _direction = (Direction) string_2_enum (prop->value(), _direction); - } + node.get_property ("direction", _direction); if (create_ports (node, version)) { return -1; } // after create_ports, updates names - if ((prop = node.property ("pretty-name")) != 0) { - set_pretty_name (prop->value()); + if (node.get_property ("pretty-name", name)) { + set_pretty_name (name); } if (connecting_legal) { @@ -640,15 +658,14 @@ IO::set_state (const XMLNode& node, int version) } else { + delete pending_state_node; pending_state_node = new XMLNode (node); pending_state_node_version = version; pending_state_node_in = false; ConnectingLegal.connect_same_thread (connection_legal_c, boost::bind (&IO::connecting_became_legal, this)); } - if ((prop = node.property ("user-latency")) != 0) { - _user_latency = atoi (prop->value ()); - } + node.get_property ("user-latency", _user_latency); return 0; } @@ -694,6 +711,7 @@ IO::set_state_2X (const XMLNode& node, int version, bool in) } else { + delete pending_state_node; pending_state_node = new XMLNode (node); pending_state_node_version = version; pending_state_node_in = in; @@ -737,6 +755,7 @@ IO::find_possible_bundle (const string &desired_name) string possible_name; bool stereo = false; string::size_type last_non_digit_pos; + std::string bundle_number_str; error << string_compose(_("Unknown bundle \"%1\" listed for %2 of %3"), desired_name, bundle_type_name, _name) << endmsg; @@ -747,9 +766,8 @@ IO::find_possible_bundle (const string &desired_name) last_non_digit_pos = desired_name.find_last_not_of(digits); if (last_non_digit_pos != string::npos) { - stringstream s; - s << desired_name.substr(last_non_digit_pos); - s >> bundle_number; + bundle_number_str = desired_name.substr(last_non_digit_pos); + bundle_number = string_to(bundle_number_str); } // see if it's a stereo connection e.g. "in 3+4" @@ -761,9 +779,8 @@ IO::find_possible_bundle (const string &desired_name) if (left_last_non_digit_pos != string::npos) { int left_bundle_number = 0; - stringstream s; - s << desired_name.substr(left_last_non_digit_pos, last_non_digit_pos-1); - s >> left_bundle_number; + bundle_number_str = desired_name.substr(left_last_non_digit_pos, last_non_digit_pos-1); + left_bundle_number = string_to(bundle_number_str); if (left_bundle_number > 0 && left_bundle_number + 1 == bundle_number) { bundle_number--; @@ -788,15 +805,12 @@ IO::find_possible_bundle (const string &desired_name) if (bundle_number & mask) { bundle_number &= ~mask; - stringstream s; - s << default_name << " " << bundle_number + 1; + std::string possible_name = default_name + " " + to_string(bundle_number + 1); if (stereo) { - s << "+" << bundle_number + 2; + possible_name += "+" + to_string(bundle_number + 2); } - possible_name = s.str(); - if ((c = _session.bundle_by_name (possible_name)) != 0) { break; } @@ -982,7 +996,7 @@ void IO::prepare_for_reset (XMLNode& node, const std::string& name) { /* reset name */ - node.add_property ("name", name); + node.set_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 @@ -1579,13 +1593,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; } @@ -1608,13 +1622,13 @@ IO::name_from_state (const XMLNode& node) void IO::set_name_in_state (XMLNode& node, const string& new_name) { - node.add_property (X_("name"), new_name); + node.set_property (X_("name"), new_name); XMLNodeList children = node.children (); for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) { if ((*i)->name() == X_("Port")) { string const old_name = (*i)->property(X_("name"))->value(); string const old_name_second_part = old_name.substr (old_name.find_first_of ("/") + 1); - (*i)->add_property (X_("name"), string_compose ("%1/%2", new_name, old_name_second_part)); + (*i)->set_property (X_("name"), string_compose ("%1/%2", new_name, old_name_second_part)); } } } @@ -1721,12 +1735,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);