From 13232d03f3e5f8a5d7d19392c26c27ce0327250c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 20 Feb 2011 00:55:32 +0000 Subject: [PATCH] Modify route _processor list set up so that the logic for placing `invisible' processors (e.g. internal returns etc.) is in one place. Add option to get pre-fade listen from before or after pre-fade processors (#3781). git-svn-id: svn://localhost/ardour2/branches/3.0@8903 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/editor.cc | 2 - gtk2_ardour/editor_routes.cc | 4 +- gtk2_ardour/gain_meter.cc | 4 +- gtk2_ardour/rc_option_editor.cc | 12 + gtk2_ardour/route_ui.cc | 12 +- libs/ardour/ardour/rc_configuration_vars.h | 1 + libs/ardour/ardour/route.h | 41 ++- libs/ardour/ardour/types.h | 9 + libs/ardour/enums.cc | 21 ++ libs/ardour/monitor_processor.cc | 5 +- libs/ardour/route.cc | 396 ++++++++++++--------- libs/ardour/session.cc | 30 +- libs/ardour/session_state.cc | 2 +- 13 files changed, 326 insertions(+), 213 deletions(-) diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index ad494aabec..801407e079 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -4870,8 +4870,6 @@ Editor::handle_new_route (RouteList& routes) RouteTimeAxisView *rtv; list new_views; - cerr << "Handle new route\n"; - for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { boost::shared_ptr route = (*x); diff --git a/gtk2_ardour/editor_routes.cc b/gtk2_ardour/editor_routes.cc index 8ea152ba54..1368979e58 100644 --- a/gtk2_ardour/editor_routes.cc +++ b/gtk2_ardour/editor_routes.cc @@ -336,7 +336,7 @@ EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string) boost::shared_ptr rl (new RouteList); rl->push_back (rtv->route()); if (Config->get_solo_control_is_listen_control()) { - _session->set_listen (rl, !rtv->route()->listening(), Session::rt_cleanup); + _session->set_listen (rl, !rtv->route()->listening_via_monitor(), Session::rt_cleanup); } else { _session->set_solo (rl, !rtv->route()->self_soloed(), Session::rt_cleanup); } @@ -929,7 +929,7 @@ EditorRoutes::key_press (GdkEventKey* ev) case 's': if (Config->get_solo_control_is_listen_control()) { - _session->set_listen (rl, !rl->front()->listening(), Session::rt_cleanup); + _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup); } else { _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup); } diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc index 77cdbfe82e..5c64396b1c 100644 --- a/gtk2_ardour/gain_meter.cc +++ b/gtk2_ardour/gain_meter.cc @@ -553,8 +553,8 @@ GainMeterBase::meter_press(GdkEventButton* ev) gint GainMeterBase::meter_release(GdkEventButton*) { - if(!ignore_toggle){ - if (wait_for_release){ + if (!ignore_toggle) { + if (wait_for_release) { wait_for_release = false; if (_route) { diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index 767e235536..fdd51a3441 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -1090,6 +1090,18 @@ RCOptionEditor::RCOptionEditor () mm->add (ExternalMonitoring, _("audio hardware")); add_option (_("Audio"), mm); + + ComboOption* pp = new ComboOption ( + "pfl-position", + _("PFL signals come from"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_pfl_position), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_pfl_position) + ); + + pp->add (PFLFromBeforeProcessors, _("before pre-fader processors")); + pp->add (PFLFromAfterProcessors, _("pre-fader but after pre-fader processors")); + + add_option (_("Audio"), pp); add_option (_("Audio"), new BoolOption ( diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index 385279ac30..6577926208 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -408,7 +408,7 @@ RouteUI::solo_press(GdkEventButton* ev) } if (Config->get_solo_control_is_listen_control()) { - _session->set_listen (_session->get_routes(), !_route->listening(), Session::rt_cleanup, true); + _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true); } else { _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true); } @@ -458,7 +458,7 @@ RouteUI::solo_press(GdkEventButton* ev) } if (Config->get_solo_control_is_listen_control()) { - _session->set_listen (_route->route_group()->route_list(), !_route->listening(), Session::rt_cleanup, true); + _session->set_listen (_route->route_group()->route_list(), !_route->listening_via_monitor(), Session::rt_cleanup, true); } else { _session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(), Session::rt_cleanup, true); } @@ -476,7 +476,7 @@ RouteUI::solo_press(GdkEventButton* ev) } if (Config->get_solo_control_is_listen_control()) { - _session->set_listen (rl, !_route->listening()); + _session->set_listen (rl, !_route->listening_via_monitor()); } else { _session->set_solo (rl, !_route->self_soloed()); } @@ -816,7 +816,7 @@ RouteUI::solo_visual_state (boost::shared_ptr r) if (Config->get_solo_control_is_listen_control()) { - if (r->listening()) { + if (r->listening_via_monitor()) { return 1; } else { return 0; @@ -844,7 +844,7 @@ RouteUI::solo_visual_state_with_isolate (boost::shared_ptr r) if (Config->get_solo_control_is_listen_control()) { - if (r->listening()) { + if (r->listening_via_monitor()) { return 1; } else { return 0; @@ -900,7 +900,7 @@ RouteUI::update_solo_display () if (Config->get_solo_control_is_listen_control()) { - if (solo_button->get_active() != (x = _route->listening())) { + if (solo_button->get_active() != (x = _route->listening_via_monitor())) { ++_i_am_the_modifier; solo_button->set_active(x); --_i_am_the_modifier; diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index 92647947a2..e1030bafa0 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -84,6 +84,7 @@ CONFIG_VARIABLE (bool, mute_affects_control_outs, "mute-affects-control-outs", t CONFIG_VARIABLE (bool, mute_affects_main_outs, "mute-affects-main-outs", true) CONFIG_VARIABLE (MonitorModel, monitoring_model, "monitoring-model", ExternalMonitoring) CONFIG_VARIABLE (ListenPosition, listen_position, "listen-position", AfterFaderListen) +CONFIG_VARIABLE (PFLPosition, pfl_position, "pfl-position", PFLFromAfterProcessors) CONFIG_VARIABLE (bool, use_monitor_bus, "use-monitor-bus", false) CONFIG_VARIABLE (bool, solo_control_is_listen_control, "solo-control-is-listen-control", false) diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index e17dc775d1..defcc2c5c2 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -155,7 +155,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, bool solo_safe() const; void set_listen (bool yn, void* src); - bool listening () const; + bool listening_via_monitor () const; void set_phase_invert (uint32_t, bool yn); void set_phase_invert (boost::dynamic_bitset<>); @@ -220,7 +220,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, void add_internal_return (); BufferSet* get_return_buffer () const; void release_return_buffer () const; - void put_monitor_send_at (Placement); + void listen_position_changed (); boost::shared_ptr add_export_point(/* Add some argument for placement later */); /** A record of the stream configuration at some point in the processor list. @@ -294,7 +294,8 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, PBD::Signal1 SelectedChanged; - int listen_via (boost::shared_ptr, Placement p, bool active, bool aux); + int listen_via_monitor (); + int listen_via (boost::shared_ptr, Placement p); void drop_listen (boost::shared_ptr); /** @@ -508,6 +509,40 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, void set_processor_positions (); void update_port_latencies (const PortSet& ports, const PortSet& feeders, bool playback, framecnt_t) const; + + void setup_invisible_processors (); + + boost::shared_ptr _capturing_processor; + + /** A handy class to keep processor state while we attempt a reconfiguration + * that may fail. + */ + class ProcessorState { + public: + ProcessorState (Route* r) + : _route (r) + , _processors (r->_processors) + , _processor_max_streams (r->processor_max_streams) + { } + + void restore () { + _route->_processors = _processors; + _route->processor_max_streams = _processor_max_streams; + } + + private: + /* this should perhaps be a shared_ptr, but ProcessorStates will + not hang around long enough for it to matter. + */ + Route* _route; + ProcessorList _processors; + ChanCount _processor_max_streams; + }; + + friend class ProcessorState; + + /* no copy construction */ + Route (Route const &); }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 744c06f552..b03ba6b232 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -346,6 +346,13 @@ namespace ARDOUR { ExternalMonitoring }; + enum PFLPosition { + /** PFL signals come from before pre-fader processors */ + PFLFromBeforeProcessors, + /** PFL signals come pre-fader but after pre-fader processors */ + PFLFromAfterProcessors + }; + enum DenormalModel { DenormalNone, DenormalFTZ, @@ -557,6 +564,7 @@ std::istream& operator>>(std::istream& o, ARDOUR::HeaderFormat& sf); std::istream& operator>>(std::istream& o, ARDOUR::AutoConnectOption& sf); std::istream& operator>>(std::istream& o, ARDOUR::EditMode& sf); std::istream& operator>>(std::istream& o, ARDOUR::MonitorModel& sf); +std::istream& operator>>(std::istream& o, ARDOUR::PFLPosition& sf); std::istream& operator>>(std::istream& o, ARDOUR::RemoteModel& sf); std::istream& operator>>(std::istream& o, ARDOUR::ListenPosition& sf); std::istream& operator>>(std::istream& o, ARDOUR::LayerModel& sf); @@ -576,6 +584,7 @@ std::ostream& operator<<(std::ostream& o, const ARDOUR::HeaderFormat& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::AutoConnectOption& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::EditMode& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::MonitorModel& sf); +std::ostream& operator<<(std::ostream& o, const ARDOUR::PFLPosition& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::RemoteModel& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::ListenPosition& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::LayerModel& sf); diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 976cd99f9f..5219b51458 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -65,6 +65,7 @@ setup_enum_writer () RegionPoint _RegionPoint; Placement _Placement; MonitorModel _MonitorModel; + PFLPosition _PFLPosition; RemoteModel _RemoteModel; DenormalModel _DenormalModel; CrossfadeModel _CrossfadeModel; @@ -219,6 +220,10 @@ setup_enum_writer () REGISTER_ENUM (ExternalMonitoring); REGISTER (_MonitorModel); + REGISTER_ENUM (PFLFromBeforeProcessors); + REGISTER_ENUM (PFLFromAfterProcessors); + REGISTER (_PFLPosition); + REGISTER_ENUM (DenormalNone); REGISTER_ENUM (DenormalFTZ); REGISTER_ENUM (DenormalDAZ); @@ -603,6 +608,7 @@ std::ostream& operator<<(std::ostream& o, const AutoConnectOption& var) std::string s = enum_2_string (var); return o << s; } + std::istream& operator>>(std::istream& o, MonitorModel& var) { std::string s; @@ -616,6 +622,21 @@ std::ostream& operator<<(std::ostream& o, const MonitorModel& var) std::string s = enum_2_string (var); return o << s; } + +std::istream& operator>>(std::istream& o, PFLPosition& var) +{ + std::string s; + o >> s; + var = (PFLPosition) string_2_enum (s, var); + return o; +} + +std::ostream& operator<<(std::ostream& o, const PFLPosition& var) +{ + std::string s = enum_2_string (var); + return o << s; +} + std::istream& operator>>(std::istream& o, RemoteModel& var) { std::string s; diff --git a/libs/ardour/monitor_processor.cc b/libs/ardour/monitor_processor.cc index 4f204031ac..be4431b98a 100644 --- a/libs/ardour/monitor_processor.cc +++ b/libs/ardour/monitor_processor.cc @@ -275,7 +275,7 @@ MonitorProcessor::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t / target_gain = 0.0; } } - + if (target_gain != _channels[chn]->current_gain || target_gain != 1.0f) { Amp::apply_gain (*b, nframes, _channels[chn]->current_gain, target_gain); @@ -334,7 +334,8 @@ MonitorProcessor::configure_io (ChanCount in, ChanCount out) bool MonitorProcessor::can_support_io_configuration (const ChanCount& in, ChanCount& out) const { - return in == out; + out = in; + return true; } void diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index a980b3f446..56fc090576 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -144,37 +144,27 @@ Route::init () _amp.reset (new Amp (_session)); add_processor (_amp, PostFader); - /* add standard processors: meter, main outs, monitor out */ + /* create standard processors: meter, main outs, monitor out; + they will be added to _processors by setup_invisible_processors () + */ _meter.reset (new PeakMeter (_session)); _meter->set_display_to_user (false); - - add_processor (_meter, PostFader); + _meter->activate (); _main_outs.reset (new Delivery (_session, _output, _pannable, _mute_master, _name, Delivery::Main)); - - add_processor (_main_outs, PostFader); + _main_outs->activate (); if (is_monitor()) { /* where we listen to tracks */ _intreturn.reset (new InternalReturn (_session)); - add_processor (_intreturn, PreFader); - - ProcessorList::iterator i; - - for (i = _processors.begin(); i != _processors.end(); ++i) { - if (*i == _intreturn) { - ++i; - break; - } - } + _intreturn->activate (); /* the thing that provides proper control over a control/monitor/listen bus (such as per-channel cut, dim, solo, invert, etc). - It always goes right after the internal return; */ _monitor_control.reset (new MonitorProcessor (_session)); - add_processor (_monitor_control, i); + _monitor_control->activate (); /* no panning on the monitor main outs */ @@ -191,6 +181,12 @@ Route::init () Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this))); + { + /* run a configure so that the invisible processors get set up */ + Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + configure_processors (0); + } + return 0; } @@ -505,7 +501,7 @@ Route::process_output_buffers (BufferSet& bufs, if (boost::dynamic_pointer_cast (*i)) { break; } - + if (bufs.count() != (*i)->input_streams()) { cerr << _name << " bufs = " << bufs.count() << " input for " << (*i)->name() << " = " << (*i)->input_streams() @@ -600,7 +596,7 @@ Route::set_listen (bool yn, void* src) } bool -Route::listening () const +Route::listening_via_monitor () const { if (_monitor_send) { return _monitor_send->active (); @@ -862,13 +858,14 @@ Route::add_processor (boost::shared_ptr processor, Placement placemen /** Add a processor to the route. - * @a iter must point to an iterator in _processors and the new - * processor will be inserted immediately before this location. Otherwise, - * @a position is used. + * @param iter an iterator in _processors; the new processor will be inserted immediately before this location. */ int Route::add_processor (boost::shared_ptr processor, ProcessorList::iterator iter, ProcessorStreams* err, bool activation_allowed) { + assert (processor != _meter); + assert (processor != _main_outs); + ChanCount old_pms = processor_max_streams; if (!_session.engine().connected() || !processor) { @@ -877,14 +874,15 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite { Glib::RWLock::WriterLock lm (_processor_lock); + ProcessorState pstate (this); boost::shared_ptr pi; boost::shared_ptr porti; ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), processor); - if (processor == _amp || processor == _meter || processor == _main_outs) { - // Ensure only one of these are in the list at any time + if (processor == _amp) { + // Ensure only one amp is in the list at any time if (loc != _processors.end()) { if (iter == loc) { // Already in place, do nothing return 0; @@ -911,9 +909,7 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); if (configure_processors_unlocked (err)) { - ProcessorList::iterator ploc = loc; - --ploc; - _processors.erase(ploc); + pstate.restore (); configure_processors_unlocked (0); // it worked before we tried to add it ... cerr << "configure failed\n"; return -1; @@ -929,15 +925,7 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite } - /* 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)) { + if (activation_allowed) { processor->activate (); } @@ -1033,8 +1021,8 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr if (before) { loc = find(_processors.begin(), _processors.end(), before); } else { - /* nothing specified - at end but before main outs */ - loc = find (_processors.begin(), _processors.end(), _main_outs); + /* nothing specified - at end */ + loc = _processors.end (); } ChanCount old_pms = processor_max_streams; @@ -1049,29 +1037,18 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr { Glib::RWLock::WriterLock lm (_processor_lock); - - ChanCount potential_max_streams = ChanCount::max (_input->n_ports(), _output->n_ports()); + ProcessorState pstate (this); for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) { - // Ensure meter only appears in the list once if (*i == _meter) { - ProcessorList::iterator m = find(_processors.begin(), _processors.end(), *i); - if (m != _processors.end()) { - _processors.erase(m); - } + continue; } boost::shared_ptr pi; if ((pi = boost::dynamic_pointer_cast(*i)) != 0) { pi->set_count (1); - - ChanCount m = max (pi->input_streams(), pi->output_streams()); - - if (m > potential_max_streams) { - potential_max_streams = m; - } } ProcessorList::iterator inserted = _processors.insert (loc, *i); @@ -1083,7 +1060,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr { Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); if (configure_processors_unlocked (err)) { - _processors.erase (inserted); + pstate.restore (); configure_processors_unlocked (0); // it worked before we tried to add it ... return -1; } @@ -1327,6 +1304,8 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream { Glib::RWLock::WriterLock lm (_processor_lock); + ProcessorState pstate (this); + ProcessorList::iterator i; bool removed = false; @@ -1373,8 +1352,7 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); if (configure_processors_unlocked (err)) { - /* get back to where we where */ - _processors.insert (i, processor); + pstate.restore (); /* we know this will work, because it worked before :) */ configure_processors_unlocked (0); return -1; @@ -1415,11 +1393,11 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* { Glib::RWLock::WriterLock lm (_processor_lock); + ProcessorState pstate (this); + ProcessorList::iterator i; boost::shared_ptr processor; - ProcessorList as_we_were = _processors; - for (i = _processors.begin(); i != _processors.end(); ) { processor = *i; @@ -1464,8 +1442,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); if (configure_processors_unlocked (err)) { - /* get back to where we where */ - _processors = as_we_were; + pstate.restore (); /* we know this will work, because it worked before :) */ configure_processors_unlocked (0); return -1; @@ -1508,6 +1485,7 @@ Route::configure_processors (ProcessorStreams* err) Glib::RWLock::WriterLock lm (_processor_lock); return configure_processors_unlocked (err); } + return 0; } @@ -1577,6 +1555,9 @@ Route::configure_processors_unlocked (ProcessorStreams* err) return 0; } + /* put invisible processors where they should be */ + setup_invisible_processors (); + _in_configure_processors = true; list > configuration = try_configure_processors_unlocked (input_streams (), err); @@ -1706,10 +1687,10 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err { Glib::RWLock::WriterLock lm (_processor_lock); - ChanCount old_pms = processor_max_streams; + ProcessorState pstate (this); + ProcessorList::iterator oiter; ProcessorList::const_iterator niter; - ProcessorList as_it_was_before = _processors; ProcessorList as_it_will_be; oiter = _processors.begin(); @@ -1767,8 +1748,7 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); if (configure_processors_unlocked (err)) { - _processors = as_it_was_before; - processor_max_streams = old_pms; + pstate.restore (); return -1; } } @@ -2348,24 +2328,20 @@ Route::set_processor_state (const XMLNode& node) 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; @@ -2412,7 +2388,11 @@ Route::set_processor_state (const XMLNode& node) /* This processor could not be configured. Turn it into a UnknownProcessor */ processor.reset (new UnknownProcessor (_session, **niter)); } - + + /* it doesn't matter if invisible processors are added here, as they + will be sorted out by setup_invisible_processors () shortly. + */ + new_order.push_back (processor); must_configure = true; } @@ -2516,78 +2496,58 @@ Route::release_return_buffer () const } } +/** Add a monitor send, if we don't already have one */ int -Route::listen_via (boost::shared_ptr route, Placement placement, bool /*active*/, bool aux) +Route::listen_via_monitor () { - vector ports; - vector::const_iterator i; + /* master never sends to control outs */ + assert (!is_master ()); + + /* make sure we have one */ + if (!_monitor_send) { + _monitor_send.reset (new InternalSend (_session, _pannable, _mute_master, _session.monitor_out(), Delivery::Listen)); + _monitor_send->activate (); + _monitor_send->set_display_to_user (false); + } + + /* set it up */ + Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + configure_processors (0); + return 0; +} + +/** Add an internal send to a route. + * @param route route to send to. + * @param placement placement for the send. + */ +int +Route::listen_via (boost::shared_ptr route, Placement placement) +{ + assert (route != _session.monitor_out ()); + { Glib::RWLock::ReaderLock rm (_processor_lock); for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ++x) { - boost::shared_ptr d = boost::dynamic_pointer_cast(*x); + boost::shared_ptr d = boost::dynamic_pointer_cast (*x); if (d && d->target_route() == route) { - - /* if the target is the control outs, then make sure - we take note of which i-send is doing that. - */ - - if (route == _session.monitor_out()) { - _monitor_send = boost::dynamic_pointer_cast(d); - } - /* already listening via the specified IO: do nothing */ - return 0; } } } - boost::shared_ptr listener; - try { - - if (is_master()) { - - if (route == _session.monitor_out()) { - /* master never sends to control outs */ - return 0; - } else { - listener.reset (new InternalSend (_session, _pannable, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen))); - } - - } else { - listener.reset (new InternalSend (_session, _pannable, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen))); - } + boost::shared_ptr listener (new InternalSend (_session, _pannable, _mute_master, route, Delivery::Aux)); + add_processor (listener, placement); } catch (failed_constructor& err) { return -1; } - if (route == _session.monitor_out()) { - _monitor_send = listener; - } - - - if (aux) { - - add_processor (listener, placement); - - } else { - - if (placement == PostFader) { - /* put it *really* at the end, not just after the panner (main outs) - */ - add_processor (listener, _processors.end()); - } else { - add_processor (listener, PreFader); - } - - } - return 0; } @@ -2971,29 +2931,21 @@ Route::set_meter_point (MeterPoint p, bool force) return; } + _meter_point = p; + bool meter_was_visible_to_user = _meter->display_to_user (); { Glib::RWLock::WriterLock lm (_processor_lock); - if (p != MeterCustom) { - // Move meter in the processors list to reflect the new position - ProcessorList::iterator loc = find (_processors.begin(), _processors.end(), _meter); - _processors.erase(loc); - switch (p) { - case MeterInput: - loc = _processors.begin(); - break; - case MeterPreFader: - loc = find (_processors.begin(), _processors.end(), _amp); - break; - case MeterPostFader: - loc = _processors.end(); - break; - default: - break; - } + if (_meter_point != MeterCustom) { + + _meter->set_display_to_user (false); + setup_invisible_processors (); + + ProcessorList::iterator loc = find (_processors.begin(), _processors.end(), _meter); + ChanCount m_in; if (loc == _processors.begin()) { @@ -3006,16 +2958,12 @@ Route::set_meter_point (MeterPoint p, bool force) _meter->reflect_inputs (m_in); - _processors.insert (loc, _meter); - /* we do not need to reconfigure the processors, because the meter (a) is always ready to handle processor_max_streams (b) is always an N-in/N-out processor, and thus moving it doesn't require any changes to the other processors. */ - _meter->set_display_to_user (false); - } else { // just make it visible and let the user move it @@ -3024,7 +2972,6 @@ Route::set_meter_point (MeterPoint p, bool force) } } - _meter_point = p; meter_change (); /* EMIT SIGNAL */ bool const meter_visibly_changed = (_meter->display_to_user() != meter_was_visible_to_user); @@ -3033,37 +2980,17 @@ Route::set_meter_point (MeterPoint p, bool force) } void -Route::put_monitor_send_at (Placement p) +Route::listen_position_changed () { - if (!_monitor_send) { - return; - } - { Glib::RWLock::WriterLock lm (_processor_lock); - ProcessorList as_it_was (_processors); - ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), _monitor_send); - _processors.erase(loc); - - switch (p) { - case PreFader: - loc = find(_processors.begin(), _processors.end(), _amp); - if (loc != _processors.begin()) { - --loc; - } - break; - case PostFader: - loc = _processors.end(); - break; - } - - _processors.insert (loc, _monitor_send); + ProcessorState pstate (this); { Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); if (configure_processors_unlocked (0)) { - _processors = as_it_was; + pstate.restore (); configure_processors_unlocked (0); // it worked before we tried to add it ... return; } @@ -3077,16 +3004,19 @@ Route::put_monitor_send_at (Placement p) boost::shared_ptr Route::add_export_point() { - // Check if it exists already - boost::shared_ptr processor; - if ((processor = boost::dynamic_pointer_cast (*_processors.begin()))) { - return processor; - } + if (!_capturing_processor) { + + _capturing_processor.reset (new CapturingProcessor (_session)); + _capturing_processor->activate (); - // ...else add it - processor.reset (new CapturingProcessor (_session)); - add_processor (processor, _processors.begin()); - return processor; + { + Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + configure_processors (0); + } + + } + + return _capturing_processor; } framecnt_t @@ -3196,7 +3126,7 @@ double Route::SoloControllable::get_value (void) const { if (Config->get_solo_control_is_listen_control()) { - return route.listening() ? 1.0f : 0.0f; + return route.listening_via_monitor() ? 1.0f : 0.0f; } else { return route.self_soloed() ? 1.0f : 0.0f; } @@ -3699,3 +3629,125 @@ Route::update_port_latencies (const PortSet& operands, const PortSet& feeders, b } #endif } + + +/** Put the invisible processors in the right place in _processors. + * Must be called with a writer lock on _processor_lock held. + */ +void +Route::setup_invisible_processors () +{ +#ifdef NDEBUG + Glib::RWLock::WriterLock lm (_processor_lock, Glib::TryLock); + assert (!lm.locked ()); +#endif + + /* we'll build this new list here and then use it */ + + ProcessorList new_processors; + + /* find visible processors */ + + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + if ((*i)->display_to_user ()) { + new_processors.push_back (*i); + } + } + + /* find the amp */ + + ProcessorList::iterator amp = new_processors.begin (); + while (amp != new_processors.end() && boost::dynamic_pointer_cast (*amp) == 0) { + ++amp; + } + + assert (amp != _processors.end ()); + + /* and the processor after the amp */ + + ProcessorList::iterator after_amp = amp; + ++after_amp; + + /* METER */ + + if (_meter) { + switch (_meter_point) { + case MeterInput: + assert (!_meter->display_to_user ()); + new_processors.push_front (_meter); + break; + case MeterPreFader: + assert (!_meter->display_to_user ()); + new_processors.insert (amp, _meter); + break; + case MeterPostFader: + assert (!_meter->display_to_user ()); + new_processors.insert (after_amp, _meter); + break; + case MeterCustom: + /* the meter is visible, so we don't touch it here */ + break; + } + } + + + /* MAIN OUTS */ + + if (_main_outs) { + assert (!_main_outs->display_to_user ()); + new_processors.push_back (_main_outs); + } + + /* MONITOR SEND */ + + if (_monitor_send && !is_monitor ()) { + assert (!_monitor_send->display_to_user ()); + switch (Config->get_listen_position ()) { + case PreFaderListen: + switch (Config->get_pfl_position ()) { + case PFLFromBeforeProcessors: + new_processors.push_front (_monitor_send); + break; + case PFLFromAfterProcessors: + new_processors.insert (amp, _monitor_send); + break; + } + break; + case AfterFaderListen: + new_processors.insert (after_amp, _monitor_send); + break; + } + } + + /* MONITOR CONTROL */ + + if (_monitor_control && is_monitor ()) { + assert (!_monitor_control->display_to_user ()); + new_processors.push_front (_monitor_control); + } + + /* INTERNAL RETURN */ + + /* doing this here means that any monitor control will come just after + the return. + */ + + if (_intreturn) { + assert (!_intreturn->display_to_user ()); + new_processors.push_front (_intreturn); + } + + /* EXPORT PROCESSOR */ + + if (_capturing_processor) { + assert (!_capturing_processor->display_to_user ()); + new_processors.push_front (_capturing_processor); + } + + _processors = new_processors; + + DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: setup_invisible_processors\n", _name)); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1\n", (*i)->name ())); + } +} diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 39f6fc4ff7..e09513b07d 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -727,10 +727,8 @@ Session::hookup_io () /* relax */ } else { - - (*x)->listen_via (_monitor_out, - (Config->get_listen_position() == AfterFaderListen ? PostFader : PreFader), - false, false); + + (*x)->listen_via_monitor (); } } } @@ -2000,9 +1998,7 @@ Session::add_routes (RouteList& new_routes, bool save) } else if ((*x)->is_master()) { /* relax */ } else { - (*x)->listen_via (_monitor_out, - (Config->get_listen_position() == AfterFaderListen ? PostFader : PreFader), - false, false); + (*x)->listen_via_monitor (); } } @@ -2091,7 +2087,7 @@ Session::add_internal_sends (boost::shared_ptr dest, Placement p, boost:: continue; } - (*i)->listen_via (dest, p, true, true); + (*i)->listen_via (dest, p); } graph_reordered (); @@ -2207,7 +2203,7 @@ Session::route_listen_changed (void* /*src*/, boost::weak_ptr wpr) return; } - if (route->listening()) { + if (route->listening_via_monitor ()) { if (Config->get_exclusive_solo()) { /* new listen: disable all other listen */ @@ -2363,7 +2359,7 @@ Session::update_route_solo_state (boost::shared_ptr r) something_soloed = true; } - if (!(*i)->is_hidden() && (*i)->listening()) { + if (!(*i)->is_hidden() && (*i)->listening_via_monitor()) { if (Config->get_solo_control_is_listen_control()) { listeners++; } else { @@ -3892,22 +3888,10 @@ Session::update_have_rec_enabled_track () void Session::listen_position_changed () { - Placement p; - - switch (Config->get_listen_position()) { - case AfterFaderListen: - p = PostFader; - break; - - case PreFaderListen: - p = PreFader; - break; - } - boost::shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - (*i)->put_monitor_send_at (p); + (*i)->listen_position_changed (); } } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index b925e9416e..a8e8abf804 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -3476,7 +3476,7 @@ Session::config_changed (std::string p, bool ours) } } else if (p == "solo-mute-override") { // catch_up_on_solo_mute_override (); - } else if (p == "listen-position") { + } else if (p == "listen-position" || p == "pfl-position") { listen_position_changed (); } else if (p == "solo-control-is-listen-control") { solo_control_mode_changed ();