X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=inline;f=libs%2Fardour%2Froute.cc;h=290d9209d93c1bdda31e46f055396f69c9958c5d;hb=7b6b75f38ff6b34de3f70e36045498f227c1727d;hp=448e295c1a4558cd2a60dd55ca8c8a82a968db24;hpb=295eb9a395d2ad36654a1d71019a571400adaee8;p=ardour.git diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 448e295c1a..290d9209d9 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -58,6 +58,7 @@ #include "ardour/session.h" #include "ardour/timestamps.h" #include "ardour/utils.h" +#include "ardour/graph.h" #include "i18n.h" @@ -71,17 +72,60 @@ PBD::Signal0 Route::RemoteControlIDChange; Route::Route (Session& sess, string name, Flag flg, DataType default_type) : SessionObject (sess, name) - , AutomatableControls (sess) + , Automatable (sess) + , GraphNode( sess.route_graph ) + , _active (true) + , _initial_delay (0) + , _roll_delay (0) , _flags (flg) + , _pending_declick (true) + , _meter_point (MeterPostFader) + , _self_solo (false) + , _soloed_by_others_upstream (0) + , _soloed_by_others_downstream (0) + , _solo_isolated (0) + , _denormal_protection (false) + , _recordable (true) + , _silent (false) + , _declickable (false) , _solo_control (new SoloControllable (X_("solo"), *this)) , _mute_control (new MuteControllable (X_("mute"), *this)) , _mute_master (new MuteMaster (sess, name)) + , _have_internal_generator (false) + , _solo_safe (false) , _default_type (default_type) + , _remote_control_id (0) + , _in_configure_processors (false) +{ + processor_max_streams.reset(); + order_keys[N_("signal")] = order_key_cnt++; +} +int +Route::init () { - init (); + /* add standard controls */ + + _solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle)); + _mute_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle)); + + add_control (_solo_control); + add_control (_mute_control); + + /* input and output objects */ + + _input.reset (new IO (_session, _name, IO::Input, _default_type)); + _output.reset (new IO (_session, _name, IO::Output, _default_type)); + + _input->changed.connect_same_thread (*this, boost::bind (&Route::input_change_handler, this, _1, _2)); + _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2)); + + /* add amp processor */ + + _amp.reset (new Amp (_session)); + add_processor (_amp, PostFader); - /* add standard processors other than amp (added by ::init()) */ + /* add standard processors: meter, main outs, monitor out */ _meter.reset (new PeakMeter (_session)); _meter->set_display_to_user (false); @@ -89,10 +133,10 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) add_processor (_meter, PostFader); _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main)); - + add_processor (_main_outs, PostFader); - if (is_control()) { + if (is_monitor()) { /* where we listen to tracks */ _intreturn.reset (new InternalReturn (_session)); add_processor (_intreturn, PreFader); @@ -112,77 +156,21 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) */ _monitor_control.reset (new MonitorProcessor (_session)); add_processor (_monitor_control, i); - } + /* no panning on the monitor main outs */ + _main_outs->panner()->set_bypassed (true); + } - /* now that we have _meter, its safe to connect to this */ - - Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this))); -} - -Route::Route (Session& sess, const XMLNode& node, DataType default_type) - : SessionObject (sess, "toBeReset") - , AutomatableControls (sess) - , _solo_control (new SoloControllable (X_("solo"), *this)) - , _mute_control (new MuteControllable (X_("mute"), *this)) - , _mute_master (new MuteMaster (sess, "toBeReset")) - , _default_type (default_type) -{ - init (); - - _set_state (node, Stateful::loading_state_version, false); + if (is_master() || is_monitor() || is_hidden()) { + _mute_master->set_solo_ignore (true); + } /* now that we have _meter, its safe to connect to this */ Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this))); -} -void -Route::init () -{ - _self_solo = false; - _soloed_by_others = 0; - _solo_isolated = 0; - _solo_safe = false; - _active = true; - processor_max_streams.reset(); - _recordable = true; - order_keys[N_("signal")] = order_key_cnt++; - _silent = false; - _meter_point = MeterPostFader; - _initial_delay = 0; - _roll_delay = 0; - _have_internal_generator = false; - _declickable = false; - _pending_declick = true; - _remote_control_id = 0; - _in_configure_processors = false; - _mute_points = MuteMaster::AllPoints; - - _phase_invert = 0; - _denormal_protection = false; - - /* add standard controls */ - - _solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle)); - _mute_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle)); - - add_control (_solo_control); - add_control (_mute_control); - - /* input and output objects */ - - _input.reset (new IO (_session, _name, IO::Input, _default_type)); - _output.reset (new IO (_session, _name, IO::Output, _default_type)); - - _input->changed.connect_same_thread (*this, boost::bind (&Route::input_change_handler, this, _1, _2)); - _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2)); - - /* add amp processor */ - - _amp.reset (new Amp (_session, _mute_master)); - add_processor (_amp, PostFader); + return 0; } Route::~Route () @@ -224,7 +212,7 @@ Route::remote_control_id() const return _remote_control_id; } -long +int32_t Route::order_key (std::string const & name) const { OrderKeys::const_iterator i = order_keys.find (name); @@ -236,17 +224,34 @@ Route::order_key (std::string const & name) const } void -Route::set_order_key (std::string const & name, long n) +Route::set_order_key (std::string const & name, int32_t n) { - order_keys[name] = n; + bool changed = false; + + /* This method looks more complicated than it should, but + it's important that we don't emit order_key_changed unless + it actually has, as expensive things happen on receipt of that + signal. + */ + + if (order_keys.find(name) == order_keys.end() || order_keys[name] != n) { + order_keys[name] = n; + changed = true; + } if (Config->get_sync_all_route_ordering()) { for (OrderKeys::iterator x = order_keys.begin(); x != order_keys.end(); ++x) { - x->second = n; + if (x->second != n) { + x->second = n; + changed = true; + } } } - _session.set_dirty (); + if (changed) { + order_key_changed (); /* EMIT SIGNAL */ + _session.set_dirty (); + } } /** Set all order keys to be the same as that for `base', if such a key @@ -261,7 +266,7 @@ Route::sync_order_keys (std::string const & base) } OrderKeys::iterator i; - uint32_t key; + int32_t key; if ((i = order_keys.find (base)) == order_keys.end()) { /* key doesn't exist, use the first existing key (during session initialization) */ @@ -274,8 +279,17 @@ Route::sync_order_keys (std::string const & base) i = order_keys.begin(); } + bool changed = false; + for (; i != order_keys.end(); ++i) { - i->second = key; + if (i->second != key) { + i->second = key; + changed = true; + } + } + + if (changed) { + order_key_changed (); /* EMIT SIGNAL */ } } @@ -284,8 +298,8 @@ Route::ensure_track_or_route_name(string name, Session &session) { string newname = name; - while (session.route_by_name (newname) != NULL) { - newname = bump_name_once (newname); + while (!session.io_name_is_legal (newname)) { + newname = bump_name_once (newname, '.'); } return newname; @@ -398,9 +412,9 @@ Route::process_output_buffers (BufferSet& bufs, ----------------------------------------------------------------------------------------- */ if (declick > 0) { - Amp::apply_gain (bufs, nframes, 0.0, 1.0); + Amp::declick (bufs, nframes, 1); } else if (declick < 0) { - Amp::apply_gain (bufs, nframes, 1.0, 0.0); + Amp::declick (bufs, nframes, -1); } _pending_declick = 0; @@ -409,7 +423,7 @@ Route::process_output_buffers (BufferSet& bufs, DENORMAL CONTROL/PHASE INVERT ----------------------------------------------------------------------------------------- */ - if (_phase_invert) { + if (_phase_invert.any ()) { int chn = 0; @@ -418,7 +432,7 @@ Route::process_output_buffers (BufferSet& bufs, for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) { Sample* const sp = i->data(); - if (_phase_invert & chn) { + if (_phase_invert[chn]) { for (nframes_t nx = 0; nx < nframes; ++nx) { sp[nx] = -sp[nx]; sp[nx] += 1.0e-27f; @@ -435,7 +449,7 @@ Route::process_output_buffers (BufferSet& bufs, for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) { Sample* const sp = i->data(); - if (_phase_invert & chn) { + if (_phase_invert[chn]) { for (nframes_t nx = 0; nx < nframes; ++nx) { sp[nx] = -sp[nx]; } @@ -461,21 +475,17 @@ Route::process_output_buffers (BufferSet& bufs, and go .... ----------------------------------------------------------------------------------------- */ - Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK); - - if (rm.locked()) { - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - - if (bufs.count() != (*i)->input_streams()) { - cerr << _name << " bufs = " << bufs.count() - << " input for " << (*i)->name() << " = " << (*i)->input_streams() - << endl; - } - assert (bufs.count() == (*i)->input_streams()); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back()); - bufs.set_count ((*i)->output_streams()); + if (bufs.count() != (*i)->input_streams()) { + cerr << _name << " bufs = " << bufs.count() + << " input for " << (*i)->name() << " = " << (*i)->input_streams() + << endl; } + assert (bufs.count() == (*i)->input_streams()); + + (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back()); + bufs.set_count ((*i)->output_streams()); } } @@ -492,15 +502,15 @@ Route::passthru (sframes_t start_frame, sframes_t end_frame, nframes_t nframes, _silent = false; - assert (bufs.available() >= _input->n_ports()); + assert (bufs.available() >= input_streams()); if (_input->n_ports() == ChanCount::ZERO) { - silence (nframes); + silence_unlocked (nframes); } - bufs.set_count (_input->n_ports()); + bufs.set_count (input_streams()); - if (is_control() && _session.listening()) { + if (is_monitor() && _session.listening() && !_session.is_auditioning()) { /* control/monitor bus ignores input ports when something is feeding the listen "stream". data will "arrive" into the @@ -537,14 +547,18 @@ Route::passthru_silence (sframes_t start_frame, sframes_t end_frame, nframes_t n void Route::set_listen (bool yn, void* src) { - if (_control_outs) { - if (yn != _control_outs->active()) { + if (_solo_safe) { + return; + } + + if (_monitor_send) { + if (yn != _monitor_send->active()) { if (yn) { - _control_outs->set_solo_level (1); - _control_outs->activate (); - } else { - _control_outs->set_solo_level (0); - _control_outs->deactivate (); + _monitor_send->activate (); + _mute_master->set_soloed (true); + } else { + _monitor_send->deactivate (); + _mute_master->set_soloed (false); } listen_changed (src); /* EMIT SIGNAL */ @@ -555,8 +569,8 @@ Route::set_listen (bool yn, void* src) bool Route::listening () const { - if (_control_outs) { - return _control_outs->active (); + if (_monitor_send) { + return _monitor_send->active (); } else { return false; } @@ -591,8 +605,8 @@ Route::set_solo (bool yn, void *src) if (self_soloed() != yn) { set_self_solo (yn); - set_delivery_solo (); - solo_changed (src); /* EMIT SIGNAL */ + set_mute_master_solo (); + solo_changed (true, src); /* EMIT SIGNAL */ _solo_control->Changed (); /* EMIT SIGNAL */ } } @@ -600,48 +614,97 @@ Route::set_solo (bool yn, void *src) void Route::set_self_solo (bool yn) { - _self_solo = yn; + _self_solo = yn; } void -Route::mod_solo_by_others (int32_t delta) +Route::mod_solo_by_others_upstream (int32_t delta) { + if (_solo_safe) { + return; + } + + uint32_t old_sbu = _soloed_by_others_upstream; + if (delta < 0) { - if (_soloed_by_others >= (uint32_t) delta) { - _soloed_by_others += delta; + if (_soloed_by_others_upstream >= (uint32_t) abs (delta)) { + _soloed_by_others_upstream += delta; } else { - _soloed_by_others = 0; + _soloed_by_others_upstream = 0; } } else { - _soloed_by_others += delta; - } + _soloed_by_others_upstream += delta; + } + + DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbU delta %2 = %3 old = %4 sbd %5 ss %6 exclusive %7\n", + name(), delta, _soloed_by_others_upstream, old_sbu, + _soloed_by_others_downstream, _self_solo, Config->get_exclusive_solo())); + + /* push the inverse solo change to everything that feeds us. + + This is important for solo-within-group. When we solo 1 track out of N that + feed a bus, that track will cause mod_solo_by_upstream (+1) to be called + on the bus. The bus then needs to call mod_solo_by_downstream (-1) on all + tracks that feed it. This will silence them if they were audible because + of a bus solo, but the newly soloed track will still be audible (because + it is self-soloed). + + but .. do this only when we are being told to solo-by-upstream (i.e delta = +1), + not in reverse. + */ + + if ((_self_solo || _soloed_by_others_downstream) && + ((old_sbu == 0 && _soloed_by_others_upstream > 0) || + (old_sbu > 0 && _soloed_by_others_upstream == 0))) { + + if (delta > 0 || !Config->get_exclusive_solo()) { + DEBUG_TRACE (DEBUG::Solo, "\t ... INVERT push\n"); + for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) { + boost::shared_ptr sr = i->r.lock(); + if (sr) { + sr->mod_solo_by_others_downstream (-delta); + } + } + } + } - set_delivery_solo (); + set_mute_master_solo (); + solo_changed (false, this); } void -Route::set_delivery_solo () +Route::mod_solo_by_others_downstream (int32_t delta) { - /* tell all delivery processors what the solo situation is, so that they keep - delivering even though Session::soloing() is true and they were not - explicitly soloed. - */ + if (_solo_safe) { + return; + } - Glib::RWLock::ReaderLock rm (_processor_lock); - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - boost::shared_ptr d; - - if ((d = boost::dynamic_pointer_cast (*i)) != 0) { - d->set_solo_level (soloed ()); - d->set_solo_isolated (solo_isolated()); + if (delta < 0) { + if (_soloed_by_others_downstream >= (uint32_t) abs (delta)) { + _soloed_by_others_downstream += delta; + } else { + _soloed_by_others_downstream = 0; } + } else { + _soloed_by_others_downstream += delta; } + + DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbD delta %2 = %3\n", name(), delta, _soloed_by_others_downstream)); + + set_mute_master_solo (); + solo_changed (false, this); +} + +void +Route::set_mute_master_solo () +{ + _mute_master->set_soloed (self_soloed() || soloed_by_others_downstream() || soloed_by_others_upstream()); } void Route::set_solo_isolated (bool yn, void *src) { - if (is_master() || is_control() || is_hidden()) { + if (is_master() || is_monitor() || is_hidden()) { return; } @@ -654,32 +717,42 @@ Route::set_solo_isolated (bool yn, void *src) boost::shared_ptr routes = _session.get_routes (); for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { + + if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_hidden()) { + continue; + } + bool sends_only; - bool does_feed = feeds (*i, &sends_only); + bool does_feed = direct_feeds (*i, &sends_only); // we will recurse anyway, so don't use ::feeds() if (does_feed && !sends_only) { (*i)->set_solo_isolated (yn, (*i)->route_group()); } } - bool changed = false; + /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */ + + bool changed = false; if (yn) { - if (_solo_isolated == 0) { - changed = true; - } + if (_solo_isolated == 0) { + _mute_master->set_solo_ignore (true); + changed = true; + } _solo_isolated++; } else { - changed = (_solo_isolated == 1); if (_solo_isolated > 0) { _solo_isolated--; + if (_solo_isolated == 0) { + _mute_master->set_solo_ignore (false); + changed = true; + } } } - if (changed) { - set_delivery_solo (); - solo_isolated_changed (src); - } + if (changed) { + solo_isolated_changed (src); + } } bool @@ -691,13 +764,12 @@ Route::solo_isolated () const void Route::set_mute_points (MuteMaster::MutePoint mp) { - _mute_points = mp; - mute_points_changed (); /* EMIT SIGNAL */ - - if (_mute_master->muted()) { - _mute_master->mute_at (_mute_points); - mute_changed (this); /* EMIT SIGNAL */ - } + _mute_master->set_mute_points (mp); + mute_points_changed (); /* EMIT SIGNAL */ + + if (_mute_master->muted_by_self()) { + mute_changed (this); /* EMIT SIGNAL */ + } } void @@ -709,20 +781,15 @@ Route::set_mute (bool yn, void *src) } if (muted() != yn) { - if (yn) { - _mute_master->mute_at (_mute_points); - } else { - _mute_master->clear_mute (); - } - + _mute_master->set_muted_by_self (yn); mute_changed (src); /* EMIT SIGNAL */ } } bool -Route::muted() const +Route::muted () const { - return _mute_master->muted (); + return _mute_master->muted_by_self(); } #if 0 @@ -823,7 +890,15 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite } - if (activation_allowed && (processor != _control_outs)) { + /* is this the monitor send ? if so, make sure we keep track of it */ + + boost::shared_ptr isend = boost::dynamic_pointer_cast (processor); + + if (isend && _session.monitor_out() && (isend->target_id() == _session.monitor_out()->id())) { + _monitor_send = isend; + } + + if (activation_allowed && (processor != _monitor_send)) { processor->activate (); } @@ -833,155 +908,11 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite } processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } -bool -Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter) -{ - const XMLProperty *prop; - - if (node.name() != "Processor") { - return false; - } - - try { - if ((prop = node.property ("type")) != 0) { - - boost::shared_ptr processor; - - if (prop->value() == "ladspa" || prop->value() == "Ladspa" || - prop->value() == "lv2" || - prop->value() == "vst" || - prop->value() == "audiounit") { - - processor.reset (new PluginInsert(_session, node)); - - } else if (prop->value() == "port") { - - processor.reset (new PortInsert (_session, _mute_master, node)); - - } else if (prop->value() == "send") { - - processor.reset (new Send (_session, _mute_master, node)); - - } else if (prop->value() == "meter") { - - if (_meter) { - if (_meter->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - return true; - } - } - - _meter.reset (new PeakMeter (_session, node)); - _meter->set_display_to_user (_meter_point == MeterCustom); - processor = _meter; - - } else if (prop->value() == "monitor") { - - if (_monitor_control) { - if (_monitor_control->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - return true; - } - } - - _monitor_control.reset (new MonitorProcessor (_session)); - _monitor_control->set_state (node, Stateful::loading_state_version); - processor = _monitor_control; - - } else if (prop->value() == "amp") { - - /* amp always exists */ - - processor = _amp; - if (processor->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - /* never any reason to add it */ - return true; - } - - } else if (prop->value() == "intsend") { - - InternalSend* isend = new InternalSend (_session, _mute_master, node); - - if (_session.control_out() && (isend->target_id() == _session.control_out()->id())) { - _control_outs.reset (isend); - if (_control_outs->active()) { - _control_outs->set_solo_level (1); - } else { - _control_outs->set_solo_level (0); - } - } - - processor.reset (isend); - - } else if (prop->value() == "intreturn") { - - /* a route only has one internal return. If it exists already - just set its state, and return - */ - - if (_intreturn) { - if (_intreturn->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - return true; - } - } - _intreturn.reset (new InternalReturn (_session, node)); - processor = _intreturn; - - } else if (prop->value() == "main-outs") { - - if (_main_outs) { - if (_main_outs->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - return true; - } - } - - _main_outs.reset (new Delivery (_session, _output, _mute_master, node)); - processor = _main_outs; - - } else { - error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; - return false; - } - - if (iter == _processors.end() && processor->display_to_user() && !_processors.empty()) { - /* check for invisible processors stacked at the end and leave them there */ - ProcessorList::iterator p; - p = _processors.end(); - --p; - while (!(*p)->display_to_user() && p != _processors.begin()) { - --p; - } - ++p; - iter = p; - } - - return (add_processor (processor, iter, 0, false) == 0); - - } else { - error << _("Processor XML node has no type property") << endmsg; - return false; - } - } - - catch (failed_constructor &err) { - warning << _("processor could not be created. Ignored.") << endmsg; - return false; - } -} - - bool Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorList::iterator iter) { @@ -999,18 +930,18 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorLis prop->value() == "vst" || prop->value() == "audiounit") { - processor.reset (new PluginInsert (_session, node)); + processor.reset (new PluginInsert (_session)); } else { - processor.reset (new PortInsert (_session, _mute_master, node)); + processor.reset (new PortInsert (_session, _mute_master)); } } } else if (node.name() == "Send") { - processor.reset (new Send (_session, _mute_master, node, version)); + processor.reset (new Send (_session, _mute_master)); } else { @@ -1018,6 +949,10 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorLis return false; } + if (processor->set_state (node, version)) { + return false; + } + if (iter == _processors.end() && processor->display_to_user() && !_processors.empty()) { /* check for invisible processors stacked at the end and leave them there */ ProcessorList::iterator p; @@ -1118,6 +1053,7 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter } processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } @@ -1318,6 +1254,7 @@ Route::clear_processors (Placement p) processor_max_streams.reset(); _have_internal_generator = false; processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); if (!already_deleting) { _session.clear_deletion_in_progress(); @@ -1409,6 +1346,7 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream processor->drop_references (); processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } @@ -1500,6 +1438,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* } processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } @@ -1515,6 +1454,12 @@ Route::configure_processors (ProcessorStreams* err) return 0; } +ChanCount +Route::input_streams () const +{ + return _input->n_ports (); +} + /** Configure the input/output configuration of each processor in the processors list. * Return 0 on success, otherwise configuration is impossible. */ @@ -1528,24 +1473,22 @@ Route::configure_processors_unlocked (ProcessorStreams* err) _in_configure_processors = true; // Check each processor in order to see if we can configure as requested - ChanCount in = _input->n_ports (); + ChanCount in = input_streams (); ChanCount out; list< pair > configuration; uint32_t index = 0; DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configure processors\n", _name)); -#ifndef NDEBUG DEBUG_TRACE (DEBUG::Processors, "{\n"); for (list >::const_iterator p = _processors.begin(); p != _processors.end(); ++p) { DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1 ID = %2\n", (*p)->name(), (*p)->id())); } DEBUG_TRACE (DEBUG::Processors, "}\n"); -#endif for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++index) { if ((*p)->can_support_io_configuration(in, out)) { - DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1in = %2 out = %3\n",(*p)->name(), in, out)); + DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1 in = %2 out = %3\n",(*p)->name(), in, out)); configuration.push_back(make_pair(in, out)); in = out; } else { @@ -1573,7 +1516,12 @@ Route::configure_processors_unlocked (ProcessorStreams* err) /* make sure we have sufficient scratch buffers to cope with the new processor configuration */ - _session.ensure_buffers (n_process_buffers ()); + { + Glib::Mutex::Lock em (_session.engine().process_lock ()); + _session.ensure_buffers (n_process_buffers ()); + } + + DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configuration complete\n", _name)); _in_configure_processors = false; return 0; @@ -1734,7 +1682,10 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err } } - processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + if (true) { + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); + } return 0; } @@ -1768,7 +1719,9 @@ Route::state(bool full_state) } node->add_property("active", _active?"yes":"no"); - node->add_property("phase-invert", _phase_invert?"yes":"no"); + string p; + boost::to_string (_phase_invert, p); + node->add_property("phase-invert", p); node->add_property("denormal-protection", _denormal_protection?"yes":"no"); node->add_property("meter-point", enum_2_string (_meter_point)); @@ -1795,8 +1748,10 @@ Route::state(bool full_state) } node->add_property ("order-keys", order_string); node->add_property ("self-solo", (_self_solo ? "yes" : "no")); - snprintf (buf, sizeof (buf), "%d", _soloed_by_others); - node->add_property ("soloed-by-others", buf); + snprintf (buf, sizeof (buf), "%d", _soloed_by_others_upstream); + node->add_property ("soloed-by-upstream", buf); + snprintf (buf, sizeof (buf), "%d", _soloed_by_others_downstream); + node->add_property ("soloed-by-downstream", buf); node->add_child_nocopy (_input->state (full_state)); node->add_child_nocopy (_output->state (full_state)); @@ -1862,6 +1817,10 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) _flags = Flag (0); } + if (is_master() || is_monitor() || is_hidden()) { + _mute_master->set_solo_ignore (true); + } + /* add all processors (except amp, which is always present) */ nlist = node.children(); @@ -1894,9 +1853,14 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) set_self_solo (string_is_affirmative (prop->value())); } - if ((prop = node.property ("soloed-by-others")) != 0) { - _soloed_by_others = 0; // needed for mod_solo_by_others () to work - mod_solo_by_others (atoi (prop->value())); + if ((prop = node.property ("soloed-by-upstream")) != 0) { + _soloed_by_others_upstream = 0; // needed for mod_.... () to work + mod_solo_by_others_upstream (atoi (prop->value())); + } + + if ((prop = node.property ("soloed-by-downstream")) != 0) { + _soloed_by_others_downstream = 0; // needed for mod_.... () to work + mod_solo_by_others_downstream (atoi (prop->value())); } if ((prop = node.property ("solo-isolated")) != 0) { @@ -1904,7 +1868,7 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) } if ((prop = node.property (X_("phase-invert"))) != 0) { - set_phase_invert (string_is_affirmative (prop->value())); + set_phase_invert (boost::dynamic_bitset<> (prop->value ())); } if ((prop = node.property (X_("denormal-protection"))) != 0) { @@ -1918,7 +1882,8 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) } if ((prop = node.property (X_("meter-point"))) != 0) { - _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point)); + MeterPoint mp = MeterPoint (string_2_enum (prop->value (), _meter_point)); + set_meter_point (mp); if (_meter) { _meter->set_display_to_user (_meter_point == MeterCustom); } @@ -1926,7 +1891,7 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) if ((prop = node.property (X_("order-keys"))) != 0) { - long n; + int32_t n; string::size_type colon, equal; string remaining = prop->value(); @@ -1937,7 +1902,7 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining) << endmsg; } else { - if (sscanf (remaining.substr (equal+1).c_str(), "%ld", &n) != 1) { + if (sscanf (remaining.substr (equal+1).c_str(), "%d", &n) != 1) { error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining) << endmsg; } else { @@ -2002,11 +1967,6 @@ Route::_set_state_2X (const XMLNode& node, int version) /* 2X things which still remain to be handled: * default-type - * muted - * mute-affects-pre-fader - * mute-affects-post-fader - * mute-affects-control-outs - * mute-affects-main-outs * automation * controlouts */ @@ -2021,60 +1981,13 @@ Route::_set_state_2X (const XMLNode& node, int version) } else { _flags = Flag (0); } - - /* add standard processors */ - - _meter.reset (new PeakMeter (_session)); - add_processor (_meter, PreFader); - - if (is_control()) { - /* where we listen to tracks */ - _intreturn.reset (new InternalReturn (_session)); - add_processor (_intreturn, PreFader); - - _monitor_control.reset (new MonitorProcessor (_session)); - add_processor (_monitor_control, PostFader); - } - - _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main)); - add_processor (_main_outs, PostFader); - - /* IOs */ - - nlist = node.children (); - for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - - child = *niter; - - if (child->name() == IO::state_node_name) { - - /* there is a note in IO::set_state_2X() about why we have to call - this directly. - */ - - _input->set_state_2X (*child, version, true); - _output->set_state_2X (*child, version, false); - - if ((prop = child->property (X_("name"))) != 0) { - set_name (prop->value ()); - } - - if ((prop = child->property (X_("id"))) != 0) { - _id = prop->value (); - } - - if ((prop = child->property (X_("active"))) != 0) { - bool yn = string_is_affirmative (prop->value()); - _active = !yn; // force switch - set_active (yn); - } - } - - /* XXX: panners? */ - } - + if ((prop = node.property (X_("phase-invert"))) != 0) { - set_phase_invert (string_is_affirmative (prop->value())); + boost::dynamic_bitset<> p (_input->n_ports().n_audio ()); + if (string_is_affirmative (prop->value ())) { + p.set (); + } + set_phase_invert (p); } if ((prop = node.property (X_("denormal-protection"))) != 0) { @@ -2089,6 +2002,65 @@ Route::_set_state_2X (const XMLNode& node, int version) set_solo (yn, this); } + if ((prop = node.property (X_("muted"))) != 0) { + + bool first = true; + bool muted = string_is_affirmative (prop->value()); + + if (muted){ + + string mute_point; + + if ((prop = node.property (X_("mute-affects-pre-fader"))) != 0) { + + if (string_is_affirmative (prop->value())){ + mute_point = mute_point + "PreFader"; + first = false; + } + } + + if ((prop = node.property (X_("mute-affects-post-fader"))) != 0) { + + if (string_is_affirmative (prop->value())){ + + if (!first) { + mute_point = mute_point + ","; + } + + mute_point = mute_point + "PostFader"; + first = false; + } + } + + if ((prop = node.property (X_("mute-affects-control-outs"))) != 0) { + + if (string_is_affirmative (prop->value())){ + + if (!first) { + mute_point = mute_point + ","; + } + + mute_point = mute_point + "Listen"; + first = false; + } + } + + if ((prop = node.property (X_("mute-affects-main-outs"))) != 0) { + + if (string_is_affirmative (prop->value())){ + + if (!first) { + mute_point = mute_point + ","; + } + + mute_point = mute_point + "Main"; + } + } + + _mute_master->set_mute_points (mute_point); + } + } + if ((prop = node.property (X_("meter-point"))) != 0) { _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point)); } @@ -2099,7 +2071,7 @@ Route::_set_state_2X (const XMLNode& node, int version) if ((prop = node.property (X_("order-keys"))) != 0) { - long n; + int32_t n; string::size_type colon, equal; string remaining = prop->value(); @@ -2110,7 +2082,7 @@ Route::_set_state_2X (const XMLNode& node, int version) error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining) << endmsg; } else { - if (sscanf (remaining.substr (equal+1).c_str(), "%ld", &n) != 1) { + if (sscanf (remaining.substr (equal+1).c_str(), "%d", &n) != 1) { error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining) << endmsg; } else { @@ -2128,6 +2100,78 @@ Route::_set_state_2X (const XMLNode& node, int version) } } + /* add standard processors */ + + //_meter.reset (new PeakMeter (_session)); + //add_processor (_meter, PreFader); + + if (is_monitor()) { + /* where we listen to tracks */ + _intreturn.reset (new InternalReturn (_session)); + add_processor (_intreturn, PreFader); + + _monitor_control.reset (new MonitorProcessor (_session)); + add_processor (_monitor_control, PostFader); + } + + _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main)); + add_processor (_main_outs, PostFader); + + /* IOs */ + + nlist = node.children (); + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { + + child = *niter; + + if (child->name() == IO::state_node_name) { + + /* there is a note in IO::set_state_2X() about why we have to call + this directly. + */ + + _input->set_state_2X (*child, version, true); + _output->set_state_2X (*child, version, false); + + if ((prop = child->property (X_("name"))) != 0) { + Route::set_name (prop->value ()); + } + + if ((prop = child->property (X_("id"))) != 0) { + _id = prop->value (); + } + + if ((prop = child->property (X_("active"))) != 0) { + bool yn = string_is_affirmative (prop->value()); + _active = !yn; // force switch + set_active (yn); + } + + if ((prop = child->property (X_("gain"))) != 0) { + gain_t val; + + if (sscanf (prop->value().c_str(), "%f", &val) == 1) { + _amp->gain_control()->set_value (val); + } + } + + /* Set up Panners in the IO */ + XMLNodeList io_nlist = child->children (); + + XMLNodeConstIterator io_niter; + XMLNode *io_child; + + for (io_niter = io_nlist.begin(); io_niter != io_nlist.end(); ++io_niter) { + + io_child = *io_niter; + + if (io_child->name() == X_("Panner")) { + _main_outs->panner()->set_state(*io_child, version); + } + } + } + } + XMLNodeList redirect_nodes; for (niter = nlist.begin(); niter != nlist.end(); ++niter){ @@ -2206,101 +2250,95 @@ Route::set_processor_state (const XMLNode& node) { const XMLNodeList &nlist = node.children(); XMLNodeConstIterator niter; - ProcessorList::iterator i, o; - - // Iterate through existing processors, remove those which are not in the state list - - for (i = _processors.begin(); i != _processors.end(); ) { - - /* leave amp alone, always */ - - if ((*i) == _amp) { - ++i; - continue; - } - - ProcessorList::iterator tmp = i; - ++tmp; - - bool processorInStateList = false; - - for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - - XMLProperty* id_prop = (*niter)->property(X_("id")); - - if (id_prop && (*i)->id() == id_prop->value()) { - processorInStateList = true; - break; - } - } - - if (!processorInStateList) { - remove_processor (*i); - } - - i = tmp; - } - - // Iterate through state list and make sure all processors are on the track and in the correct order, - // set the state of existing processors according to the new state on the same go - - i = _processors.begin(); + ProcessorList new_order; + bool must_configure = false; - for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) { + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { XMLProperty* prop = (*niter)->property ("type"); - o = i; - - // Check whether the next processor in the list is the right one, - // except for "amp" which is always there and may not have the - // old ID since it is always created anew in every Route + if (prop->value() == "amp") { + _amp->set_state (**niter, Stateful::current_state_version); + new_order.push_back (_amp); + } else if (prop->value() == "meter") { + _meter->set_state (**niter, Stateful::current_state_version); + new_order.push_back (_meter); + } else if (prop->value() == "main-outs") { + _main_outs->set_state (**niter, Stateful::current_state_version); + new_order.push_back (_main_outs); + } else if (prop->value() == "intreturn") { + if (!_intreturn) { + _intreturn.reset (new InternalReturn (_session)); + must_configure = true; + } + _intreturn->set_state (**niter, Stateful::current_state_version); + new_order.push_back (_intreturn); + } else if (is_monitor() && prop->value() == "monitor") { + if (!_monitor_control) { + _monitor_control.reset (new MonitorProcessor (_session)); + must_configure = true; + } + _monitor_control->set_state (**niter, Stateful::current_state_version); + new_order.push_back (_monitor_control); + } else { + ProcessorList::iterator o; - if (prop->value() != "amp") { - while (o != _processors.end()) { + for (o = _processors.begin(); o != _processors.end(); ++o) { XMLProperty* id_prop = (*niter)->property(X_("id")); if (id_prop && (*o)->id() == id_prop->value()) { + (*o)->set_state (**niter, Stateful::current_state_version); + new_order.push_back (*o); break; } - - ++o; - } - } - - // If the processor (*niter) is not on the route, - // create it and move it to the correct location - - if (o == _processors.end()) { - - if (add_processor_from_xml (**niter, i)) { - --i; // move iterator to the newly inserted processor - } else { - cerr << "Error restoring route: unable to restore processor" << endl; - } - - } else { - - // Otherwise, the processor already exists; just - // ensure it is at the location provided in the XML state - - if (i != o) { - boost::shared_ptr tmp = (*o); - _processors.erase (o); // remove the old copy - _processors.insert (i, tmp); // insert the processor at the correct location - --i; // move iterator to the correct processor } - // and make it (just) so + // If the processor (*niter) is not on the route then create it + + if (o == _processors.end()) { + + boost::shared_ptr processor; + + if (prop->value() == "intsend") { + + processor.reset (new InternalSend (_session, _mute_master, boost::shared_ptr(), Delivery::Role (0))); + + } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" || + prop->value() == "lv2" || + prop->value() == "vst" || + prop->value() == "audiounit") { + + processor.reset (new PluginInsert(_session)); + + } else if (prop->value() == "port") { + + processor.reset (new PortInsert (_session, _mute_master)); + + } else if (prop->value() == "send") { + + processor.reset (new Send (_session, _mute_master)); + + } else { + error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; + continue; + } - (*i)->set_state (**niter, Stateful::current_state_version); - } - } + processor->set_state (**niter, Stateful::current_state_version); + new_order.push_back (processor); + must_configure = true; + } + } + } - /* note: there is no configure_processors() call because we figure that - the XML state represents a working signal route. - */ + { + Glib::RWLock::WriterLock lm (_processor_lock); + _processors = new_order; + if (must_configure) { + configure_processors_unlocked (0); + } + } - processors_changed (RouteProcessorChange ()); + processors_changed (RouteProcessorChange ()); + set_processor_positions (); } void @@ -2313,31 +2351,37 @@ Route::curve_reallocate () void Route::silence (nframes_t nframes) { - if (!_silent) { - - _output->silence (nframes); - - { - Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + if (!lm.locked()) { + return; + } - if (lm.locked()) { - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - boost::shared_ptr pi; + silence_unlocked (nframes); +} - if (!_active && (pi = boost::dynamic_pointer_cast (*i)) != 0) { - // skip plugins, they don't need anything when we're not active - continue; - } +void +Route::silence_unlocked (nframes_t nframes) +{ + /* Must be called with the processor lock held */ + + if (!_silent) { - (*i)->silence (nframes); - } + _output->silence (nframes); - if (nframes == _session.get_block_size()) { - // _silent = true; - } + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + boost::shared_ptr pi; + + if (!_active && (pi = boost::dynamic_pointer_cast (*i)) != 0) { + // skip plugins, they don't need anything when we're not active + continue; } + + (*i)->silence (nframes); + } + + if (nframes == _session.get_block_size()) { + // _silent = true; } - } } @@ -2400,13 +2444,8 @@ Route::listen_via (boost::shared_ptr route, Placement placement, bool /*a we take note of which i-send is doing that. */ - if (route == _session.control_out()) { - _control_outs = boost::dynamic_pointer_cast(d); - if (_control_outs->active()) { - _control_outs->set_solo_level (1); - } else { - _control_outs->set_solo_level (0); - } + if (route == _session.monitor_out()) { + _monitor_send = boost::dynamic_pointer_cast(d); } /* already listening via the specified IO: do nothing */ @@ -2422,7 +2461,7 @@ Route::listen_via (boost::shared_ptr route, Placement placement, bool /*a if (is_master()) { - if (route == _session.control_out()) { + if (route == _session.monitor_out()) { /* master never sends to control outs */ return 0; } else { @@ -2431,16 +2470,14 @@ Route::listen_via (boost::shared_ptr route, Placement placement, bool /*a } else { listener.reset (new InternalSend (_session, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen))); - if (route == _session.control_out()) { - } } } catch (failed_constructor& err) { return -1; } - if (route == _session.control_out()) { - _control_outs = listener; + if (route == _session.monitor_out()) { + _monitor_send = listener; } if (placement == PostFader) { @@ -2483,8 +2520,8 @@ Route::drop_listen (boost::shared_ptr route) rl.release (); - if (route == _session.control_out()) { - _control_outs.reset (); + if (route == _session.monitor_out()) { + _monitor_send.reset (); } } @@ -2497,7 +2534,53 @@ Route::set_comment (string cmt, void *src) } bool -Route::feeds (boost::shared_ptr other, bool* only_send) +Route::add_fed_by (boost::shared_ptr other, bool via_sends_only) +{ + FeedRecord fr (other, via_sends_only); + + pair result = _fed_by.insert (fr); + + if (!result.second) { + + /* already a record for "other" - make sure sends-only information is correct */ + if (!via_sends_only && result.first->sends_only) { + FeedRecord* frp = const_cast(&(*result.first)); + frp->sends_only = false; + } + } + + return result.second; +} + +void +Route::clear_fed_by () +{ + _fed_by.clear (); +} + +bool +Route::feeds (boost::shared_ptr other, bool* via_sends_only) +{ + const FedBy& fed_by (other->fed_by()); + + for (FedBy::iterator f = fed_by.begin(); f != fed_by.end(); ++f) { + boost::shared_ptr sr = f->r.lock(); + + if (sr && (sr.get() == this)) { + + if (via_sends_only) { + *via_sends_only = f->sends_only; + } + + return true; + } + } + + return false; +} + +bool +Route::direct_feeds (boost::shared_ptr other, bool* only_send) { DEBUG_TRACE (DEBUG::Graph, string_compose ("Feeds? %1\n", _name)); @@ -2538,7 +2621,7 @@ Route::feeds (boost::shared_ptr other, bool* only_send) void Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors) { - nframes_t now = _session.transport_frame(); + framepos_t now = _session.transport_frame(); { Glib::RWLock::ReaderLock lm (_processor_lock); @@ -2547,11 +2630,14 @@ Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool c automation_snapshot (now, true); } + Automatable::transport_stopped (now); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if (Config->get_plugins_stop_with_transport() && can_flush_processors) { (*i)->deactivate (); (*i)->activate (); + (*i)->flush (); } (*i)->transport_stopped (now); @@ -2566,6 +2652,8 @@ Route::input_change_handler (IOChange change, void * /*src*/) { if ((change & ConfigurationChanged)) { configure_processors (0); + _phase_invert.resize (_input->n_ports().n_audio ()); + io_changed (); /* EMIT SIGNAL */ } } @@ -2594,12 +2682,17 @@ int Route::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, bool session_state_changing, bool /*can_record*/, bool /*rec_monitors_input*/) { + Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + if (!lm.locked()) { + return 0; + } + if (n_outputs().n_total() == 0) { return 0; } if (!_active || n_inputs() == ChanCount::ZERO) { - silence (nframes); + silence_unlocked (nframes); return 0; } if (session_state_changing) { @@ -2609,7 +2702,7 @@ Route::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, XXX note the absurdity of ::no_roll() being called when we ARE rolling! */ - silence (nframes); + silence_unlocked (nframes); return 0; } /* we're really not rolling, so we're either delivery silence or actually @@ -2629,14 +2722,14 @@ Route::check_initial_delay (nframes_t nframes, nframes_t& transport_frame) if (_roll_delay > nframes) { _roll_delay -= nframes; - silence (nframes); + silence_unlocked (nframes); /* transport frame is not legal for caller to use */ return 0; } else if (_roll_delay > 0) { nframes -= _roll_delay; - silence (_roll_delay); + silence_unlocked (_roll_delay); /* we've written _roll_delay of samples into the output ports, so make a note of that for future reference. @@ -2652,24 +2745,21 @@ Route::check_initial_delay (nframes_t nframes, nframes_t& transport_frame) int Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, - bool /*can_record*/, bool /*rec_monitors_input*/) + bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */) { - { - // automation snapshot can also be called from the non-rt context - // and it uses the processor list, so we try to acquire the lock here - Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); - - if (lm.locked()) { - automation_snapshot (_session.transport_frame(), false); - } + Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + if (!lm.locked()) { + return 0; } + + automation_snapshot (_session.transport_frame(), false); if (n_outputs().n_total() == 0) { return 0; } if (!_active || n_inputs().n_total() == 0) { - silence (nframes); + silence_unlocked (nframes); return 0; } @@ -2688,7 +2778,7 @@ Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int int Route::silent_roll (nframes_t nframes, sframes_t /*start_frame*/, sframes_t /*end_frame*/, - bool /*can_record*/, bool /*rec_monitors_input*/) + bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */) { silence (nframes); return 0; @@ -2740,13 +2830,12 @@ Route::flush_processors () Glib::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - (*i)->deactivate (); - (*i)->activate (); + (*i)->flush (); } } void -Route::set_meter_point (MeterPoint p, void *src) +Route::set_meter_point (MeterPoint p) { /* CAN BE CALLED FROM PROCESS CONTEXT */ @@ -2808,7 +2897,7 @@ Route::set_meter_point (MeterPoint p, void *src) } _meter_point = p; - meter_change (src); /* EMIT SIGNAL */ + meter_change (); /* EMIT SIGNAL */ bool const meter_visibly_changed = (_meter->display_to_user() != meter_was_visible_to_user); @@ -2816,16 +2905,16 @@ Route::set_meter_point (MeterPoint p, void *src) } void -Route::put_control_outs_at (Placement p) +Route::put_monitor_send_at (Placement p) { - if (!_control_outs) { + if (!_monitor_send) { return; } { Glib::RWLock::WriterLock lm (_processor_lock); ProcessorList as_it_was (_processors); - ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), _control_outs); + ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), _monitor_send); _processors.erase(loc); switch (p) { @@ -2840,7 +2929,7 @@ Route::put_control_outs_at (Placement p) break; } - _processors.insert (loc, _control_outs); + _processors.insert (loc, _monitor_send); if (configure_processors_unlocked (0)) { _processors = as_it_was; @@ -2938,7 +3027,7 @@ Route::SoloControllable::SoloControllable (std::string name, Route& r) } void -Route::SoloControllable::set_value (float val) +Route::SoloControllable::set_value (double val) { bool bval = ((val >= 0.5f) ? true: false); # if 0 @@ -2957,7 +3046,7 @@ Route::SoloControllable::set_value (float val) #endif } -float +double Route::SoloControllable::get_value (void) const { if (Config->get_solo_control_is_listen_control()) { @@ -2977,7 +3066,7 @@ Route::MuteControllable::MuteControllable (std::string name, Route& r) } void -Route::MuteControllable::set_value (float val) +Route::MuteControllable::set_value (double val) { bool bval = ((val >= 0.5f) ? true: false); # if 0 @@ -2991,7 +3080,7 @@ Route::MuteControllable::set_value (float val) #endif } -float +double Route::MuteControllable::get_value (void) const { return route.muted() ? 1.0f : 0.0f; @@ -3143,19 +3232,39 @@ Route::internal_send_for (boost::shared_ptr target) const return boost::shared_ptr(); } +/** @param c Audio channel index. + * @param yn true to invert phase, otherwise false. + */ +void +Route::set_phase_invert (uint32_t c, bool yn) +{ + if (_phase_invert[c] != yn) { + _phase_invert[c] = yn; + phase_invert_changed (); /* EMIT SIGNAL */ + _session.set_dirty (); + } +} + void -Route::set_phase_invert (bool yn) +Route::set_phase_invert (boost::dynamic_bitset<> p) { - if (_phase_invert != yn) { - _phase_invert = 0xffff; // XXX all channels + if (_phase_invert != p) { + _phase_invert = p; phase_invert_changed (); /* EMIT SIGNAL */ + _session.set_dirty (); } } bool +Route::phase_invert (uint32_t c) const +{ + return _phase_invert[c]; +} + +boost::dynamic_bitset<> Route::phase_invert () const { - return _phase_invert != 0; + return _phase_invert; } void @@ -3272,15 +3381,51 @@ Route::nth_send (uint32_t n) ProcessorList::iterator i; for (i = _processors.begin(); i != _processors.end(); ++i) { - cerr << "check " << (*i)->name() << endl; if (boost::dynamic_pointer_cast (*i)) { if (n-- == 0) { return *i; } - } else { - cerr << "\tnot a send\n"; - } + } } return boost::shared_ptr (); } + +bool +Route::has_io_processor_named (const string& name) +{ + Glib::RWLock::ReaderLock lm (_processor_lock); + ProcessorList::iterator i; + + for (i = _processors.begin(); i != _processors.end(); ++i) { + if (boost::dynamic_pointer_cast (*i) || + boost::dynamic_pointer_cast (*i)) { + if ((*i)->name() == name) { + return true; + } + } + } + + return false; +} + +MuteMaster::MutePoint +Route::mute_points () const +{ + return _mute_master->mute_points (); +} + +void +Route::set_processor_positions () +{ + Glib::RWLock::ReaderLock lm (_processor_lock); + + bool had_amp = false; + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + (*i)->set_pre_fader (!had_amp); + if (boost::dynamic_pointer_cast (*i)) { + had_amp = true; + } + } +} +