diff options
Diffstat (limited to 'libs/ardour/io.cc')
-rw-r--r-- | libs/ardour/io.cc | 705 |
1 files changed, 350 insertions, 355 deletions
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index 95f40f1f80..d0a233a356 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -34,7 +34,7 @@ #include <ardour/port.h> #include <ardour/audio_port.h> #include <ardour/midi_port.h> -#include <ardour/bundle.h> +#include <ardour/auto_bundle.h> #include <ardour/session.h> #include <ardour/cycle_timer.h> #include <ardour/panner.h> @@ -153,7 +153,7 @@ IO::IO (Session& s, const string& name, _session.add_controllable (_gain_control); - create_bundles (); + create_bundles_for_inputs_and_outputs (); } IO::IO (Session& s, const XMLNode& node, DataType dt) @@ -193,7 +193,7 @@ IO::IO (Session& s, const XMLNode& node, DataType dt) _session.add_controllable (_gain_control); - create_bundles (); + create_bundles_for_inputs_and_outputs (); } IO::~IO () @@ -334,24 +334,62 @@ IO::just_meter_input (nframes_t start_frame, nframes_t end_frame, _meter->run(bufs, start_frame, end_frame, nframes, offset); } + void -IO::drop_input_bundle () +IO::check_bundles_connected_to_inputs () { - _input_bundle.reset (); - input_bundle_configuration_connection.disconnect(); - input_bundle_connection_connection.disconnect(); - _session.set_dirty (); + check_bundles (_bundles_connected_to_inputs, inputs()); } void -IO::drop_output_bundle () +IO::check_bundles_connected_to_outputs () { - _output_bundle.reset (); - output_bundle_configuration_connection.disconnect(); - output_bundle_connection_connection.disconnect(); - _session.set_dirty (); + check_bundles (_bundles_connected_to_outputs, outputs()); } +void +IO::check_bundles (std::vector<UserBundleInfo>& list, const PortSet& ports) +{ + std::vector<UserBundleInfo> new_list; + + for (std::vector<UserBundleInfo>::iterator i = list.begin(); i != list.end(); ++i) { + + uint32_t const N = i->bundle->nchannels (); + + if (ports.num_ports() < N) { + continue; + } + + bool ok = true; + for (uint32_t j = 0; j < N; ++j) { + /* Every port on bundle channel j must be connected to our input j */ + PortList const pl = i->bundle->channel_ports (j); + for (uint32_t k = 0; k < pl.size(); ++k) { + if (ports.port(j)->connected_to (pl[k]) == false) { + ok = false; + break; + } + } + + if (ok == false) { + break; + } + } + + if (ok) { + new_list.push_back (*i); + } else { + i->configuration_will_change.disconnect (); + i->configuration_has_changed.disconnect (); + i->ports_will_change.disconnect (); + i->ports_have_changed.disconnect (); + } + } + + list = new_list; +} + + int IO::disconnect_input (Port* our_port, string other_port, void* src) { @@ -378,7 +416,7 @@ IO::disconnect_input (Port* our_port, string other_port, void* src) return -1; } - drop_input_bundle (); + check_bundles_connected_to_inputs (); } } @@ -412,8 +450,6 @@ IO::connect_input (Port* our_port, string other_port, void* src) if (_session.engine().connect (other_port, our_port->name())) { return -1; } - - drop_input_bundle (); } } @@ -448,7 +484,7 @@ IO::disconnect_output (Port* our_port, string other_port, void* src) return -1; } - drop_output_bundle (); + check_bundles_connected_to_outputs (); } } @@ -482,8 +518,6 @@ IO::connect_output (Port* our_port, string other_port, void* src) if (_session.engine().connect (our_port->name(), other_port)) { return -1; } - - drop_output_bundle (); } } @@ -544,7 +578,7 @@ IO::remove_output_port (Port* port, void* src) } _session.engine().unregister_port (*port); - drop_output_bundle (); + check_bundles_connected_to_outputs (); setup_peak_meters (); reset_panner (); @@ -555,7 +589,7 @@ IO::remove_output_port (Port* port, void* src) } if (change == ConnectionsChanged) { - setup_bundles (); + setup_bundles_for_inputs_and_outputs (); } if (change != NoChange) { @@ -608,7 +642,6 @@ IO::add_output_port (string destination, void* src, DataType type) } _outputs.add (our_port); - drop_output_bundle (); setup_peak_meters (); reset_panner (); } @@ -624,7 +657,7 @@ IO::add_output_port (string destination, void* src, DataType type) // pan_changed (src); /* EMIT SIGNAL */ output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ - setup_bundles (); + setup_bundles_for_inputs_and_outputs (); _session.set_dirty (); return 0; @@ -655,7 +688,7 @@ IO::remove_input_port (Port* port, void* src) } _session.engine().unregister_port (*port); - drop_input_bundle (); + check_bundles_connected_to_inputs (); setup_peak_meters (); reset_panner (); @@ -666,7 +699,7 @@ IO::remove_input_port (Port* port, void* src) } if (change == ConfigurationChanged) { - setup_bundles (); + setup_bundles_for_inputs_and_outputs (); } if (change != NoChange) { @@ -719,7 +752,6 @@ IO::add_input_port (string source, void* src, DataType type) } _inputs.add (our_port); - drop_input_bundle (); setup_peak_meters (); reset_panner (); } @@ -736,7 +768,7 @@ IO::add_input_port (string source, void* src, DataType type) // pan_changed (src); /* EMIT SIGNAL */ input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ - setup_bundles (); + setup_bundles_for_inputs_and_outputs (); _session.set_dirty (); return 0; @@ -755,7 +787,7 @@ IO::disconnect_inputs (void* src) _session.engine().disconnect (*i); } - drop_input_bundle (); + check_bundles_connected_to_inputs (); } } @@ -777,7 +809,7 @@ IO::disconnect_outputs (void* src) _session.engine().disconnect (*i); } - drop_output_bundle (); + check_bundles_connected_to_outputs (); } } @@ -841,7 +873,7 @@ IO::ensure_inputs_locked (ChanCount count, bool clear, void* src) } if (changed) { - drop_input_bundle (); + check_bundles_connected_to_inputs (); setup_peak_meters (); reset_panner (); PortCountChanged (n_inputs()); /* EMIT SIGNAL */ @@ -1008,18 +1040,18 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src) } if (out_changed) { - drop_output_bundle (); + check_bundles_connected_to_outputs (); output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ } if (in_changed) { - drop_input_bundle (); + check_bundles_connected_to_inputs (); input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ } if (in_changed || out_changed) { PortCountChanged (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */ - setup_bundles (); + setup_bundles_for_inputs_and_outputs (); _session.set_dirty (); } @@ -1047,7 +1079,7 @@ IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src) if (changed) { input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ - setup_bundles (); + setup_bundles_for_inputs_and_outputs (); _session.set_dirty (); } return 0; @@ -1106,7 +1138,7 @@ IO::ensure_outputs_locked (ChanCount count, bool clear, void* src) } if (changed) { - drop_output_bundle (); + check_bundles_connected_to_outputs (); PortCountChanged (n_outputs()); /* EMIT SIGNAL */ _session.set_dirty (); } @@ -1145,7 +1177,7 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src) if (changed) { output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ - setup_bundles (); + setup_bundles_for_inputs_and_outputs (); } return 0; @@ -1209,8 +1241,6 @@ IO::state (bool full_state) XMLNode* node = new XMLNode (state_node_name); char buf[64]; string str; - bool need_ins = true; - bool need_outs = true; LocaleGuard lg (X_("POSIX")); Glib::Mutex::Lock lm (io_lock); @@ -1218,83 +1248,91 @@ IO::state (bool full_state) id().print (buf, sizeof (buf)); node->add_property("id", buf); - str = ""; - - if (_input_bundle && !_input_bundle->dynamic()) { - node->add_property ("input-connection", _input_bundle->name()); - need_ins = false; + for ( + std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_inputs.begin(); + i != _bundles_connected_to_inputs.end(); + ++i + ) + { + XMLNode* n = new XMLNode ("InputBundle"); + n->add_property ("name", i->bundle->name ()); + node->add_child_nocopy (*n); } - if (_output_bundle && !_output_bundle->dynamic()) { - node->add_property ("output-connection", _output_bundle->name()); - need_outs = false; + for ( + std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_outputs.begin(); + i != _bundles_connected_to_outputs.end(); + ++i + ) + { + XMLNode* n = new XMLNode ("OutputBundle"); + n->add_property ("name", i->bundle->name ()); + node->add_child_nocopy (*n); } + + str = ""; - if (need_ins) { - for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { - const char **connections = i->get_connections(); + const char **connections = i->get_connections(); + + if (connections && connections[0]) { + str += '{'; - if (connections && connections[0]) { - str += '{'; + for (int n = 0; connections && connections[n]; ++n) { + if (n) { + str += ','; + } - for (int n = 0; connections && connections[n]; ++n) { - if (n) { - str += ','; - } - - /* if its a connection to our own port, - return only the port name, not the - whole thing. this allows connections - to be re-established even when our - client name is different. - */ - - str += _session.engine().make_port_name_relative (connections[n]); - } - - str += '}'; + /* if its a connection to our own port, + return only the port name, not the + whole thing. this allows connections + to be re-established even when our + client name is different. + */ - free (connections); - } - else { - str += "{}"; - } + str += _session.engine().make_port_name_relative (connections[n]); + } + + str += '}'; + + free (connections); + } + else { + str += "{}"; } - - node->add_property ("inputs", str); } + + node->add_property ("inputs", str); - if (need_outs) { - str = ""; + str = ""; + + for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { - for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + const char **connections = i->get_connections(); + + if (connections && connections[0]) { - const char **connections = i->get_connections(); + str += '{'; - if (connections && connections[0]) { - - str += '{'; - - for (int n = 0; connections[n]; ++n) { - if (n) { - str += ','; - } - - str += _session.engine().make_port_name_relative (connections[n]); + for (int n = 0; connections[n]; ++n) { + if (n) { + str += ','; } - - str += '}'; - free (connections); - } - else { - str += "{}"; + str += _session.engine().make_port_name_relative (connections[n]); } + + str += '}'; + + free (connections); + } + else { + str += "{}"; } - - node->add_property ("outputs", str); } + + node->add_property ("outputs", str); node->add_child_nocopy (_panner->state (full_state)); node->add_child_nocopy (_gain_control->get_state ()); @@ -1575,55 +1613,12 @@ IO::ports_became_legal () int IO::create_ports (const XMLNode& node) { - const XMLProperty* prop; + XMLProperty const * prop; int num_inputs = 0; int num_outputs = 0; - /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to - * break the session file format. - */ - if ((prop = node.property ("input-connection")) != 0) { - - boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value()); - - if (c == 0) { - error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg; - - if ((c = _session.bundle_by_name (_("in 1"))) == 0) { - error << _("No input bundles available as a replacement") - << endmsg; - return -1; - } else { - info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value()) - << endmsg; - } - } - - num_inputs = c->nchannels(); - - } else if ((prop = node.property ("inputs")) != 0) { - + if ((prop = node.property ("inputs")) != 0) { num_inputs = count (prop->value().begin(), prop->value().end(), '{'); - } - - if ((prop = node.property ("output-connection")) != 0) { - boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value()); - - if (c == 0) { - error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg; - - if ((c = _session.bundle_by_name (_("out 1"))) == 0) { - error << _("No output bundles available as a replacement") - << endmsg; - return -1; - } else { - info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value()) - << endmsg; - } - } - - num_outputs = c->nchannels (); - } else if ((prop = node.property ("outputs")) != 0) { num_outputs = count (prop->value().begin(), prop->value().end(), '{'); } @@ -1648,57 +1643,48 @@ IO::create_ports (const XMLNode& node) int IO::make_connections (const XMLNode& node) { - const XMLProperty* prop; - - if ((prop = node.property ("input-connection")) != 0) { - boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value()); - - if (c == 0) { - error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg; - - if ((c = _session.bundle_by_name (_("in 1"))) == 0) { - error << _("No input connections available as a replacement") - << endmsg; - return -1; - } else { - info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value()) - << endmsg; - } - } - - connect_input_ports_to_bundle (c, this); - - } else if ((prop = node.property ("inputs")) != 0) { + XMLProperty const * prop; + + if ((prop = node.property ("inputs")) != 0) { if (set_inputs (prop->value())) { error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg; return -1; } } - - if ((prop = node.property ("output-bundle")) != 0) { - boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value()); - - if (c == 0) { - error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg; - if ((c = _session.bundle_by_name (_("out 1"))) == 0) { - error << _("No output bundles available as a replacement") - << endmsg; - return -1; - } else { - info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value()) - << endmsg; - } - } - - connect_output_ports_to_bundle (c, this); - - } else if ((prop = node.property ("outputs")) != 0) { + + if ((prop = node.property ("outputs")) != 0) { if (set_outputs (prop->value())) { error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg; return -1; } } + + for (XMLNodeConstIterator i = node.children().begin(); i != node.children().end(); ++i) { + + if ((*i)->name() == "InputBundle") { + XMLProperty const * prop = (*i)->property ("name"); + if (prop) { + boost::shared_ptr<Bundle> b = _session.bundle_by_name (prop->value()); + if (b) { + connect_input_ports_to_bundle (b, this); + } else { + error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg; + } + } + + } else if ((*i)->name() == "OutputBundle") { + XMLProperty const * prop = (*i)->property ("name"); + if (prop) { + boost::shared_ptr<Bundle> b = _session.bundle_by_name (prop->value()); + if (b) { + connect_output_ports_to_bundle (b, this); + } else { + error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg; + } + } + } + } return 0; } @@ -1880,7 +1866,7 @@ IO::set_name (const string& str) bool const r = SessionObject::set_name(name); - setup_bundles (); + setup_bundles_for_inputs_and_outputs (); return r; } @@ -1960,61 +1946,21 @@ IO::input_latency () const int IO::connect_input_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src) { - uint32_t limit; - { BLOCK_PROCESS_CALLBACK (); Glib::Mutex::Lock lm2 (io_lock); - - limit = c->nchannels(); - - drop_input_bundle (); - - // FIXME bundles only work for audio-only - if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) { - return -1; - } - /* first pass: check the current state to see what's correctly - connected, and drop anything that we don't want. - */ - - for (uint32_t n = 0; n < limit; ++n) { - const Bundle::PortList& pl = c->channel_ports (n); - - for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { - - if (!_inputs.port(n)->connected_to ((*i))) { - - /* clear any existing connections */ - - _session.engine().disconnect (*_inputs.port(n)); - - } else if (_inputs.port(n)->connected() > 1) { - - /* OK, it is connected to the port we want, - but its also connected to other ports. - Change that situation. - */ - - /* XXX could be optimized to not drop - the one we want. - */ - - _session.engine().disconnect (*_inputs.port(n)); - - } - } - } - - /* second pass: connect all requested ports where necessary */ + /* Connect to the bundle, not worrying about any connections + that are already made. */ + + uint32_t const channels = c->nchannels (); - for (uint32_t n = 0; n < limit; ++n) { - const Bundle::PortList& pl = c->channel_ports (n); - - for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { - - if (!_inputs.port(n)->connected_to ((*i))) { + for (uint32_t n = 0; n < channels; ++n) { + const PortList& pl = c->channel_ports (n); + + for (PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { + + if (!_inputs.port(n)->connected_to (*i)) { if (_session.engine().connect (*i, _inputs.port(n)->name())) { return -1; @@ -2023,13 +1969,23 @@ IO::connect_input_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src) } } - - _input_bundle = c; - - input_bundle_configuration_connection = c->ConfigurationChanged.connect - (mem_fun (*this, &IO::input_bundle_configuration_changed)); - input_bundle_connection_connection = c->PortsChanged.connect - (mem_fun (*this, &IO::input_bundle_connection_changed)); + + /* If this is a UserBundle, make a note of what we've done */ + + boost::shared_ptr<UserBundle> ub = boost::dynamic_pointer_cast<UserBundle> (c); + if (ub) { + + /* See if we already know about this one */ + std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_inputs.begin(); + while (i != _bundles_connected_to_inputs.end() && i->bundle != ub) { + ++i; + } + + if (i == _bundles_connected_to_inputs.end()) { + /* We don't, so make a note */ + _bundles_connected_to_inputs.push_back (UserBundleInfo (this, ub)); + } + } } input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */ @@ -2039,62 +1995,22 @@ IO::connect_input_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src) int IO::connect_output_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src) { - uint32_t limit; - { BLOCK_PROCESS_CALLBACK (); Glib::Mutex::Lock lm2 (io_lock); - limit = c->nchannels(); - - drop_output_bundle (); - - // FIXME: audio-only - if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) { - return -1; - } - - /* first pass: check the current state to see what's correctly - connected, and drop anything that we don't want. - */ - - for (uint32_t n = 0; n < limit; ++n) { - - const Bundle::PortList& pl = c->channel_ports (n); - - for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { - - if (!_outputs.port(n)->connected_to ((*i))) { - - /* clear any existing connections */ - - _session.engine().disconnect (*_outputs.port(n)); + /* Connect to the bundle, not worrying about any connections + that are already made. */ - } else if (_outputs.port(n)->connected() > 1) { + uint32_t const channels = c->nchannels (); - /* OK, it is connected to the port we want, - but its also connected to other ports. - Change that situation. - */ + for (uint32_t n = 0; n < channels; ++n) { - /* XXX could be optimized to not drop - the one we want. - */ - - _session.engine().disconnect (*_outputs.port(n)); - } - } - } + const PortList& pl = c->channel_ports (n); - /* second pass: connect all requested ports where necessary */ + for (PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { - for (uint32_t n = 0; n < limit; ++n) { - - const Bundle::PortList& pl = c->channel_ports (n); - - for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { - - if (!_outputs.port(n)->connected_to ((*i))) { + if (!_outputs.port(n)->connected_to (*i)) { if (_session.engine().connect (_outputs.port(n)->name(), *i)) { return -1; @@ -2103,12 +2019,22 @@ IO::connect_output_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src) } } - _output_bundle = c; + /* If this is a UserBundle, make a note of what we've done */ - output_bundle_configuration_connection = c->ConfigurationChanged.connect - (mem_fun (*this, &IO::output_bundle_configuration_changed)); - output_bundle_connection_connection = c->PortsChanged.connect - (mem_fun (*this, &IO::output_bundle_connection_changed)); + boost::shared_ptr<UserBundle> ub = boost::dynamic_pointer_cast<UserBundle> (c); + if (ub) { + + /* See if we already know about this one */ + std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_outputs.begin(); + while (i != _bundles_connected_to_outputs.end() && i->bundle != ub) { + ++i; + } + + if (i == _bundles_connected_to_outputs.end()) { + /* We don't, so make a note */ + _bundles_connected_to_outputs.push_back (UserBundleInfo (this, ub)); + } + } } output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */ @@ -2159,27 +2085,31 @@ IO::reset_panners () } void -IO::input_bundle_connection_changed (int ignored) +IO::bundle_configuration_will_change () { - connect_input_ports_to_bundle (_input_bundle, this); + //XXX +// connect_input_ports_to_bundle (_input_bundle, this); } void -IO::input_bundle_configuration_changed () +IO::bundle_configuration_has_changed () { - connect_input_ports_to_bundle (_input_bundle, this); + //XXX +// connect_input_ports_to_bundle (_input_bundle, this); } void -IO::output_bundle_connection_changed (int ignored) +IO::bundle_ports_will_change (int ignored) { - connect_output_ports_to_bundle (_output_bundle, this); +//XXX +// connect_output_ports_to_bundle (_output_bundle, this); } void -IO::output_bundle_configuration_changed () +IO::bundle_ports_have_changed (int ignored) { - connect_output_ports_to_bundle (_output_bundle, this); + //XXX +// connect_output_ports_to_bundle (_output_bundle, this); } void @@ -2483,27 +2413,25 @@ IO::update_port_total_latencies () */ void -IO::setup_bundles () +IO::setup_bundles_for_inputs_and_outputs () { char buf[32]; snprintf(buf, sizeof (buf), _("%s in"), _name.c_str()); - _bundle_for_inputs->set_name (buf, 0); - int const ins = n_inputs().n_total(); - _bundle_for_inputs->set_nchannels (ins); - - for (int i = 0; i < ins; ++i) { - _bundle_for_inputs->add_port_to_channel (i, _inputs.port(i)->name ()); - } + _bundle_for_inputs->set_name (buf); + uint32_t const ni = inputs().num_ports(); + _bundle_for_inputs->set_channels (ni); + for (uint32_t i = 0; i < ni; ++i) { + _bundle_for_inputs->set_port (i, inputs().port(i)->name()); + } snprintf(buf, sizeof (buf), _("%s out"), _name.c_str()); - _bundle_for_outputs->set_name (buf, 0); - int const outs = n_outputs().n_total(); - _bundle_for_outputs->set_nchannels (outs); - - for (int i = 0; i < outs; ++i) { - _bundle_for_outputs->add_port_to_channel (i, _outputs.port(i)->name ()); - } + _bundle_for_outputs->set_name (buf); + uint32_t const no = outputs().num_ports(); + _bundle_for_outputs->set_channels (no); + for (uint32_t i = 0; i < no; ++i) { + _bundle_for_outputs->set_port (i, outputs().port(i)->name()); + } } @@ -2512,64 +2440,131 @@ IO::setup_bundles () */ void -IO::create_bundles () +IO::create_bundles_for_inputs_and_outputs () { - _bundle_for_inputs = boost::shared_ptr<Bundle> ( - new InputBundle ("", true) - ); - - _bundle_for_outputs = boost::shared_ptr<Bundle> ( - new OutputBundle ("", true) - ); - - setup_bundles (); + _bundle_for_inputs = boost::shared_ptr<AutoBundle> (new AutoBundle (true)); + _bundle_for_outputs = boost::shared_ptr<AutoBundle> (new AutoBundle (false)); + setup_bundles_for_inputs_and_outputs (); } -boost::shared_ptr<Bundle> -IO::input_bundle() +/** Add a bundle to a list if is connected to our inputs. + * @param b Bundle to check. + * @param bundles List to add to. + */ +void +IO::maybe_add_input_bundle_to_list (boost::shared_ptr<Bundle> b, std::vector<boost::shared_ptr<Bundle> >* bundles) { - if (_input_bundle) { - return _input_bundle; + boost::shared_ptr<AutoBundle> ab = boost::dynamic_pointer_cast<AutoBundle, Bundle> (b); + if (ab == 0 || ab->ports_are_outputs() == false) { + return; + } + + if (ab->nchannels () != n_inputs().n_total ()) { + return; } - /* XXX: will only report the first bundle found; should really return a list, I think */ - - /* check that _input_bundle is right wrt the connections that are currently made */ + for (uint32_t i = 0; i < n_inputs().n_total (); ++i) { - /* make a vector of the first output connected to each of our inputs */ - std::vector<std::string> connected; - for (uint32_t i = 0; i < _inputs.num_ports(); ++i) { - const char** c = _inputs.port(i)->get_connections (); - if (c) { - connected.push_back (c[0]); + PortList const & pl = b->channel_ports (i); + + if (pl.empty()) { + return; + } + + if (!input(i)->connected_to (pl[0])) { + return; } } - _input_bundle = _session.bundle_by_ports (connected); - return _input_bundle; + bundles->push_back (b); +} + +/** @return Bundles connected to our inputs */ +std::vector<boost::shared_ptr<Bundle> > +IO::bundles_connected_to_inputs () +{ + std::vector<boost::shared_ptr<Bundle> > bundles; + + /* User bundles */ + for (std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_inputs.begin(); i != _bundles_connected_to_inputs.end(); ++i) { + bundles.push_back (i->bundle); + } + + /* Auto bundles */ + _session.foreach_bundle ( + sigc::bind (sigc::mem_fun (*this, &IO::maybe_add_input_bundle_to_list), &bundles) + ); + + return bundles; } -boost::shared_ptr<Bundle> -IO::output_bundle() +/** Add a bundle to a list if is connected to our outputs. + * @param b Bundle to check. + * @param bundles List to add to. + */ +void +IO::maybe_add_output_bundle_to_list (boost::shared_ptr<Bundle> b, std::vector<boost::shared_ptr<Bundle> >* bundles) { - if (_output_bundle) { - return _output_bundle; + boost::shared_ptr<AutoBundle> ab = boost::dynamic_pointer_cast<AutoBundle, Bundle> (b); + if (ab == 0 || ab->ports_are_inputs() == false) { + return; + } + + if (ab->nchannels () != n_outputs().n_total ()) { + return; } - - /* XXX: will only report the first bundle found; should really return a list, I think */ - - /* check that _output_bundle is right wrt the connections that are currently made */ - /* make a vector of the first input connected to each of our outputs */ - std::vector<std::string> connected; - for (uint32_t i = 0; i < _outputs.num_ports(); ++i) { - const char** c = _outputs.port(i)->get_connections (); - if (c) { - connected.push_back (c[0]); + for (uint32_t i = 0; i < n_outputs().n_total (); ++i) { + + PortList const & pl = b->channel_ports (i); + + if (pl.empty()) { + return; + } + + if (!output(i)->connected_to (pl[0])) { + return; } } - _output_bundle = _session.bundle_by_ports (connected); - return _output_bundle; + bundles->push_back (b); +} + + +/* @return Bundles connected to our outputs */ +std::vector<boost::shared_ptr<Bundle> > +IO::bundles_connected_to_outputs () +{ + std::vector<boost::shared_ptr<Bundle> > bundles; + + /* User bundles */ + for (std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_outputs.begin(); i != _bundles_connected_to_outputs.end(); ++i) { + bundles.push_back (i->bundle); + } + + /* Auto bundles */ + _session.foreach_bundle ( + sigc::bind (sigc::mem_fun (*this, &IO::maybe_add_output_bundle_to_list), &bundles) + ); + + return bundles; +} + + +IO::UserBundleInfo::UserBundleInfo (IO* io, boost::shared_ptr<UserBundle> b) +{ + bundle = b; + configuration_will_change = b->ConfigurationWillChange.connect ( + sigc::mem_fun (*io, &IO::bundle_configuration_will_change) + ); + configuration_has_changed = b->ConfigurationHasChanged.connect ( + sigc::mem_fun (*io, &IO::bundle_configuration_has_changed) + ); + ports_will_change = b->PortsWillChange.connect ( + sigc::mem_fun (*io, &IO::bundle_ports_will_change) + ); + ports_have_changed = b->PortsHaveChanged.connect ( + sigc::mem_fun (*io, &IO::bundle_ports_have_changed) + ); } |