diff options
-rw-r--r-- | gtk2_ardour/ardour_button.cc | 1 | ||||
-rw-r--r-- | gtk2_ardour/mixer_ui.cc | 40 | ||||
-rw-r--r-- | gtk2_ardour/mixer_ui.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/monitor_section.cc | 4 | ||||
-rw-r--r-- | gtk2_ardour/session_option_editor.cc | 31 | ||||
-rw-r--r-- | gtk2_ardour/session_option_editor.h | 3 | ||||
-rw-r--r-- | libs/ardour/ardour/route.h | 13 | ||||
-rw-r--r-- | libs/ardour/ardour/session.h | 10 | ||||
-rw-r--r-- | libs/ardour/internal_return.cc | 8 | ||||
-rw-r--r-- | libs/ardour/io.cc | 1 | ||||
-rw-r--r-- | libs/ardour/route.cc | 96 | ||||
-rw-r--r-- | libs/ardour/session.cc | 340 | ||||
-rw-r--r-- | libs/ardour/session_click.cc | 1 | ||||
-rw-r--r-- | libs/ardour/session_state.cc | 25 | ||||
-rw-r--r-- | libs/ardour/session_transport.cc | 4 | ||||
-rw-r--r-- | libs/ardour/utils.cc | 8 |
16 files changed, 389 insertions, 198 deletions
diff --git a/gtk2_ardour/ardour_button.cc b/gtk2_ardour/ardour_button.cc index 4689b912f3..55e94a996e 100644 --- a/gtk2_ardour/ardour_button.cc +++ b/gtk2_ardour/ardour_button.cc @@ -468,7 +468,6 @@ ArdourButton::on_button_release_event (GdkEventButton *ev) if (_act_on_release) { if (_action) { - Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (_action); _action->activate (); return true; } diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc index 474cef2395..053f8eb595 100644 --- a/gtk2_ardour/mixer_ui.cc +++ b/gtk2_ardour/mixer_ui.cc @@ -250,6 +250,9 @@ Mixer_UI::Mixer_UI () Mixer_UI::~Mixer_UI () { + if (_monitor_section) { + delete _monitor_section; + } } void @@ -323,19 +326,21 @@ Mixer_UI::add_strip (RouteList& routes) } if (route->is_monitor()) { + if (!_monitor_section) { _monitor_section = new MonitorSection (_session); - out_packer.pack_end (_monitor_section->tearoff(), false, false); - } else { - _monitor_section->set_session (_session); - } + + XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section")); + if (mnode) { + _monitor_section->tearoff().set_state (*mnode); + } + } + out_packer.pack_end (_monitor_section->tearoff(), false, false); + _monitor_section->set_session (_session); _monitor_section->tearoff().show_all (); - XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section")); - if (mnode) { - _monitor_section->tearoff().set_state (*mnode); - } + route->DropReferences.connect (*this, invalidator(*this), ui_bind (&Mixer_UI::monitor_section_going_away, this), gui_context()); /* no regular strip shown for control out */ @@ -384,25 +389,23 @@ Mixer_UI::remove_strip (MixerStrip* strip) return; } - ENSURE_GUI_THREAD (*this, &Mixer_UI::remove_strip, strip); - TreeModel::Children rows = track_model->children(); TreeModel::Children::iterator ri; list<MixerStrip *>::iterator i; - + if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) { strips.erase (i); } - + strip_redisplay_does_not_sync_order_keys = true; - + for (ri = rows.begin(); ri != rows.end(); ++ri) { if ((*ri)[track_columns.strip] == strip) { track_model->erase (ri); break; } } - + strip_redisplay_does_not_sync_order_keys = false; } @@ -1850,3 +1853,12 @@ Mixer_UI::set_route_targets_for_operation () _route_targets.insert (ms); } } + +void +Mixer_UI::monitor_section_going_away () +{ + if (_monitor_section) { + out_packer.remove (_monitor_section->tearoff()); + _monitor_section->set_session (0); + } +} diff --git a/gtk2_ardour/mixer_ui.h b/gtk2_ardour/mixer_ui.h index 5a3b746457..febc62b8dd 100644 --- a/gtk2_ardour/mixer_ui.h +++ b/gtk2_ardour/mixer_ui.h @@ -275,6 +275,8 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR void follow_editor_selection (); bool _following_editor_selection; + + void monitor_section_going_away (); }; #endif /* __ardour_mixer_ui_h__ */ diff --git a/gtk2_ardour/monitor_section.cc b/gtk2_ardour/monitor_section.cc index 7de31e7d41..11d6b6925c 100644 --- a/gtk2_ardour/monitor_section.cc +++ b/gtk2_ardour/monitor_section.cc @@ -214,7 +214,7 @@ MonitorSection::MonitorSection (Session* s) act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all")); if (act) { cut_all_button.set_related_action (act); - } + } dim_all_button.set_text (_("dim")); dim_all_button.set_name ("monitor section dim"); @@ -549,7 +549,7 @@ MonitorSection::cut_all () if (act) { Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act); _monitor->set_cut_all (tact->get_active()); - } + } } void diff --git a/gtk2_ardour/session_option_editor.cc b/gtk2_ardour/session_option_editor.cc index dc72e6a045..e5cd7780f1 100644 --- a/gtk2_ardour/session_option_editor.cc +++ b/gtk2_ardour/session_option_editor.cc @@ -260,6 +260,13 @@ SessionOptionEditor::SessionOptionEditor (Session* s) sigc::mem_fun (*_session_config, &SessionConfiguration::set_auto_input) )); + add_option (_("Monitoring"), new BoolOption ( + "have-monitor-section", + _("Use monitor section in this session"), + sigc::mem_fun (*this, &SessionOptionEditor::get_use_monitor_section), + sigc::mem_fun (*this, &SessionOptionEditor::set_use_monitor_section) + )); + /* Misc */ add_option (_("Misc"), new OptionEditorHeading (_("MIDI Options"))); @@ -341,3 +348,27 @@ SessionOptionEditor::parameter_changed (std::string const & p) _sync_source->set_sensitive (!_session->config.get_external_sync ()); } } + +/* the presence of absence of a monitor section is not really a regular session + * property so we provide these two functions to act as setter/getter slots + */ + +bool +SessionOptionEditor::set_use_monitor_section (bool yn) +{ + bool had_monitor_section = _session->monitor_out(); + + if (yn) { + _session->add_monitor_section (); + } else { + _session->remove_monitor_section (); + } + + return had_monitor_section != yn; +} + +bool +SessionOptionEditor::get_use_monitor_section () +{ + return _session->monitor_out() != 0; +} diff --git a/gtk2_ardour/session_option_editor.h b/gtk2_ardour/session_option_editor.h index 2563f4153d..55d49a1e3a 100644 --- a/gtk2_ardour/session_option_editor.h +++ b/gtk2_ardour/session_option_editor.h @@ -35,4 +35,7 @@ private: ARDOUR::SessionConfiguration* _session_config; ComboOption<ARDOUR::SyncSource>* _sync_source; + + bool set_use_monitor_section (bool); + bool get_use_monitor_section (); }; diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 3fab63bb9b..e41682dd8e 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -162,6 +162,8 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, void set_listen (bool yn, void* src); bool listening_via_monitor () const; + void enable_monitor_send (); + void disable_monitor_send (); void set_phase_invert (uint32_t, bool yn); void set_phase_invert (boost::dynamic_bitset<>); @@ -242,7 +244,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, int add_processor_by_index (boost::shared_ptr<Processor>, int, ProcessorStreams* err = 0, bool activation_allowed = true); int add_processor (boost::shared_ptr<Processor>, ProcessorList::iterator iter, ProcessorStreams* err = 0, bool activation_allowed = true); int add_processors (const ProcessorList&, boost::shared_ptr<Processor> before, ProcessorStreams* err = 0); - int remove_processor (boost::shared_ptr<Processor>, ProcessorStreams* err = 0); + int remove_processor (boost::shared_ptr<Processor>, ProcessorStreams* err = 0, bool need_process_lock = true); int remove_processors (const ProcessorList&, ProcessorStreams* err = 0); int reorder_processors (const ProcessorList& new_order, ProcessorStreams* err = 0); void disable_processors (Placement); @@ -397,6 +399,15 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, void automation_snapshot (framepos_t now, bool force=false); void protect_automation (); + enum { + /* These numbers are taken from MIDI Machine Control, + which can only control up to 317 tracks without + doing sysex segmentation. + */ + MasterBusRemoteControlID = 318, + MonitorBusRemoteControlID = 319, + }; + void set_remote_control_id (uint32_t id, bool notify_class_listeners = true); uint32_t remote_control_id () const; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index ba1731bcda..fab442f07a 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -628,7 +628,10 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi PBD::Signal0<void> SoloChanged; PBD::Signal0<void> IsolatedChanged; - /* control/master out */ + /* monitor/master out */ + + void add_monitor_section (); + void remove_monitor_section (); boost::shared_ptr<Route> monitor_out() const { return _monitor_out; } boost::shared_ptr<Route> master_out() const { return _master_out; } @@ -1406,6 +1409,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi boost::shared_ptr<Route> _master_out; boost::shared_ptr<Route> _monitor_out; + void auto_connect_master_bus (); + /* Windows VST support */ long _windows_vst_callback ( @@ -1505,6 +1510,9 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi and solo/mute computations. */ GraphEdges _current_route_graph; + + uint32_t next_control_id () const; + bool ignore_route_processor_changes; }; } // namespace ARDOUR diff --git a/libs/ardour/internal_return.cc b/libs/ardour/internal_return.cc index 19f677f368..3c75c7957d 100644 --- a/libs/ardour/internal_return.cc +++ b/libs/ardour/internal_return.cc @@ -57,14 +57,18 @@ InternalReturn::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*e void InternalReturn::add_send (InternalSend* send) { - Glib::Mutex::Lock lm (_session.engine().process_lock()); + /* caller must hold process lock */ + assert (!AudioEngine::instance()->process_lock().trylock()); + _sends.push_back (send); } void InternalReturn::remove_send (InternalSend* send) { - Glib::Mutex::Lock lm (_session.engine().process_lock()); + /* caller must hold process lock */ + assert (!AudioEngine::instance()->process_lock().trylock()); + _sends.remove (send); } diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index aac2adf784..2397c7ee06 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -1252,6 +1252,7 @@ IO::disable_connecting () int IO::enable_connecting () { + Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock()); connecting_legal = true; boost::optional<int> r = ConnectingLegal (); return r.get_value_or (0); diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 00507627b5..de2e801d31 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -108,6 +108,13 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) { processor_max_streams.reset(); order_keys[N_("signal")] = order_key_cnt++; + + if (is_master()) { + set_remote_control_id (MasterBusRemoteControlID); + } else if (is_monitor()) { + set_remote_control_id (MonitorBusRemoteControlID); + } + } int @@ -207,6 +214,26 @@ Route::~Route () void Route::set_remote_control_id (uint32_t id, bool notify_class_listeners) { + /* force IDs for master/monitor busses and prevent + any other route from accidentally getting these IDs + (i.e. legacy sessions) + */ + + if (is_master() && id != MasterBusRemoteControlID) { + id = MasterBusRemoteControlID; + } + + if (is_monitor() && id != MonitorBusRemoteControlID) { + id = MonitorBusRemoteControlID; + } + + /* don't allow it to collide */ + + if (!is_master () && !is_monitor() && + (id == MasterBusRemoteControlID || id == MonitorBusRemoteControlID)) { + id += MonitorBusRemoteControlID; + } + if (id != _remote_control_id) { _remote_control_id = id; RemoteControlIDChanged (); @@ -1330,7 +1357,7 @@ Route::clear_processors (Placement p) } int -Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err) +Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err, bool need_process_lock) { /* these can never be removed */ @@ -1388,9 +1415,9 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream if (!removed) { /* what? */ return 1; - } + } - { + if (need_process_lock) { Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); if (configure_processors_unlocked (err)) { @@ -1399,6 +1426,13 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream configure_processors_unlocked (0); return -1; } + } else { + if (configure_processors_unlocked (err)) { + pstate.restore (); + /* we know this will work, because it worked before :) */ + configure_processors_unlocked (0); + return -1; + } } _have_internal_generator = false; @@ -2542,11 +2576,13 @@ Route::remove_send_from_internal_return (InternalSend* send) } } -/** Add a monitor send (if we don't already have one) but don't activate it */ -int -Route::listen_via_monitor () +void +Route::enable_monitor_send () { - /* master never sends to control outs */ + /* Caller must hold process lock */ + assert (!AudioEngine::instance()->process_lock().trylock()); + + /* master never sends to monitor section via the normal mechanism */ assert (!is_master ()); /* make sure we have one */ @@ -2556,10 +2592,7 @@ Route::listen_via_monitor () } /* set it up */ - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); configure_processors (0); - - return 0; } /** Add an internal send to a route. @@ -2602,31 +2635,34 @@ Route::drop_listen (boost::shared_ptr<Route> route) ProcessorStreams err; ProcessorList::iterator tmp; - Glib::RWLock::ReaderLock rl(_processor_lock); - rl.acquire (); - - again: - for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ) { - - boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x); - - if (d && d->target_route() == route) { - rl.release (); - remove_processor (*x, &err); - rl.acquire (); + { + Glib::RWLock::ReaderLock rl(_processor_lock); - /* list could have been demolished while we dropped the lock - so start over. - */ + /* have to do this early because otherwise processor reconfig + * will put _monitor_send back in the list + */ - goto again; + if (route == _session.monitor_out()) { + _monitor_send.reset (); } - } - rl.release (); + again: + for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ++x) { + + boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x); + + if (d && d->target_route() == route) { + rl.release (); + remove_processor (*x, &err, false); + rl.acquire (); - if (route == _session.monitor_out()) { - _monitor_send.reset (); + /* list could have been demolished while we dropped the lock + so start over. + */ + + goto again; + } + } } } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 26b3d47b7e..ef0a6c2a48 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -45,6 +45,8 @@ #include "pbd/file_utils.h" #include "pbd/convert.h" #include "pbd/strsplit.h" +#include "pbd/strsplit.h" +#include "pbd/unwind.h" #include "ardour/amp.h" #include "ardour/analyser.h" @@ -539,105 +541,207 @@ Session::when_engine_running () hookup_io (); if (_is_new && !no_auto_connect()) { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock()); + auto_connect_master_bus (); + } - /* don't connect the master bus outputs if there is a monitor bus */ + _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty)); - if (_master_out && Config->get_auto_connect_standard_busses() && !_monitor_out) { + /* update latencies */ - /* if requested auto-connect the outputs to the first N physical ports. - */ + initialize_latencies (); - uint32_t limit = _master_out->n_outputs().n_total(); + /* hook us up to the engine */ - for (uint32_t n = 0; n < limit; ++n) { - boost::shared_ptr<Port> p = _master_out->output()->nth (n); - string connect_to; - if (outputs[p->type()].size() > n) { - connect_to = outputs[p->type()][n]; - } + BootMessage (_("Connect to engine")); + _engine.set_session (this); +} - if (!connect_to.empty() && p->connected_to (connect_to) == false) { - if (_master_out->output()->connect (p, connect_to, this)) { - error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to) - << endmsg; - break; - } - } +void +Session::auto_connect_master_bus () +{ + if (!_master_out || !Config->get_auto_connect_standard_busses() || _monitor_out) { + return; + } + + /* if requested auto-connect the outputs to the first N physical ports. + */ + + uint32_t limit = _master_out->n_outputs().n_total(); + vector<string> outputs[DataType::num_types]; + + for (uint32_t i = 0; i < DataType::num_types; ++i) { + _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]); + } + + for (uint32_t n = 0; n < limit; ++n) { + boost::shared_ptr<Port> p = _master_out->output()->nth (n); + string connect_to; + if (outputs[p->type()].size() > n) { + connect_to = outputs[p->type()][n]; + } + + if (!connect_to.empty() && p->connected_to (connect_to) == false) { + if (_master_out->output()->connect (p, connect_to, this)) { + error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to) + << endmsg; + break; } } + } +} - if (_monitor_out) { +void +Session::remove_monitor_section () +{ + if (!_monitor_out) { + return; + } - /* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else - are undefined, at best. - */ + /* force reversion to Solo-In-Pace */ + Config->set_solo_control_is_listen_control (false); - /* control out listens to master bus (but ignores it - under some conditions) - */ + { + /* Hold process lock while doing this so that we don't hear bits and + * pieces of audio as we work on each route. + */ + + Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + + /* Connect tracks to monitor section. Note that in an + existing session, the internal sends will already exist, but we want the + routes to notice that they connect to the control out specifically. + */ + + + boost::shared_ptr<RouteList> r = routes.reader (); + PBD::Unwinder<bool> uw (ignore_route_processor_changes, true); + + for (RouteList::iterator x = r->begin(); x != r->end(); ++x) { + + if ((*x)->is_monitor()) { + /* relax */ + } else if ((*x)->is_master()) { + /* relax */ + } else { + (*x)->drop_listen (_monitor_out); + } + } + } - uint32_t limit = _monitor_out->n_inputs().n_audio(); + remove_route (_monitor_out); + auto_connect_master_bus (); +} - if (_master_out) { - for (uint32_t n = 0; n < limit; ++n) { - boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n); - boost::shared_ptr<AudioPort> o = _master_out->output()->ports().nth_audio_port (n); +void +Session::add_monitor_section () +{ + RouteList rl; - if (o) { - string connect_to = o->name(); - if (_monitor_out->input()->connect (p, connect_to, this)) { - error << string_compose (_("cannot connect control input %1 to %2"), n, connect_to) - << endmsg; - break; - } - } - } - } + if (_monitor_out || !_master_out) { + return; + } - /* if control out is not connected, connect control out to physical outs - */ + boost::shared_ptr<Route> r (new Route (*this, _("monitor"), Route::MonitorOut, DataType::AUDIO)); - if (!_monitor_out->output()->connected ()) { + if (r->init ()) { + return; + } - if (!Config->get_monitor_bus_preferred_bundle().empty()) { +#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS + // boost_debug_shared_ptr_mark_interesting (r.get(), "Route"); +#endif + { + Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + r->input()->ensure_io (_master_out->output()->n_ports(), false, this); + r->output()->ensure_io (_master_out->output()->n_ports(), false, this); + } - boost::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle()); + rl.push_back (r); + add_routes (rl, false, false); + + assert (_monitor_out); - if (b) { - _monitor_out->output()->connect_ports_to_bundle (b, this); - } else { - warning << string_compose (_("The preferred I/O for the monitor bus (%1) cannot be found"), - Config->get_monitor_bus_preferred_bundle()) - << endmsg; - } + /* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else + are undefined, at best. + */ + + uint32_t limit = _monitor_out->n_inputs().n_audio(); + + if (_master_out) { + + /* connect the inputs to the master bus outputs. this + * represents a separate data feed from the internal sends from + * each route. as of jan 2011, it allows the monitor section to + * conditionally ignore either the internal sends or the normal + * input feed, but we should really find a better way to do + * this, i think. + */ + + _master_out->output()->disconnect (this); + + for (uint32_t n = 0; n < limit; ++n) { + boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n); + boost::shared_ptr<AudioPort> o = _master_out->output()->ports().nth_audio_port (n); + + if (o) { + string connect_to = o->name(); + if (_monitor_out->input()->connect (p, connect_to, this)) { + error << string_compose (_("cannot connect control input %1 to %2"), n, connect_to) + << endmsg; + break; + } + } + } + } + + /* if monitor section is not connected, connect it to physical outs + */ + + if (Config->get_auto_connect_standard_busses() && !_monitor_out->output()->connected ()) { + + if (!Config->get_monitor_bus_preferred_bundle().empty()) { + + boost::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle()); + + if (b) { + _monitor_out->output()->connect_ports_to_bundle (b, this); + } else { + warning << string_compose (_("The preferred I/O for the monitor bus (%1) cannot be found"), + Config->get_monitor_bus_preferred_bundle()) + << endmsg; + } + + } else { + + /* Monitor bus is audio only */ - } else { + uint32_t mod = n_physical_outputs.get (DataType::AUDIO); + uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO); + vector<string> outputs[DataType::num_types]; - /* Monitor bus is audio only */ - uint32_t mod = n_physical_outputs.get (DataType::AUDIO); - uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO); - - if (mod != 0) { - - for (uint32_t n = 0; n < limit; ++n) { - - boost::shared_ptr<Port> p = _monitor_out->output()->ports().port(DataType::AUDIO, n); - string connect_to; - if (outputs[DataType::AUDIO].size() > (n % mod)) { - connect_to = outputs[DataType::AUDIO][n % mod]; - } - - if (!connect_to.empty()) { - if (_monitor_out->output()->connect (p, connect_to, this)) { - error << string_compose ( - _("cannot connect control output %1 to %2"), - n, connect_to) - << endmsg; - break; - } - } + for (uint32_t i = 0; i < DataType::num_types; ++i) { + _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]); + } + + + if (mod != 0) { + + for (uint32_t n = 0; n < limit; ++n) { + + boost::shared_ptr<Port> p = _monitor_out->output()->ports().port(DataType::AUDIO, n); + string connect_to; + if (outputs[DataType::AUDIO].size() > (n % mod)) { + connect_to = outputs[DataType::AUDIO][n % mod]; + } + + if (!connect_to.empty()) { + if (_monitor_out->output()->connect (p, connect_to, this)) { + error << string_compose ( + _("cannot connect control output %1 to %2"), + n, connect_to) + << endmsg; + break; } } } @@ -645,16 +749,32 @@ Session::when_engine_running () } } - _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty)); + /* Hold process lock while doing this so that we don't hear bits and + * pieces of audio as we work on each route. + */ + + Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - /* update latencies */ + /* Connect tracks to monitor section. Note that in an + existing session, the internal sends will already exist, but we want the + routes to notice that they connect to the control out specifically. + */ - initialize_latencies (); - /* hook us up to the engine */ + boost::shared_ptr<RouteList> rls = routes.reader (); - BootMessage (_("Connect to engine")); - _engine.set_session (this); + PBD::Unwinder<bool> uw (ignore_route_processor_changes, true); + + for (RouteList::iterator x = rls->begin(); x != rls->end(); ++x) { + + if ((*x)->is_monitor()) { + /* relax */ + } else if ((*x)->is_master()) { + /* relax */ + } else { + (*x)->enable_monitor_send (); + } + } } void @@ -701,30 +821,6 @@ Session::hookup_io () Delivery::reset_panners (); - /* Connect tracks to monitor/listen bus if there is one. Note that in an - existing session, the internal sends will already exist, but we want the - routes to notice that they connect to the control out specifically. - */ - - if (_monitor_out) { - boost::shared_ptr<RouteList> r = routes.reader (); - for (RouteList::iterator x = r->begin(); x != r->end(); ++x) { - - if ((*x)->is_monitor()) { - - /* relax */ - - } else if ((*x)->is_master()) { - - /* relax */ - - } else { - - (*x)->listen_via_monitor (); - } - } - } - /* Anyone who cares about input state, wake up and do something */ IOConnectionsComplete (); /* EMIT SIGNAL */ @@ -1467,7 +1563,7 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m list<boost::shared_ptr<MidiTrack> > ret; uint32_t control_id; - control_id = ntracks() + nbusses(); + control_id = next_control_id (); bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("MIDI"); @@ -1683,9 +1779,8 @@ Session::auto_connect_route (boost::shared_ptr<Route> route, ChanCount& existing * @param name_template string to use for the start of the name, or "" to use "Audio". */ list< boost::shared_ptr<AudioTrack> > -Session::new_audio_track ( - int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template - ) +Session::new_audio_track (int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group, + uint32_t how_many, string name_template) { char track_name[32]; uint32_t track_id = 0; @@ -1694,7 +1789,7 @@ Session::new_audio_track ( list<boost::shared_ptr<AudioTrack> > ret; uint32_t control_id; - control_id = ntracks() + nbusses() + 1; + control_id = next_control_id (); bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Audio"); @@ -1813,7 +1908,7 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r RouteList ret; uint32_t control_id; - control_id = ntracks() + nbusses() + 1; + control_id = next_control_id (); bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Bus"); @@ -1901,7 +1996,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template XMLNode* node = tree.root(); - control_id = ntracks() + nbusses() + 1; + control_id = next_control_id (); while (how_many) { @@ -2054,7 +2149,7 @@ Session::add_routes (RouteList& new_routes, bool auto_connect, bool save) } else if ((*x)->is_master()) { /* relax */ } else { - (*x)->listen_via_monitor (); + (*x)->enable_monitor_send (); } } @@ -2153,7 +2248,7 @@ Session::add_internal_sends (boost::shared_ptr<Route> dest, Placement p, boost:: void Session::remove_route (boost::shared_ptr<Route> route) { - if (((route == _master_out) || (route == _monitor_out)) && !Config->get_allow_special_bus_removal()) { + if (route == _master_out) { return; } @@ -2175,13 +2270,6 @@ Session::remove_route (boost::shared_ptr<Route> route) } if (route == _monitor_out) { - - /* cancel control outs for all routes */ - - for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) { - (*r)->drop_listen (_monitor_out); - } - _monitor_out.reset (); } @@ -4564,3 +4652,9 @@ Session::session_name_is_legal (const string& path) return 0; } + +uint32_t +Session::next_control_id () const +{ + return ntracks() + nbusses() + 1; +} diff --git a/libs/ardour/session_click.cc b/libs/ardour/session_click.cc index a9f867e24c..72816f3f19 100644 --- a/libs/ardour/session_click.cc +++ b/libs/ardour/session_click.cc @@ -57,7 +57,6 @@ Session::click (framepos_t start, framecnt_t nframes) click_distance = start - _clicks_cleared; - if (!clickm.locked() || _transport_speed != 1.0 || !_clicking || click_data == 0 || ((click_distance + nframes) < _worst_track_latency)) { _click_io->silence (nframes); return; diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 33768e1ce8..893f94831b 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -225,6 +225,7 @@ Session::first_stage_init (string fullpath, string snapshot_name) no_questions_about_missing_files = false; _speakers.reset (new Speakers); _clicks_cleared = 0; + ignore_route_processor_changes = false; AudioDiskstream::allocate_working_buffers(); @@ -570,7 +571,6 @@ Session::create (const string& session_template, BusProfile* bus_profile) if (bus_profile) { RouteList rl; - int control_id = 1; ChanCount count(DataType::AUDIO, bus_profile->master_out_channels); if (bus_profile->master_out_channels) { @@ -586,28 +586,9 @@ Session::create (const string& session_template, BusProfile* bus_profile) r->input()->ensure_io (count, false, this); r->output()->ensure_io (count, false, this); } - r->set_remote_control_id (control_id++); rl.push_back (r); - if (Config->get_use_monitor_bus()) { - boost::shared_ptr<Route> r (new Route (*this, _("monitor"), Route::MonitorOut, DataType::AUDIO)); - if (r->init ()) { - return -1; - } -#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS - // boost_debug_shared_ptr_mark_interesting (r.get(), "Route"); -#endif - { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - r->input()->ensure_io (count, false, this); - r->output()->ensure_io (count, false, this); - } - r->set_remote_control_id (control_id); - - rl.push_back (r); - } - } else { /* prohibit auto-connect to master, because there isn't one */ bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster); @@ -629,6 +610,10 @@ Session::create (const string& session_template, BusProfile* bus_profile) Config->set_output_auto_connect (bus_profile->output_ac); } + if (Config->get_use_monitor_bus() && bus_profile) { + add_monitor_section (); + } + save_state (""); return 0; diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index b1eb5caf27..84699ac718 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -1503,6 +1503,10 @@ Session::xrun_recovery () void Session::route_processors_changed (RouteProcessorChange c) { + if (ignore_route_processor_changes) { + return; + } + if (c.type == RouteProcessorChange::MeterPointChange) { return; } diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc index 8588d9ccd6..cc02386bf4 100644 --- a/libs/ardour/utils.cc +++ b/libs/ardour/utils.cc @@ -344,8 +344,7 @@ path_expand (string path) if (realpath (path.c_str(), buf)) { return buf; } else { - error << string_compose (_("programming error: realpath(%1) failed, errcode %2"), path, errno) << endmsg; - return path; + return string(); } } @@ -362,7 +361,10 @@ search_path_expand (string path) split (path, s, ':'); for (vector<string>::iterator i = s.begin(); i != s.end(); ++i) { - n.push_back (path_expand (*i)); + string exp = path_expand (*i); + if (!exp.empty()) { + n.push_back (exp); + } } string r; |