X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Froute.cc;h=c750ca2719d05ee3f5b76692b5555061b2359f62;hb=bc706064c6be9ed740961e1b49d8a469b2b17a0b;hp=9a2559e2404be3be5a960ed59d1703137382bd9c;hpb=81857a947c106586e2a90c46cb8f69cdd3ad600d;p=ardour.git diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 9a2559e240..c750ca2719 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -1,21 +1,33 @@ /* - Copyright (C) 2000 Paul Davis - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ + * Copyright (C) 2000-2019 Paul Davis + * Copyright (C) 2006-2007 Sampo Savolainen + * Copyright (C) 2006-2014 David Robillard + * Copyright (C) 2006 Jesse Chappell + * Copyright (C) 2008-2012 Carl Hetherington + * Copyright (C) 2011-2012 Sakari Bergen + * Copyright (C) 2013-2015 Nick Mainsbridge + * Copyright (C) 2013-2017 John Emmas + * Copyright (C) 2013-2019 Robin Gareus + * Copyright (C) 2014-2018 Ben Loftis + * Copyright (C) 2015-2018 Len Ovens + * Copyright (C) 2016 Julien "_FrnchFrgg_" RIVAUD + * Copyright (C) 2016 Tim Mayberry + * Copyright (C) 2017-2018 Johannes Mueller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ #ifdef WAF_BUILD #include "libardour-config.h" @@ -71,6 +83,7 @@ #include "ardour/port_insert.h" #include "ardour/processor.h" #include "ardour/profile.h" +#include "ardour/revision.h" #include "ardour/route.h" #include "ardour/route_group.h" #include "ardour/send.h" @@ -102,7 +115,6 @@ Route::Route (Session& sess, string name, PresentationInfo::Flag flag, DataType , _pending_signals (0) , _meter_point (MeterPostFader) , _pending_meter_point (MeterPostFader) - , _meter_type (MeterPeak) , _denormal_protection (false) , _recordable (true) , _have_internal_generator (false) @@ -128,16 +140,6 @@ Route::weakroute () { int Route::init () { - /* set default meter type */ - if (is_master()) { - _meter_type = Config->get_meter_type_master (); - } - else if (dynamic_cast(this)) { - _meter_type = Config->get_meter_type_track (); - } else { - _meter_type = Config->get_meter_type_bus (); - } - /* add standard controls */ _gain_control.reset (new GainControl (_session, GainAutomation)); @@ -186,7 +188,8 @@ Route::init () */ _amp.reset (new Amp (_session, X_("Fader"), _gain_control, true)); - add_processor (_amp, PostFader); + _amp->activate (); + _amp->set_owner (this); _polarity.reset (new PolarityProcessor (_session, _phase_control)); _polarity->activate(); @@ -211,7 +214,7 @@ Route::init () */ _trim->activate(); } - else if (!dynamic_cast(this) && ! ( is_monitor() || is_auditioner() )) { + else if (!dynamic_cast(this) && ! (is_monitor() || is_auditioner())) { /* regular bus */ _trim->activate(); } @@ -225,6 +228,19 @@ Route::init () _meter->set_display_to_user (false); _meter->activate (); + /* set default meter type */ + if (is_master()) { +#ifdef MIXBUS + set_meter_type (MeterK14); +#else + set_meter_type (Config->get_meter_type_master ()); +#endif + } else if (dynamic_cast(this)) { + set_meter_type (Config->get_meter_type_track ()); + } else { + set_meter_type (Config->get_meter_type_bus ()); + } + _main_outs.reset (new Delivery (_session, _output, _pannable, _mute_master, _name, Delivery::Main)); _main_outs->activate (); @@ -239,12 +255,20 @@ Route::init () _monitor_control.reset (new MonitorProcessor (_session)); _monitor_control->activate (); } + if (_presentation_info.flags() & PresentationInfo::FoldbackBus) { + panner_shell()->select_panner_by_uri ("http://ardour.org/plugin/panner_balance"); + } - /* now that we have _meter, its safe to connect to this */ - + /* now set up processor chain and invisible processors */ { Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); - configure_processors (0); + { + Glib::Threads::RWLock::WriterLock lm (_processor_lock); + _processors.push_back (_amp); + } + if (!_session.loading()) { + configure_processors (0); + } } return 0; @@ -407,10 +431,10 @@ Route::process_output_buffers (BufferSet& bufs, * Also during remaining_latency_preroll, transport_rolling () is false, but * we may need to monitor disk instead. */ - MonitorState ms = monitoring_state (); - bool silence = _have_internal_generator ? false : (ms == MonitoringSilence); + const MonitorState ms = monitoring_state (); + const bool silent = _have_internal_generator ? false : (ms == MonitoringSilence); - _main_outs->no_outs_cuz_we_no_monitor (silence); + _main_outs->no_outs_cuz_we_no_monitor (silent); /* ------------------------------------------------------------------------------------------- DENORMAL CONTROL @@ -499,7 +523,7 @@ Route::process_output_buffers (BufferSet& bufs, * So there can be cases where adding up all latencies may not equal _signal_latency. */ if ((*i)->active ()) { - latency += (*i)->signal_latency (); + latency += (*i)->effective_latency (); } if (re_inject_oob_data) { @@ -533,13 +557,21 @@ Route::bounce_process (BufferSet& buffers, samplepos_t start, samplecnt_t nframe _trim->setup_gain_automation (start, start + nframes, nframes); latency = 0; - const double speed = _session.transport_speed (); + bool seen_disk_io = false; for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if (!include_endpoint && (*i) == endpoint) { break; } + if (!for_export && !seen_disk_io) { + if (boost::dynamic_pointer_cast (*i)) { + seen_disk_io = true; + buffers.set_count ((*i)->output_streams()); + } + continue; + } + /* if we're *not* exporting, stop processing if we come across a routing processor. */ if (!for_export && boost::dynamic_pointer_cast(*i)) { break; @@ -556,7 +588,7 @@ Route::bounce_process (BufferSet& buffers, samplepos_t start, samplecnt_t nframe */ if ((*i) == _main_outs) { assert ((*i)->does_routing()); - (*i)->run (buffers, start - latency, start - latency + nframes, speed, nframes, true); + (*i)->run (buffers, start - latency, start - latency + nframes, 1.0, nframes, true); buffers.set_count ((*i)->output_streams()); } @@ -566,7 +598,7 @@ Route::bounce_process (BufferSet& buffers, samplepos_t start, samplecnt_t nframe if (!(*i)->does_routing() && !boost::dynamic_pointer_cast(*i)) { (*i)->run (buffers, start - latency, start - latency + nframes, 1.0, nframes, true); buffers.set_count ((*i)->output_streams()); - latency += (*i)->signal_latency (); + latency += (*i)->effective_latency (); } if ((*i) == endpoint) { @@ -584,10 +616,17 @@ Route::bounce_get_latency (boost::shared_ptr endpoint, return latency; } + bool seen_disk_io = false; for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { if (!include_endpoint && (*i) == endpoint) { break; } + if (!for_export && !seen_disk_io) { + if (boost::dynamic_pointer_cast (*i)) { + seen_disk_io = true; + } + continue; + } if (!for_export && boost::dynamic_pointer_cast(*i)) { break; } @@ -595,7 +634,7 @@ Route::bounce_get_latency (boost::shared_ptr endpoint, break; } if (!(*i)->does_routing() && !boost::dynamic_pointer_cast(*i)) { - latency += (*i)->signal_latency (); + latency += (*i)->effective_latency (); } if ((*i) == endpoint) { break; @@ -938,7 +977,7 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version) //A2 uses the "active" flag in the toplevel redirect node, not in the child plugin/IO if (i != children.end()) { if ((prop = (*i)->property (X_("active"))) != 0) { - if ( string_to (prop->value()) && (!_session.get_bypass_all_loaded_plugins () || !processor->display_to_user () ) ) + if (string_to (prop->value()) && (!_session.get_bypass_all_loaded_plugins () || !processor->display_to_user ())) processor->activate(); else processor->deactivate(); @@ -1106,7 +1145,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr (*i)->activate (); } - (*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false)); + (*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false)); boost::shared_ptr send; if ((send = boost::dynamic_pointer_cast (*i))) { @@ -1125,8 +1164,6 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr } } } - - _output->set_user_latency (0); } reset_instrument_info (); @@ -1365,6 +1402,11 @@ Route::is_internal_processor (boost::shared_ptr p) const if (p == _amp || p == _meter || p == _main_outs || p == _delayline || p == _trim || p == _polarity) { return true; } +#ifdef MIXBUS + if (p == _ch_pre || p == _ch_post || p == _ch_eq || p == _ch_comp) { + return true; + } +#endif return false; } @@ -1444,8 +1486,6 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream } else { ++i; } - - _output->set_user_latency (0); } if (!removed) { @@ -1572,8 +1612,7 @@ Route::replace_processor (boost::shared_ptr old, boost::shared_ptrenable (true); } - sub->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false)); - _output->set_user_latency (0); + sub->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false)); } reset_instrument_info (); @@ -1645,8 +1684,6 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* return 0; } - _output->set_user_latency (0); - if (configure_processors_unlocked (err, &lm)) { pstate.restore (); /* we know this will work, because it worked before :) */ @@ -2014,7 +2051,7 @@ Route::apply_processor_order (const ProcessorList& new_order) /* "new_order" is an ordered list of processors to be positioned according to "placement". * NOTE: all processors in "new_order" MUST be marked as display_to_user(). There maybe additional * processors in the current actual processor list that are hidden. Any visible processors - * in the current list but not in "new_order" will be assumed to be deleted. + * in the current list but not in "new_order" will be assumed to be deleted. */ /* "as_it_will_be" and "_processors" are lists of shared pointers. @@ -2036,17 +2073,17 @@ Route::apply_processor_order (const ProcessorList& new_order) while (niter != new_order.end()) { /* if the next processor in the old list is invisible (i.e. should not be in the new order) - then append it to the temp list. - - Otherwise, see if the next processor in the old list is in the new list. if not, - its been deleted. If its there, append it to the temp list. - */ + * then append it to the temp list. + * + * Otherwise, see if the next processor in the old list is in the new list. if not, + * its been deleted. If its there, append it to the temp list. + */ if (oiter == _processors.end()) { /* no more elements in the old list, so just stick the rest of - the new order onto the temp list. - */ + * the new order onto the temp list. + */ as_it_will_be.insert (as_it_will_be.end(), niter, new_order.end()); while (niter != new_order.end()) { @@ -2082,6 +2119,44 @@ Route::apply_processor_order (const ProcessorList& new_order) /* If the meter is in a custom position, find it and make a rough note of its position */ maybe_note_meter_position (); + + /* if any latent plugins were re-ordered and sends or side-chains are present + * in the signal-flow, a full latency-recompute is needed. + * + * The Session will be informed about the new order via + * processors_changed() + * and test if a full latency-recompute is required by comparing + * _signal_latency != ::update_signal_latency(); + * + * Since the route's latency itself does not initially change by + * re-ordering, we need to force this: + */ + bool need_latency_recompute = false; + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + if (boost::shared_ptr pi = boost::dynamic_pointer_cast (*i)) { + need_latency_recompute = true; + break; + } else if (boost::shared_ptr snd = boost::dynamic_pointer_cast (*i)) { + need_latency_recompute = true; + break; + } else if (boost::shared_ptr pi = boost::dynamic_pointer_cast (*i)) { + if (boost::shared_ptr pio = pi->sidechain_input ()) { + need_latency_recompute = true; + break; + } + } + } + if (need_latency_recompute) { + /* force a change, the correct value will be set + * ::update_signal_latency() will be called via + * + * SIGNAL processors_changed () -> + * -> Session::route_processors_changed () + * -> Session::update_latency_compensation () + * -> Route::::update_signal_latency () + */ + _signal_latency = 0; + } } void @@ -2407,6 +2482,14 @@ Route::state (bool save_template) XMLNode *node = new XMLNode("Route"); ProcessorList::iterator i; + if(save_template) { + XMLNode* child = node->add_child("ProgramVersion"); + child->set_property("created-with", _session.created_with); + + std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision); + child->set_property("modified-with", modified_with); + } + node->set_property (X_("id"), id ()); node->set_property (X_("name"), name()); node->set_property (X_("default-type"), _default_type); @@ -2419,7 +2502,7 @@ Route::state (bool save_template) node->set_property (X_("meter-point"), _meter_point); node->set_property (X_("disk-io-point"), _disk_io_point); - node->set_property (X_("meter-type"), _meter_type); + node->set_property (X_("meter-type"), _meter->meter_type ()); if (_route_group) { node->set_property (X_("route-group"), _route_group->name()); @@ -2588,7 +2671,10 @@ Route::set_state (const XMLNode& node, int version) set_disk_io_point (diop); } - node.get_property (X_("meter-type"), _meter_type); + MeterType meter_type; + if (node.get_property (X_("meter-type"), meter_type)) { + set_meter_type (meter_type); + } _initial_io_setup = false; @@ -2953,14 +3039,30 @@ Route::set_processor_state (const XMLNode& node) */ _processors = new_order; - if (must_configure) { + /* When a required/existing internal processor is not in the list, it needs to + * be added via configure_processors() -> setup_invisible_processors() + */ + if (_monitor_control) { + must_configure |= find (_processors.begin(), _processors.end(), _monitor_control) == _processors.end (); + } + if (_main_outs) { + must_configure |= find (_processors.begin(), _processors.end(), _main_outs) == _processors.end (); + } + if (_delayline) { + must_configure |= find (_processors.begin(), _processors.end(), _delayline) == _processors.end (); + } + if (_intreturn) { + must_configure |= find (_processors.begin(), _processors.end(), _intreturn) == _processors.end (); + } + + if (must_configure && !_session.loading()) { configure_processors_unlocked (0, &lm); } for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { (*i)->set_owner (this); - (*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false)); + (*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false)); boost::shared_ptr pi; @@ -3017,11 +3119,6 @@ Route::set_processor_state (XMLNode const & node, XMLProperty const* prop, Proce } else { processor.reset (new PluginInsert (_session)); processor->set_owner (this); - if (_strict_io) { - boost::shared_ptr pi = boost::dynamic_pointer_cast(processor); - pi->set_strict_io (true); - } - } } else if (prop->value() == "port") { @@ -3035,6 +3132,7 @@ Route::set_processor_state (XMLNode const & node, XMLProperty const* prop, Proce boost::bind (&Route::processor_selfdestruct, this, boost::weak_ptr (processor))); } else { + warning << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; return false; } @@ -3043,8 +3141,14 @@ Route::set_processor_state (XMLNode const & node, XMLProperty const* prop, Proce processor.reset (new UnknownProcessor (_session, node)); } - /* subscribe to Sidechain IO changes */ + /* set strict I/O only after loading plugin state, because + * individual plugins may override this */ boost::shared_ptr pi = boost::dynamic_pointer_cast (processor); + if (pi && _strict_io) { + pi->set_strict_io (true); + } + + /* subscribe to Sidechain IO changes */ if (pi && pi->has_sidechain ()) { pi->sidechain_input ()->changed.connect_same_thread (*this, boost::bind (&Route::sidechain_change_handler, this, _1, _2)); } @@ -3067,13 +3171,6 @@ Route::set_processor_state (XMLNode const & node, XMLProperty const* prop, Proce return true; } -void -Route::curve_reallocate () -{ -// _gain_automation_curve.finish_resize (); -// _pan_automation_curve.finish_resize (); -} - void Route::silence (samplecnt_t nframes) { @@ -3241,11 +3338,13 @@ Route::add_foldback_send (boost::shared_ptr route) listener.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast(shared_from_this()), route, Delivery::Foldback)); } + listener->panner_shell()->set_linked_to_route (false); add_processor (listener, before); } catch (failed_constructor& err) { return -1; } + _session.FBSendsChanged (); return 0; } @@ -3255,6 +3354,7 @@ Route::remove_aux_or_listen (boost::shared_ptr route) { ProcessorStreams err; ProcessorList::iterator tmp; + bool do_fb_signal = false; { Glib::Threads::RWLock::ReaderLock rl(_processor_lock); @@ -3273,6 +3373,11 @@ Route::remove_aux_or_listen (boost::shared_ptr route) boost::shared_ptr d = boost::dynamic_pointer_cast(*x); if (d && d->target_route() == route) { + boost::shared_ptr snd = boost::dynamic_pointer_cast(d); + if (snd && snd->is_foldback()) { + do_fb_signal = true; + } + rl.release (); if (remove_processor (*x, &err, false) > 0) { rl.acquire (); @@ -3292,6 +3397,10 @@ Route::remove_aux_or_listen (boost::shared_ptr route) } } } + if (do_fb_signal) { + _session.FBSendsChanged (); + } + } void @@ -3393,9 +3502,9 @@ Route::all_outputs () const bool Route::direct_feeds_according_to_reality (boost::shared_ptr other, bool* via_send_only) { - DEBUG_TRACE (DEBUG::Graph, string_compose ("Feeds? %1\n", _name)); + DEBUG_TRACE (DEBUG::Graph, string_compose ("Feeds from %1 (-> %2)?\n", _name, other->name())); if (other->all_inputs().fed_by (_output)) { - DEBUG_TRACE (DEBUG::Graph, string_compose ("\tdirect FEEDS %2\n", other->name())); + DEBUG_TRACE (DEBUG::Graph, string_compose ("\tdirect FEEDS to %1\n", other->name())); if (via_send_only) { *via_send_only = false; } @@ -3430,10 +3539,7 @@ Route::direct_feeds_according_to_reality (boost::shared_ptr other, bool* } else { DEBUG_TRACE (DEBUG::Graph, string_compose ("\tIOP %1 does NOT feed %2\n", iop->name(), other->name())); } - } else { - DEBUG_TRACE (DEBUG::Graph, string_compose ("\tPROC %1 is not an IOP\n", (*r)->name())); } - } DEBUG_TRACE (DEBUG::Graph, string_compose ("\tdoes NOT feed %1\n", other->name())); @@ -3485,6 +3591,10 @@ Route::realtime_handle_transport_stopped () void Route::input_change_handler (IOChange change, void * /*src*/) { + if (_session.loading()) { + return; + } + if ((change.type & IOChange::ConfigurationChanged)) { /* This is called with the process lock held if change contains ConfigurationChanged @@ -3889,16 +3999,18 @@ Route::set_meter_point (MeterPoint p, bool force) } if (force || !AudioEngine::instance()->running()) { - Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); - Glib::Threads::RWLock::WriterLock lm (_processor_lock); - _pending_meter_point = p; + bool meter_visibly_changed = false; + { + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); + _pending_meter_point = p; + if (set_meter_point_unlocked ()) { + meter_visibly_changed = true; + } + } _meter->emit_configuration_changed(); meter_change (); /* EMIT SIGNAL */ - if (set_meter_point_unlocked()) { - processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, true)); /* EMIT SIGNAL */ - } else { - processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, false)); /* EMIT SIGNAL */ - } + processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, meter_visibly_changed)); /* EMIT SIGNAL */ } else { _pending_meter_point = p; } @@ -4033,9 +4145,9 @@ Route::update_signal_latency (bool apply_to_delayline) Glib::Threads::RWLock::ReaderLock lm (_processor_lock); samplecnt_t l_in = 0; - samplecnt_t l_out = _output->user_latency(); + samplecnt_t l_out = 0; for (ProcessorList::reverse_iterator i = _processors.rbegin(); i != _processors.rend(); ++i) { - if (boost::shared_ptr snd = boost::dynamic_pointer_cast (*i)) { + if (boost::shared_ptr snd = boost::dynamic_pointer_cast (*i)) { snd->set_delay_in (l_out + _output->latency()); } @@ -4047,8 +4159,8 @@ Route::update_signal_latency (bool apply_to_delayline) } } (*i)->set_output_latency (l_out); - if ((*i)->active ()) { - l_out += (*i)->signal_latency (); + if ((*i)->active ()) { // XXX + l_out += (*i)->effective_latency (); } } @@ -4075,6 +4187,7 @@ Route::update_signal_latency (bool apply_to_delayline) snd->output ()->set_private_port_latencies (capt_lat_in + l_in, false); /* take send-target's playback latency into account */ snd->set_delay_out (snd->output ()->connected_latency (true)); + /* InternalReturn::set_playback_offset() below, also calls set_delay_out() */ } } @@ -4082,7 +4195,7 @@ Route::update_signal_latency (bool apply_to_delayline) (*i)->set_playback_offset (_signal_latency + _output->latency ()); (*i)->set_capture_offset (_input->latency ()); if ((*i)->active ()) { - l_in += (*i)->signal_latency (); + l_in += (*i)->effective_latency (); } } @@ -4100,13 +4213,6 @@ Route::update_signal_latency (bool apply_to_delayline) return _signal_latency; } -void -Route::set_user_latency (samplecnt_t nframes) -{ - _output->set_user_latency (nframes); - _session.update_latency_compensation (); -} - void Route::apply_latency_compensation () { @@ -4160,28 +4266,6 @@ Route::protect_automation () void Route::shift (samplepos_t pos, samplecnt_t samples) { - /* gain automation */ - { - boost::shared_ptr gc = _amp->gain_control(); - - XMLNode &before = gc->alist()->get_state (); - gc->alist()->shift (pos, samples); - XMLNode &after = gc->alist()->get_state (); - _session.add_command (new MementoCommand (*gc->alist().get(), &before, &after)); - } - - /* gain automation */ - { - boost::shared_ptr gc = _trim->gain_control(); - - XMLNode &before = gc->alist()->get_state (); - gc->alist()->shift (pos, samples); - XMLNode &after = gc->alist()->get_state (); - _session.add_command (new MementoCommand (*gc->alist().get(), &before, &after)); - } - - // TODO mute automation ?? - /* pan automation */ if (_pannable) { ControlSet::Controls& c (_pannable->controls()); @@ -4198,7 +4282,9 @@ Route::shift (samplepos_t pos, samplecnt_t samples) } } - /* redirect automation */ + /* TODO mute automation, MuteControl */ + + /* processor automation (incl. gain, trim,..) */ { Glib::Threads::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::iterator i = _processors.begin (); i != _processors.end (); ++i) { @@ -4209,6 +4295,9 @@ Route::shift (samplepos_t pos, samplecnt_t samples) boost::shared_ptr ac = (*i)->automation_control (*p); if (ac) { boost::shared_ptr al = ac->alist(); + if (al->empty ()) { + continue; + } XMLNode &before = al->get_state (); al->shift (pos, samples); XMLNode &after = al->get_state (); @@ -4236,7 +4325,7 @@ Route::save_as_template (const string& path, const string& name, const string& d std::string state_dir = path.substr (0, path.find_last_of ('.')); // strip template_suffix PBD::Unwinder uw (_session._template_state_dir, state_dir); - XMLNode& node (state (false)); + XMLNode& node (state (true)); node.set_property (X_("name"), name); node.remove_nodes (X_("description")); @@ -4313,7 +4402,7 @@ Route::set_name (const string& str) * @param name New name. */ void -Route::set_name_in_state (XMLNode& node, string const & name, bool rename_playlist) +Route::set_name_in_state (XMLNode& node, string const & name) { node.set_property (X_("name"), name); @@ -4330,14 +4419,6 @@ Route::set_name_in_state (XMLNode& node, string const & name, bool rename_playli if ((*i)->get_property (X_("role"), str) && str == X_("Main")) { (*i)->set_property (X_("name"), name); } - - } else if ((*i)->name() == X_("Diskstream")) { - - if (rename_playlist) { - (*i)->set_property (X_("playlist"), name + ".1"); - } - (*i)->set_property (X_("name"), name); - } } } @@ -4490,10 +4571,10 @@ Route::nth_send (uint32_t n) const for (i = _processors.begin(); i != _processors.end(); ++i) { if (boost::dynamic_pointer_cast (*i)) { - if ((*i)->name().find (_("Monitor")) == 0) { + if ((*i) == _monitor_send) { /* send to monitor section is not considered - to be an accessible send. - */ + * to be an accessible send. + */ continue; } @@ -4659,7 +4740,7 @@ Route::set_private_port_latencies (bool playback) const for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { if ((*i)->active ()) { - own_latency += (*i)->signal_latency (); + own_latency += (*i)->effective_latency (); } } @@ -5225,13 +5306,10 @@ boost::shared_ptr Route::pan_azimuth_control() const { #ifdef MIXBUS -# undef MIXBUS_PORTS_H -# include "../../gtk2_ardour/mixbus_ports.h" - boost::shared_ptr plug = ch_post(); - if (!plug) { - return boost::shared_ptr(); + if (_mixbus_send) { + return _mixbus_send->master_pan_ctrl (); } - return boost::dynamic_pointer_cast (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_channel_post_pan))); + return boost::shared_ptr(); #else if (!_pannable || !panner()) { return boost::shared_ptr(); @@ -5261,7 +5339,7 @@ Route::pan_width_control() const #ifdef MIXBUS if (mixbus() && _ch_pre) { //mono blend - return boost::dynamic_pointer_cast(_ch_pre->control(Evoral::Parameter(PluginAutomation, 0, 5))); + return boost::dynamic_pointer_cast(_ch_pre->control(Evoral::Parameter(PluginAutomation, 0, 1))); } #endif if (Profile->get_mixbus() || !_pannable || !panner()) { @@ -5330,7 +5408,7 @@ boost::shared_ptr Route::eq_gain_controllable (uint32_t band) const { #ifdef MIXBUS - boost::shared_ptr eq = ch_eq(); + boost::shared_ptr eq = _ch_eq; if (!eq) { return boost::shared_ptr(); @@ -5380,7 +5458,7 @@ Route::eq_freq_controllable (uint32_t band) const return boost::shared_ptr(); } - boost::shared_ptr eq = ch_eq(); + boost::shared_ptr eq = _ch_eq; if (!eq) { return boost::shared_ptr(); @@ -5422,7 +5500,6 @@ boost::shared_ptr Route::eq_shape_controllable (uint32_t band) const { #ifdef MIXBUS32C - boost::shared_ptr eq = ch_eq(); if (is_master() || mixbus() || !eq) { return boost::shared_ptr(); } @@ -5444,7 +5521,7 @@ boost::shared_ptr Route::eq_enable_controllable () const { #ifdef MIXBUS - boost::shared_ptr eq = ch_eq(); + boost::shared_ptr eq = _ch_eq; if (!eq) { return boost::shared_ptr(); @@ -5460,7 +5537,7 @@ boost::shared_ptr Route::filter_freq_controllable (bool hpf) const { #ifdef MIXBUS - boost::shared_ptr eq = ch_eq(); + boost::shared_ptr eq = _ch_eq; if (is_master() || mixbus() || !eq) { return boost::shared_ptr(); @@ -5494,7 +5571,7 @@ boost::shared_ptr Route::filter_enable_controllable (bool) const { #ifdef MIXBUS32C - boost::shared_ptr eq = ch_eq(); + boost::shared_ptr eq = _ch_eq; if (is_master() || mixbus() || !eq) { return boost::shared_ptr(); @@ -5510,17 +5587,68 @@ boost::shared_ptr Route::tape_drive_controllable () const { #ifdef MIXBUS - if (_ch_pre && mixbus()) { - return boost::dynamic_pointer_cast (_ch_pre->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 4))); + if (_ch_pre) { + return boost::dynamic_pointer_cast (_ch_pre->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 0))); } - if (_ch_pre && is_master()) { - return boost::dynamic_pointer_cast (_ch_pre->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 1))); +#endif + return boost::shared_ptr(); +} + +boost::shared_ptr +Route::tape_drive_mtr_controllable () const +{ +#ifdef MIXBUS + if (_ch_pre) { + return _ch_pre->control_output (is_master() ? 1 : 2); + } +#endif + return boost::shared_ptr(); +} + +boost::shared_ptr +Route::master_correlation_mtr_controllable (bool mm) const +{ +#ifdef MIXBUS + if (is_master() && _ch_post) { + return _ch_post->control_output (mm ? 4 : 3); } #endif + return boost::shared_ptr(); +} +boost::shared_ptr +Route::master_limiter_enable_controllable () const +{ +#ifdef MIXBUS + if (is_master() && _ch_post) { + return boost::dynamic_pointer_cast (_ch_post->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 1))); + } +#endif return boost::shared_ptr(); } +boost::shared_ptr +Route::master_limiter_mtr_controllable () const +{ +#ifdef MIXBUS + if (is_master() && _ch_post) { + return _ch_post->control_output (2); + } +#endif + return boost::shared_ptr(); +} + +boost::shared_ptr +Route::master_k_mtr_controllable () const +{ +#ifdef MIXBUS + if (is_master() && _ch_post) { + return _ch_post->control_output (5); + } +#endif + return boost::shared_ptr(); +} + string Route::eq_band_name (uint32_t band) const { @@ -5541,8 +5669,8 @@ Route::eq_band_name (uint32_t band) const } else { switch (band) { case 0: return _("lo"); - case 1: return _("lo mid"); - case 2: return _("hi mid"); + case 1: return _("lm"); + case 2: return _("hm"); case 3: return _("hi"); default: return string(); } @@ -5554,96 +5682,61 @@ boost::shared_ptr Route::comp_enable_controllable () const { #ifdef MIXBUS - boost::shared_ptr comp = ch_comp(); - - if (!comp) { - return boost::shared_ptr(); + if (_ch_comp) { + return boost::dynamic_pointer_cast (_ch_comp->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 1))); } - - return boost::dynamic_pointer_cast (comp->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 1))); -#else - return boost::shared_ptr(); #endif + return boost::shared_ptr(); } boost::shared_ptr Route::comp_threshold_controllable () const { #ifdef MIXBUS - boost::shared_ptr comp = ch_comp(); - - if (!comp) { - return boost::shared_ptr(); + if (_ch_comp) { + return boost::dynamic_pointer_cast (_ch_comp->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 2))); } - - return boost::dynamic_pointer_cast (comp->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 2))); - -#else - return boost::shared_ptr(); #endif + return boost::shared_ptr(); } boost::shared_ptr Route::comp_speed_controllable () const { #ifdef MIXBUS - boost::shared_ptr comp = ch_comp(); - - if (!comp) { - return boost::shared_ptr(); + if (_ch_comp) { + return boost::dynamic_pointer_cast (_ch_comp->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 3))); } - - return boost::dynamic_pointer_cast (comp->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 3))); -#else - return boost::shared_ptr(); #endif + return boost::shared_ptr(); } boost::shared_ptr Route::comp_mode_controllable () const { #ifdef MIXBUS - boost::shared_ptr comp = ch_comp(); - - if (!comp) { - return boost::shared_ptr(); + if (_ch_comp) { + return boost::dynamic_pointer_cast (_ch_comp->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 4))); } - - return boost::dynamic_pointer_cast (comp->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 4))); -#else - return boost::shared_ptr(); #endif + return boost::shared_ptr(); } boost::shared_ptr Route::comp_makeup_controllable () const { #ifdef MIXBUS - boost::shared_ptr comp = ch_comp(); - - if (!comp) { - return boost::shared_ptr(); + if (_ch_comp) { + return boost::dynamic_pointer_cast (_ch_comp->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 5))); } - - return boost::dynamic_pointer_cast (comp->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, 5))); -#else - return boost::shared_ptr(); #endif + return boost::shared_ptr(); } boost::shared_ptr Route::comp_redux_controllable () const { #ifdef MIXBUS - boost::shared_ptr comp = ch_comp(); - - if (!comp) { - return boost::shared_ptr(); - } - if (is_master()) { - return comp->control_output (2); - } else { - return comp->control_output (6); + if (_ch_comp) { + return _ch_comp->control_output (6); } - -#else - return boost::shared_ptr(); #endif + return boost::shared_ptr(); } string @@ -5687,39 +5780,15 @@ Route::comp_speed_name (uint32_t mode) const } boost::shared_ptr -Route::send_pan_azi_controllable (uint32_t n) const +Route::send_pan_azimuth_controllable (uint32_t n) const { #ifdef MIXBUS -# undef MIXBUS_PORTS_H -# include "../../gtk2_ardour/mixbus_ports.h" - boost::shared_ptr plug = ch_post(); - if (plug && !mixbus()) { - uint32_t port_id = 0; - switch (n) { -# ifdef MIXBUS32C - case 0: port_id = port_channel_post_aux0_pan; break; //32c mb "pan" controls use zero-based names, unlike levels. ugh - case 1: port_id = port_channel_post_aux1_pan; break; - case 2: port_id = port_channel_post_aux2_pan; break; - case 3: port_id = port_channel_post_aux3_pan; break; - case 4: port_id = port_channel_post_aux4_pan; break; - case 5: port_id = port_channel_post_aux5_pan; break; - case 6: port_id = port_channel_post_aux6_pan; break; - case 7: port_id = port_channel_post_aux7_pan; break; - case 8: port_id = port_channel_post_aux8_pan; break; - case 9: port_id = port_channel_post_aux9_pan; break; - case 10: port_id = port_channel_post_aux10_pan; break; - case 11: port_id = port_channel_post_aux11_pan; break; -# endif - default: - break; - } - - if (port_id > 0) { - return boost::dynamic_pointer_cast (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_id))); + if (_mixbus_send) { + if (n < _mixbus_send->n_busses ()) { + return _mixbus_send->send_pan_ctrl (n + 1); } } #endif - return boost::shared_ptr(); } @@ -5727,87 +5796,28 @@ boost::shared_ptr Route::send_level_controllable (uint32_t n) const { #ifdef MIXBUS -# undef MIXBUS_PORTS_H -# include "../../gtk2_ardour/mixbus_ports.h" - boost::shared_ptr plug = ch_post(); - if (plug && !mixbus()) { - uint32_t port_id = 0; - switch (n) { - case 0: port_id = port_channel_post_aux1_level; break; - case 1: port_id = port_channel_post_aux2_level; break; - case 2: port_id = port_channel_post_aux3_level; break; - case 3: port_id = port_channel_post_aux4_level; break; - case 4: port_id = port_channel_post_aux5_level; break; - case 5: port_id = port_channel_post_aux6_level; break; - case 6: port_id = port_channel_post_aux7_level; break; - case 7: port_id = port_channel_post_aux8_level; break; -# ifdef MIXBUS32C - case 8: port_id = port_channel_post_aux9_level; break; - case 9: port_id = port_channel_post_aux10_level; break; - case 10: port_id = port_channel_post_aux11_level; break; - case 11: port_id = port_channel_post_aux12_level; break; -# endif - default: - break; - } - - if (port_id > 0) { - return boost::dynamic_pointer_cast (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_id))); + if (_mixbus_send) { + if (n < _mixbus_send->n_busses ()) { + return _mixbus_send->send_gain_ctrl (n + 1); } -# ifdef MIXBUS32C - assert (n > 11); - n -= 12; -# else - assert (n > 7); - n -= 8; -# endif + n -= _mixbus_send->n_busses (); } #endif boost::shared_ptr s = boost::dynamic_pointer_cast(nth_send (n)); - if (!s) { - return boost::shared_ptr(); + if (s) { + return s->gain_control (); } - return s->gain_control (); + return boost::shared_ptr(); } boost::shared_ptr Route::send_enable_controllable (uint32_t n) const { #ifdef MIXBUS -# undef MIXBUS_PORTS_H -# include "../../gtk2_ardour/mixbus_ports.h" - boost::shared_ptr plug = ch_post(); - if (plug && !mixbus()) { - uint32_t port_id = 0; - switch (n) { - case 0: port_id = port_channel_post_aux1_asgn; break; - case 1: port_id = port_channel_post_aux2_asgn; break; - case 2: port_id = port_channel_post_aux3_asgn; break; - case 3: port_id = port_channel_post_aux4_asgn; break; - case 4: port_id = port_channel_post_aux5_asgn; break; - case 5: port_id = port_channel_post_aux6_asgn; break; - case 6: port_id = port_channel_post_aux7_asgn; break; - case 7: port_id = port_channel_post_aux8_asgn; break; -# ifdef MIXBUS32C - case 8: port_id = port_channel_post_aux9_asgn; break; - case 9: port_id = port_channel_post_aux10_asgn; break; - case 10: port_id = port_channel_post_aux11_asgn; break; - case 11: port_id = port_channel_post_aux12_asgn; break; -# endif - default: - break; + if (_mixbus_send) { + if (n < _mixbus_send->n_busses ()) { + return _mixbus_send->send_enable_ctrl (n + 1); } - - if (port_id > 0) { - return boost::dynamic_pointer_cast (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, port_id))); - } -# ifdef MIXBUS32C - assert (n > 11); - n -= 12; -# else - assert (n > 7); - n -= 8; -# endif } #endif /* although Ardour sends have enable/disable as part of the Processor @@ -5818,31 +5828,35 @@ Route::send_enable_controllable (uint32_t n) const return boost::shared_ptr(); } +boost::shared_ptr +Route::send_pan_azimuth_enable_controllable (uint32_t n) const +{ +#ifdef MIXBUS + if (_mixbus_send) { + if (n < _mixbus_send->n_busses ()) { + return _mixbus_send->send_pan_enable_ctrl (n + 1); + } + } +#endif + return boost::shared_ptr(); +} + string Route::send_name (uint32_t n) const { -#ifdef MIXBUS - boost::shared_ptr plug = ch_post(); - if (plug && !mixbus()) { -# ifdef MIXBUS32C - if (n < 12) { - return _session.get_mixbus (n)->name(); - } - n -= 12; -#else - if (n < 8) { +#ifdef MIXBUS + if (_mixbus_send) { + if (n < _mixbus_send->n_busses ()) { return _session.get_mixbus (n)->name(); } - n -= 8; -# endif + n -= _mixbus_send->n_busses (); } #endif boost::shared_ptr p = nth_send (n); if (p) { return p->name(); - } else { - return string(); } + return string(); } boost::shared_ptr @@ -5853,14 +5867,12 @@ Route::master_send_enable_controllable () const return boost::shared_ptr(); } - boost::shared_ptr plug = mixbus() ? ch_pre () : ch_post(); - if (!plug) { - return boost::shared_ptr(); + if (_mixbus_send) { + return _mixbus_send->master_send_enable_ctrl (); } - return boost::dynamic_pointer_cast (plug->control (Evoral::Parameter (ARDOUR::PluginAutomation, 0, mixbus() ? 3 : 19))); -#else - return boost::shared_ptr(); + #endif + return boost::shared_ptr(); } bool @@ -5931,6 +5943,18 @@ Route::slavables () const return rv; } +void +Route::set_meter_type (MeterType t) +{ + _meter->set_meter_type (t); +} + +MeterType +Route::meter_type () const +{ + return _meter->meter_type (); +} + void Route::set_disk_io_point (DiskIOPoint diop) { @@ -5976,65 +6000,6 @@ Route::set_loop (Location* l) } } -#ifdef USE_TRACKS_CODE_FEATURES - -/* This is the Tracks version of Track::monitoring_state(). - * - * Ardour developers: try to flag or fix issues if parts of the libardour API - * change in ways that invalidate this - */ - -MonitorState -Route::monitoring_state () const -{ - /* Explicit requests */ - - if (_monitoring != MonitorInput) { - return MonitoringInput; - } - - if (_monitoring & MonitorDisk) { - return MonitoringDisk; - } - - /* This is an implementation of the truth table in doc/monitor_modes.pdf; - I don't think it's ever going to be too pretty too look at. - */ - - // GZ: NOT USED IN TRACKS - //bool const auto_input = _session.config.get_auto_input (); - //bool const software_monitor = Config->get_monitoring_model() == SoftwareMonitoring; - //bool const tape_machine_mode = Config->get_tape_machine_mode (); - - bool const roll = _session.transport_rolling (); - bool const track_rec = _diskstream->record_enabled (); - bool session_rec = _session.actively_recording (); - - if (track_rec) { - - if (!session_rec && roll) { - return MonitoringDisk; - } else { - return MonitoringInput; - } - - } else { - - if (roll) { - return MonitoringDisk; - } - } - - return MonitoringSilence; -} - -#else - -/* This is the Ardour/Mixbus version of Track::monitoring_state(). - * - * Tracks developers: do NOT modify this method under any circumstances. - */ - MonitorState Route::monitoring_state () const { @@ -6073,4 +6038,3 @@ Route::monitoring_state () const return get_auto_monitoring_state(); } -#endif