X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Froute.cc;h=b9acae45eb13ab804ed2d83bfd2014d49fe254a7;hb=e584ae0bf94673bf719e661c49e8a2f2d2dd0346;hp=ccfe38e9e18fa48f348a6117db7cdbec97967374;hpb=291618fe7116424448da5f7029e567d655526521;p=ardour.git diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index ccfe38e9e1..b9acae45eb 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -47,6 +47,7 @@ #include "ardour/internal_return.h" #include "ardour/internal_send.h" #include "ardour/meter.h" +#include "ardour/delayline.h" #include "ardour/midi_buffer.h" #include "ardour/midi_port.h" #include "ardour/monitor_processor.h" @@ -79,6 +80,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) , GraphNode (sess._process_graph) , _active (true) , _signal_latency (0) + , _signal_latency_at_amp_position (0) , _initial_delay (0) , _roll_delay (0) , _flags (flg) @@ -100,6 +102,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) , _order_key (0) , _has_order_key (false) , _remote_control_id (0) + , _track_number (0) , _in_configure_processors (false) , _initial_io_setup (false) , _custom_meter_position_noted (false) @@ -142,6 +145,13 @@ Route::init () _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2)); _output->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::output_port_count_changing, this, _1)); +#if 0 // not used - just yet + if (!is_master() && !is_monitor() && !is_auditioner()) { + _delayline.reset (new DelayLine (_session, _name)); + add_processor (_delayline, PreFader); + } +#endif + /* add amp processor */ _amp.reset (new Amp (_session)); @@ -419,13 +429,22 @@ Route::process_output_buffers (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick, bool gain_automation_ok) { + /* Caller must hold process lock */ + assert (!AudioEngine::instance()->process_lock().trylock()); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK); - assert(lm.locked()); + if (!lm.locked()) { + bufs.silence (nframes, 0); + return; + } /* figure out if we're going to use gain automation */ if (gain_automation_ok) { _amp->set_gain_automation_buffer (_session.gain_automation_buffer ()); - _amp->setup_gain_automation (start_frame, end_frame, nframes); + _amp->setup_gain_automation ( + start_frame + _signal_latency_at_amp_position, + end_frame + _signal_latency_at_amp_position, + nframes); } else { _amp->apply_gain_automation (false); } @@ -434,8 +453,13 @@ Route::process_output_buffers (BufferSet& bufs, on a transition between monitoring states we get a de-clicking gain change in the _main_outs delivery. */ + bool silence = monitoring_state () == MonitoringSilence; + + //but we override this in the case where we have an internal generator + if ( _have_internal_generator ) + silence = false; - _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence); + _main_outs->no_outs_cuz_we_no_monitor (silence); /* ------------------------------------------------------------------------------------------- GLOBAL DECLICK (for transport changes etc.) @@ -503,6 +527,8 @@ Route::process_output_buffers (BufferSet& bufs, /* set this to be true if the meter will already have been ::run() earlier */ bool const meter_already_run = metering_state() == MeteringInput; + framecnt_t latency = 0; + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if (meter_already_run && boost::dynamic_pointer_cast (*i)) { @@ -528,11 +554,120 @@ Route::process_output_buffers (BufferSet& bufs, do we catch route != active somewhere higher? */ - (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back()); + if (boost::dynamic_pointer_cast(*i) != 0) { + boost::dynamic_pointer_cast(*i)->set_delay_in(_signal_latency - latency); + } + + (*i)->run (bufs, start_frame - latency, end_frame - latency, nframes, *i != _processors.back()); bufs.set_count ((*i)->output_streams()); + + if ((*i)->active ()) { + latency += (*i)->signal_latency (); + } + } +} + +void +Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes, + boost::shared_ptr endpoint, + bool include_endpoint, bool for_export, bool for_freeze) +{ + /* If no processing is required, there's no need to go any further. */ + if (!endpoint && !include_endpoint) { + return; + } + + framecnt_t latency = bounce_get_latency(_amp, false, for_export, for_freeze); + _amp->set_gain_automation_buffer (_session.gain_automation_buffer ()); + _amp->setup_gain_automation (start - latency, start - latency + nframes, nframes); + + latency = 0; + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + + if (!include_endpoint && (*i) == endpoint) { + break; + } + + /* if we're not exporting, stop processing if we come across a routing processor. */ + if (!for_export && boost::dynamic_pointer_cast(*i)) { + break; + } + if (!for_export && for_freeze && (*i)->does_routing() && (*i)->active()) { + break; + } + + /* don't run any processors that does routing. + * oh, and don't bother with the peak meter either. + */ + if (!(*i)->does_routing() && !boost::dynamic_pointer_cast(*i)) { + (*i)->run (buffers, start - latency, start - latency + nframes, nframes, true); + buffers.set_count ((*i)->output_streams()); + latency += (*i)->signal_latency (); + } + + if ((*i) == endpoint) { + break; + } } } +framecnt_t +Route::bounce_get_latency (boost::shared_ptr endpoint, + bool include_endpoint, bool for_export, bool for_freeze) const +{ + framecnt_t latency = 0; + if (!endpoint && !include_endpoint) { + return latency; + } + + for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { + if (!include_endpoint && (*i) == endpoint) { + break; + } + if (!for_export && boost::dynamic_pointer_cast(*i)) { + break; + } + if (!for_export && for_freeze && (*i)->does_routing() && (*i)->active()) { + break; + } + if (!(*i)->does_routing() && !boost::dynamic_pointer_cast(*i)) { + latency += (*i)->signal_latency (); + } + if ((*i) == endpoint) { + break; + } + } + return latency; +} + +ChanCount +Route::bounce_get_output_streams (ChanCount &cc, boost::shared_ptr endpoint, + bool include_endpoint, bool for_export, bool for_freeze) const +{ + if (!endpoint && !include_endpoint) { + return cc; + } + + for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { + if (!include_endpoint && (*i) == endpoint) { + break; + } + if (!for_export && boost::dynamic_pointer_cast(*i)) { + break; + } + if (!for_export && for_freeze && (*i)->does_routing() && (*i)->active()) { + break; + } + if (!(*i)->does_routing() && !boost::dynamic_pointer_cast(*i)) { + cc = (*i)->output_streams(); + } + if ((*i) == endpoint) { + break; + } + } + return cc; +} + ChanCount Route::n_process_buffers () { @@ -544,6 +679,7 @@ Route::monitor_run (framepos_t start_frame, framepos_t end_frame, pframes_t nfra { assert (is_monitor()); BufferSet& bufs (_session.get_route_buffers (n_process_buffers())); + fill_buffers_with_input (bufs, _input, nframes); passthru (bufs, start_frame, end_frame, nframes, declick); } @@ -1329,7 +1465,7 @@ Route::clear_processors (Placement p) seen_amp = true; } - if ((*i) == _amp || (*i) == _meter || (*i) == _main_outs) { + if ((*i) == _amp || (*i) == _meter || (*i) == _main_outs || (*i) == _delayline) { /* you can't remove these */ @@ -1382,12 +1518,21 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream { // TODO once the export point can be configured properly, do something smarter here if (processor == _capturing_processor) { + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK); + if (need_process_lock) { + lx.acquire(); + } + _capturing_processor.reset(); + + if (need_process_lock) { + lx.release(); + } } /* these can never be removed */ - if (processor == _amp || processor == _meter || processor == _main_outs) { + if (processor == _amp || processor == _meter || processor == _main_outs || processor == _delayline) { return 0; } @@ -1402,7 +1547,12 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream if (need_process_lock) { lx.acquire(); } - Glib::Threads::RWLock::WriterLock lm (_processor_lock); + + /* Caller must hold process lock */ + assert (!AudioEngine::instance()->process_lock().trylock()); + + Glib::Threads::RWLock::WriterLock lm (_processor_lock); // XXX deadlock after export + ProcessorState pstate (this); ProcessorList::iterator i; @@ -1499,7 +1649,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* /* these can never be removed */ - if (processor == _amp || processor == _meter || processor == _main_outs) { + if (processor == _amp || processor == _meter || processor == _main_outs || processor == _delayline) { ++i; continue; } @@ -1568,63 +1718,6 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* return 0; } -#if 0 -/* currently unused (again) -- but will come in handy soon (again) - * once there is an option to link route + delivery panner settings - */ -void -Route::set_custom_panner_uri (std::string const panner_uri) -{ - if (_in_configure_processors) { - DEBUG_TRACE (DEBUG::Panning, string_compose (_("Route::set_custom_panner_uri '%1' -- called while in_configure_processors\n"), name())); - return; - } - - if (!_main_outs->panner_shell()->set_user_selected_panner_uri(panner_uri)) { - DEBUG_TRACE (DEBUG::Panning, string_compose (_("Route::set_custom_panner_uri '%1 '%2' -- no change needed\n"), name(), panner_uri)); - /* no change needed */ - return; - } - - DEBUG_TRACE (DEBUG::Panning, string_compose (_("Route::set_custom_panner_uri '%1 '%2' -- reconfigure I/O\n"), name(), panner_uri)); - - /* reconfigure I/O -- re-initialize panner modules */ - { - Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); - Glib::Threads::RWLock::WriterLock lm (_processor_lock); - - for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p) { - boost::shared_ptr dl; - boost::shared_ptr panner; - if ((dl = boost::dynamic_pointer_cast (*p)) == 0) { - continue; - } - if (!dl->panner_shell()) { - continue; - } - if (!(panner = dl->panner_shell()->panner())) { - continue; - } - /* _main_outs has already been set before the loop. - * Ignore the return status here. It need reconfiguration */ - if (dl->panner_shell() != _main_outs->panner_shell()) { - if (!dl->panner_shell()->set_user_selected_panner_uri(panner_uri)) { - continue; - } - } - - ChanCount in = panner->in(); - ChanCount out = panner->out(); - dl->panner_shell()->configure_io(in, out); - dl->panner_shell()->pannable()->set_panner(dl->panner_shell()->panner()); - } - } - - processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ - _session.set_dirty (); -} -#endif - void Route::reset_instrument_info () { @@ -1638,7 +1731,10 @@ Route::reset_instrument_info () int Route::configure_processors (ProcessorStreams* err) { +#ifndef PLATFORM_WINDOWS assert (!AudioEngine::instance()->process_lock().trylock()); +#endif + if (!_in_configure_processors) { Glib::Threads::RWLock::WriterLock lm (_processor_lock); return configure_processors_unlocked (err); @@ -1708,7 +1804,9 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err) int Route::configure_processors_unlocked (ProcessorStreams* err) { +#ifndef PLATFORM_WINDOWS assert (!AudioEngine::instance()->process_lock().trylock()); +#endif if (_in_configure_processors) { return 0; @@ -1940,6 +2038,10 @@ Route::state(bool full_state) node->add_child_nocopy (_mute_control->get_state ()); node->add_child_nocopy (_mute_master->get_state ()); + if (full_state) { + node->add_child_nocopy (Automatable::get_automation_xml_state ()); + } + XMLNode* remote_control_node = new XMLNode (X_("RemoteControl")); snprintf (buf, sizeof (buf), "%d", _remote_control_id); remote_control_node->add_property (X_("id"), buf); @@ -2210,6 +2312,9 @@ Route::set_state (const XMLNode& node, int version) } else if (child->name() == X_("MuteMaster")) { _mute_master->set_state (*child, version); + + } else if (child->name() == Automatable::xml_node_name) { + set_automation_xml_state (*child, Evoral::Parameter(NullAutomation)); } } @@ -2516,6 +2621,11 @@ Route::set_processor_state (const XMLNode& node) } else if (prop->value() == "meter") { _meter->set_state (**niter, Stateful::current_state_version); new_order.push_back (_meter); + } else if (prop->value() == "delay") { + if (_delayline) { + _delayline->set_state (**niter, Stateful::current_state_version); + new_order.push_back (_delayline); + } } else if (prop->value() == "main-outs") { _main_outs->set_state (**niter, Stateful::current_state_version); } else if (prop->value() == "intreturn") { @@ -2553,8 +2663,7 @@ Route::set_processor_state (const XMLNode& node) if (prop->value() == "intsend") { - boost::shared_ptr sendpan (new Pannable (_session)); - processor.reset (new InternalSend (_session, sendpan, _mute_master, boost::shared_ptr(), Delivery::Role (0))); + processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast(shared_from_this()), boost::shared_ptr(), Delivery::Aux, true)); } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" || prop->value() == "lv2" || @@ -2570,8 +2679,7 @@ Route::set_processor_state (const XMLNode& node) } else if (prop->value() == "send") { - boost::shared_ptr sendpan (new Pannable (_session)); - processor.reset (new Send (_session, sendpan, _mute_master)); + processor.reset (new Send (_session, _pannable, _mute_master, Delivery::Send, true)); } else { error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; @@ -2724,7 +2832,7 @@ Route::enable_monitor_send () /* make sure we have one */ if (!_monitor_send) { - _monitor_send.reset (new InternalSend (_session, _pannable, _mute_master, _session.monitor_out(), Delivery::Listen)); + _monitor_send.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast(shared_from_this()), _session.monitor_out(), Delivery::Listen)); _monitor_send->set_display_to_user (false); } @@ -2762,7 +2870,7 @@ Route::add_aux_send (boost::shared_ptr route, boost::shared_ptrprocess_lock ()); boost::shared_ptr sendpan (new Pannable (_session)); - listener.reset (new InternalSend (_session, sendpan, _mute_master, route, Delivery::Aux)); + listener.reset (new InternalSend (_session, sendpan, _mute_master, boost::dynamic_pointer_cast(shared_from_this()), route, Delivery::Aux)); } add_processor (listener, before); @@ -2849,7 +2957,7 @@ 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) { + for (FedBy::const_iterator f = fed_by.begin(); f != fed_by.end(); ++f) { boost::shared_ptr sr = f->r.lock(); if (sr && (sr.get() == this)) { @@ -3122,6 +3230,7 @@ Route::set_meter_point (MeterPoint p, bool force) bool meter_was_visible_to_user = _meter->display_to_user (); { + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); Glib::Threads::RWLock::WriterLock lm (_processor_lock); maybe_note_meter_position (); @@ -3207,12 +3316,16 @@ Route::listen_position_changed () boost::shared_ptr Route::add_export_point() { + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); if (!_capturing_processor) { + lm.release(); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lw (_processor_lock); _capturing_processor.reset (new CapturingProcessor (_session)); _capturing_processor->activate (); - configure_processors (0); + configure_processors_unlocked (0); } @@ -3223,15 +3336,24 @@ framecnt_t Route::update_signal_latency () { framecnt_t l = _output->user_latency(); + framecnt_t lamp = 0; + bool before_amp = true; for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if ((*i)->active ()) { l += (*i)->signal_latency (); } + if ((*i) == _amp) { + before_amp = false; + } + if (before_amp) { + lamp = l; + } } DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: internal signal latency = %2\n", _name, l)); + _signal_latency_at_amp_position = lamp; if (_signal_latency != l) { _signal_latency = l; signal_latency_changed (); /* EMIT SIGNAL */ @@ -3273,18 +3395,21 @@ Route::set_latency_compensation (framecnt_t longest_session_latency) } Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr r) - : AutomationControl (r->session(), Evoral::Parameter (SoloAutomation), - boost::shared_ptr(), name) + : AutomationControl (r->session(), + Evoral::Parameter (SoloAutomation), + ParameterDescriptor(Evoral::Parameter (SoloAutomation)), + boost::shared_ptr(), name) , _route (r) { boost::shared_ptr gl(new AutomationList(Evoral::Parameter(SoloAutomation))); + gl->set_interpolation(Evoral::ControlList::Discrete); set_list (gl); } void Route::SoloControllable::set_value (double val) { - bool bval = ((val >= 0.5f) ? true: false); + const bool bval = ((val >= 0.5) ? true : false); boost::shared_ptr rl (new RouteList); @@ -3318,39 +3443,64 @@ Route::SoloControllable::get_value () const } Route::MuteControllable::MuteControllable (std::string name, boost::shared_ptr r) - : AutomationControl (r->session(), Evoral::Parameter (MuteAutomation), - boost::shared_ptr(), name) + : AutomationControl (r->session(), + Evoral::Parameter (MuteAutomation), + ParameterDescriptor (Evoral::Parameter (MuteAutomation)), + boost::shared_ptr(), + name) , _route (r) { boost::shared_ptr gl(new AutomationList(Evoral::Parameter(MuteAutomation))); + gl->set_interpolation(Evoral::ControlList::Discrete); set_list (gl); } void -Route::MuteControllable::set_value (double val) +Route::MuteControllable::set_superficial_value(bool muted) { - bool bval = ((val >= 0.5f) ? true: false); + /* Note we can not use AutomationControl::set_value here since it will emit + Changed(), but the value will not be correct to the observer. */ - boost::shared_ptr rl (new RouteList); + bool to_list = _list && ((AutomationList*)_list.get())->automation_write(); + + Control::set_double (muted, _session.transport_frame(), to_list); +} + +void +Route::MuteControllable::set_value (double val) +{ + const bool bval = ((val >= 0.5) ? true : false); boost::shared_ptr r = _route.lock (); if (!r) { return; } - rl->push_back (r); - _session.set_mute (rl, bval); + if (_list && ((AutomationList*)_list.get())->automation_playback()) { + // Playing back automation, set route mute directly + r->set_mute (bval, this); + } else { + // Set from user, queue mute event + boost::shared_ptr rl (new RouteList); + rl->push_back (r); + _session.set_mute (rl, bval, Session::rt_cleanup); + } + + // Set superficial/automation value to drive controller (and possibly record) + set_superficial_value(bval); } double Route::MuteControllable::get_value () const { - boost::shared_ptr r = _route.lock (); - if (!r) { - return 0; + if (_list && ((AutomationList*)_list.get())->automation_playback()) { + // Playing back automation, get the value from the list + return AutomationControl::get_value(); } - return r->muted() ? 1.0f : 0.0f; + // Not playing back automation, get the actual route mute value + boost::shared_ptr r = _route.lock (); + return (r && r->muted()) ? 1.0 : 0.0; } void @@ -3460,14 +3610,14 @@ Route::save_as_template (const string& path, const string& name) bool Route::set_name (const string& str) { - bool ret; - string ioproc_name; - string name; + if (str == name()) { + return true; + } - name = Route::ensure_track_or_route_name (str, _session); + string name = Route::ensure_track_or_route_name (str, _session); SessionObject::set_name (name); - ret = (_input->set_name(name) && _output->set_name(name)); + bool ret = (_input->set_name(name) && _output->set_name(name)); if (ret) { /* rename the main outs. Leave other IO processors @@ -3592,6 +3742,10 @@ Route::denormal_protection () const void Route::set_active (bool yn, void* src) { + if (_session.transport_rolling()) { + return; + } + if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_route_active()) { _route_group->foreach_route (boost::bind (&Route::set_active, _1, yn, _route_group)); return; @@ -3609,7 +3763,7 @@ Route::set_active (bool yn, void* src) void Route::meter () { - Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK); + Glib::Threads::RWLock::ReaderLock rm (_processor_lock); assert (_meter); @@ -3664,7 +3818,7 @@ Route::get_control (const Evoral::Parameter& param) /* maybe one of our processors does or ... */ - Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK); + Glib::Threads::RWLock::ReaderLock rm (_processor_lock); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if ((c = boost::dynamic_pointer_cast((*i)->control (param))) != 0) { break; @@ -3942,7 +4096,7 @@ Route::setup_invisible_processors () ++amp; } - assert (amp != _processors.end ()); + assert (amp != new_processors.end ()); /* and the processor after the amp */ @@ -4034,6 +4188,12 @@ Route::setup_invisible_processors () } } +#if 0 // not used - just yet + if (!is_master() && !is_monitor() && !is_auditioner()) { + new_processors.push_front (_delayline); + } +#endif + /* MONITOR CONTROL */ if (_monitor_control && is_monitor ()) { @@ -4190,9 +4350,13 @@ Route::non_realtime_locate (framepos_t pos) _pannable->transport_located (pos); } + if (_delayline.get()) { + _delayline.get()->flush(); + } + { //Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); - Glib::Threads::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { (*i)->transport_located (pos);