X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession.cc;h=127367483b4a402e2eb31951008fb240a80fae7d;hb=f50ab8ccecade415f6266a567f3576eacd5190a7;hp=99efc1cb7276fc9a8ac9504a6ca25c7d207c8b05;hpb=5f994c07a830438c684430e875cc4d2f79348841;p=ardour.git diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 99efc1cb72..127367483b 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -37,7 +37,6 @@ #include "pbd/basename.h" #include "pbd/convert.h" -#include "pbd/convert.h" #include "pbd/error.h" #include "pbd/file_utils.h" #include "pbd/md5.h" @@ -214,6 +213,7 @@ Session::Session (AudioEngine &eng, , _exporting (false) , _export_rolling (false) , _realtime_export (false) + , _region_export (false) , _export_preroll (0) , _export_latency (0) , _pre_export_mmc_enabled (false) @@ -312,7 +312,7 @@ Session::Session (AudioEngine &eng, , _step_editors (0) , _suspend_timecode_transmission (0) , _speakers (new Speakers) - , ignore_route_processor_changes (false) + , _ignore_route_processor_changes (0) , midi_clock (0) , _scene_changer (0) , _midi_ports (0) @@ -911,6 +911,14 @@ Session::setup_click_state (const XMLNode* node) } } +void +Session::get_physical_ports (vector& inputs, vector& outputs, DataType type, + MidiPortFlags include, MidiPortFlags exclude) +{ + _engine.get_physical_inputs (type, inputs, include, exclude); + _engine.get_physical_outputs (type, outputs, include, exclude); +} + void Session::setup_bundles () { @@ -929,9 +937,12 @@ Session::setup_bundles () vector inputs[DataType::num_types]; vector outputs[DataType::num_types]; + for (uint32_t i = 0; i < DataType::num_types; ++i) { - _engine.get_physical_inputs (DataType (DataType::Symbol (i)), inputs[i]); - _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]); + get_physical_ports (inputs[i], outputs[i], DataType (DataType::Symbol (i)), + MidiPortFlags (0), /* no specific inclusions */ + MidiPortFlags (MidiPortControl|MidiPortVirtual) /* exclude control & virtual ports */ + ); } /* Create a set of Bundle objects that map @@ -1015,6 +1026,7 @@ Session::setup_bundles () for (uint32_t np = 0; np < inputs[DataType::MIDI].size(); ++np) { string n = inputs[DataType::MIDI][np]; + std::string pn = _engine.get_pretty_name_by_name (n); if (!pn.empty()) { n = pn; @@ -1117,7 +1129,7 @@ Session::remove_monitor_section () boost::shared_ptr r = routes.reader (); - PBD::Unwinder uw (ignore_route_processor_changes, true); + ProcessorChangeBlocker pcb (this, false); for (RouteList::iterator x = r->begin(); x != r->end(); ++x) { @@ -1277,7 +1289,7 @@ Session::add_monitor_section () boost::shared_ptr rls = routes.reader (); - PBD::Unwinder uw (ignore_route_processor_changes, true); + ProcessorChangeBlocker pcb (this, false /* XXX */); for (RouteList::iterator x = rls->begin(); x != rls->end(); ++x) { @@ -1401,7 +1413,7 @@ Session::reset_monitor_section () boost::shared_ptr rls = routes.reader (); - PBD::Unwinder uw (ignore_route_processor_changes, true); + ProcessorChangeBlocker pcb (this, false); for (RouteList::iterator x = rls->begin(); x != rls->end(); ++x) { @@ -2368,8 +2380,11 @@ Session::find_route_name (string const & base, uint32_t& id, string& name, bool } } - if (!definitely_add_number && route_by_name (base) == 0) { - /* juse use the base */ + /* if we have "base 1" already, it doesn't make sense to add "base" + * if "base 1" has been deleted, adding "base" is no worse than "base 1" + */ + if (!definitely_add_number && route_by_name (base) == 0 && (route_by_name (string_compose("%1 1", base)) == 0)) { + /* just use the base */ name = base; return true; } @@ -2518,12 +2533,15 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, if (instrument) { for (RouteList::iterator r = new_routes.begin(); r != new_routes.end(); ++r) { PluginPtr plugin = instrument->load (*this); + if (!plugin) { + warning << "Failed to add Synth Plugin to newly created track." << endmsg; + continue; + } if (pset) { plugin->load_preset (*pset); } boost::shared_ptr p (new PluginInsert (*this, plugin)); (*r)->add_processor (p, PreFader); - } } } @@ -2606,6 +2624,10 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name if (instrument) { for (RouteList::iterator r = ret.begin(); r != ret.end(); ++r) { PluginPtr plugin = instrument->load (*this); + if (!plugin) { + warning << "Failed to add Synth Plugin to newly created track." << endmsg; + continue; + } if (pset) { plugin->load_preset (*pset); } @@ -3158,7 +3180,8 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r } RouteList -Session::new_route_from_template (uint32_t how_many, const std::string& template_path, const std::string& name_base, PlaylistDisposition pd) +Session::new_route_from_template (uint32_t how_many, PresentationInfo::order_t insert_at, const std::string& template_path, const std::string& name_base, + PlaylistDisposition pd) { XMLTree tree; @@ -3166,11 +3189,11 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template return RouteList(); } - return new_route_from_template (how_many, *tree.root(), name_base, pd); + return new_route_from_template (how_many, insert_at, *tree.root(), name_base, pd); } RouteList -Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::string& name_base, PlaylistDisposition pd) +Session::new_route_from_template (uint32_t how_many, PresentationInfo::order_t insert_at, XMLNode& node, const std::string& name_base, PlaylistDisposition pd) { RouteList ret; uint32_t number = 0; @@ -3220,10 +3243,10 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s bool rename_playlist; switch (pd) { case NewPlaylist: + case CopyPlaylist: rename_playlist = true; break; default: - case CopyPlaylist: case SharePlaylist: rename_playlist = false; } @@ -3310,7 +3333,6 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s if ((track = boost::dynamic_pointer_cast (route))) { switch (pd) { case NewPlaylist: - track->use_new_playlist (); break; case CopyPlaylist: track->use_copy_playlist (); @@ -3340,9 +3362,9 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s if (!ret.empty()) { StateProtector sp (this); if (Profile->get_trx()) { - add_routes (ret, false, false, false, PresentationInfo::max_order); + add_routes (ret, false, false, false, insert_at); } else { - add_routes (ret, true, true, false, PresentationInfo::max_order); + add_routes (ret, true, true, false, insert_at); } IO::enable_connecting (); } @@ -3438,6 +3460,7 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool if (mt) { mt->StepEditStatusChange.connect_same_thread (*this, boost::bind (&Session::step_edit_status_change, this, _1)); mt->output()->changed.connect_same_thread (*this, boost::bind (&Session::midi_output_change_handler, this, _1, _2, boost::weak_ptr(mt))); + mt->presentation_info().PropertyChanged.connect_same_thread (*this, boost::bind (&Session::midi_track_presentation_info_changed, this, _1, boost::weak_ptr(mt))); } } @@ -3638,7 +3661,7 @@ Session::remove_routes (boost::shared_ptr routes_to_remove) /* if the monitoring section had a pointer to this route, remove it */ if (_monitor_out && !(*iter)->is_master() && !(*iter)->is_monitor()) { Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - PBD::Unwinder uw (ignore_route_processor_changes, true); + ProcessorChangeBlocker pcb (this, false); (*iter)->remove_aux_or_listen (_monitor_out); } @@ -3684,6 +3707,7 @@ Session::remove_routes (boost::shared_ptr routes_to_remove) */ for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) { + cerr << "Drop references to " << (*iter)->name() << endl; (*iter)->drop_references (); } @@ -3765,8 +3789,6 @@ Session::route_listen_changed (Controllable::GroupControlDisposition group_overr _listen_cnt--; } - - update_route_solo_state (); } void @@ -3800,7 +3822,7 @@ Session::route_solo_isolated_changed (boost::weak_ptr wpr) void Session::route_solo_changed (bool self_solo_changed, Controllable::GroupControlDisposition group_override, boost::weak_ptr wpr) { - DEBUG_TRACE (DEBUG::Solo, string_compose ("route solo change, self = %1\n", self_solo_changed)); + DEBUG_TRACE (DEBUG::Solo, string_compose ("route solo change, self = %1, update\n", self_solo_changed)); boost::shared_ptr route (wpr.lock()); @@ -3816,21 +3838,13 @@ Session::route_solo_changed (bool self_solo_changed, Controllable::GroupControlD DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: self %2 masters %3 transition %4\n", route->name(), route->self_soloed(), route->solo_control()->get_masters_value(), route->solo_control()->transitioned_into_solo())); if (route->solo_control()->transitioned_into_solo() == 0) { - /* route solo changed by upstream/downstream; not interesting + /* route solo changed by upstream/downstream or clear all solo state; not interesting to Session. */ DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 not self-soloed nor soloed by master (%2), ignoring\n", route->name(), route->solo_control()->get_masters_value())); return; } - if (route->solo_control()->transitioned_into_solo() == 0) { - /* reason for being soloed changed (e.g. master went away, we - * took over the master state), but actual status did - * not. nothing to do. - */ - DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: solo change was change in reason, not status\n", route->name())); - } - boost::shared_ptr r = routes.reader (); int32_t delta = route->solo_control()->transitioned_into_solo (); @@ -3853,6 +3867,8 @@ Session::route_solo_changed (bool self_solo_changed, Controllable::GroupControlD RouteGroup* rg = route->route_group (); const bool group_already_accounted_for = (group_override == Controllable::ForGroup); + DEBUG_TRACE (DEBUG::Solo, string_compose ("propagate to session, group accounted for ? %1\n", group_already_accounted_for)); + if (delta == 1 && Config->get_exclusive_solo()) { /* new solo: disable all other solos, but not the group if its solo-enabled */ @@ -3966,8 +3982,6 @@ Session::route_solo_changed (bool self_solo_changed, Controllable::GroupControlD DEBUG_TRACE (DEBUG::Solo, "propagation complete\n"); - update_route_solo_state (r); - /* now notify that the mute state of the routes not involved in the signal pathway of the just-solo-changed route may have altered. */ @@ -3975,11 +3989,10 @@ Session::route_solo_changed (bool self_solo_changed, Controllable::GroupControlD for (RouteList::iterator i = uninvolved.begin(); i != uninvolved.end(); ++i) { DEBUG_TRACE (DEBUG::Solo, string_compose ("mute change for %1, which neither feeds or is fed by %2\n", (*i)->name(), route->name())); (*i)->act_on_mute (); - (*i)->mute_control()->Changed (false, Controllable::NoGroup); + /* Session will emit SoloChanged() after all solo changes are + * complete, which should be used by UIs to update mute status + */ } - - SoloChanged (); /* EMIT SIGNAL */ - set_dirty(); } void @@ -3999,13 +4012,13 @@ Session::update_route_solo_state (boost::shared_ptr r) for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->can_solo()) { if (Config->get_solo_control_is_listen_control()) { - if ((*i)->self_soloed() || (*i)->solo_control()->get_masters_value()) { + if ((*i)->solo_control()->soloed_by_self_or_masters()) { listeners++; something_listening = true; } } else { (*i)->set_listen (false); - if ((*i)->can_solo() && ((*i)->self_soloed() || (*i)->solo_control()->get_masters_value())) { + if ((*i)->can_solo() && (*i)->solo_control()->soloed_by_self_or_masters()) { something_soloed = true; } } @@ -4035,6 +4048,10 @@ Session::update_route_solo_state (boost::shared_ptr r) DEBUG_TRACE (DEBUG::Solo, string_compose ("solo state updated by session, soloed? %1 listeners %2 isolated %3\n", something_soloed, listeners, isolated)); + + + SoloChanged (); /* EMIT SIGNAL */ + set_dirty(); } void @@ -4244,6 +4261,24 @@ Session::get_remote_nth_stripable (PresentationInfo::order_t n, PresentationInfo sl.sort (Stripable::PresentationOrderSorter()); for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) { + + if ((*s)->presentation_info().hidden()) { + /* if the caller didn't explicitly ask for hidden + stripables, ignore hidden ones. This matches + the semantics of the pre-PresentationOrder + "get by RID" logic of Ardour 4.x and earlier. + + XXX at some point we should likely reverse + the logic of the flags, because asking for "the + hidden stripables" is not going to be common, + whereas asking for visible ones is normal. + */ + + if (! (flags & PresentationInfo::Hidden)) { + continue; + } + } + if ((*s)->presentation_info().flag_match (flags)) { if (match_cnt++ == n) { return *s; @@ -6180,8 +6215,8 @@ Session::update_route_record_state () void Session::listen_position_changed () { + ProcessorChangeBlocker pcb (this); boost::shared_ptr r = routes.reader (); - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->listen_position_changed (); } @@ -6191,14 +6226,18 @@ void Session::solo_control_mode_changed () { if (soloing() || listening()) { - /* We can't use ::clear_all_solo_state() here because during - session loading at program startup, that will queue a call - to rt_clear_all_solo_state() that will not execute until - AFTER solo states have been established (thus throwing away - the session's saved solo state). So just explicitly turn - them all off. - */ - set_controls (route_list_to_control_list (get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup); + if (loading()) { + /* We can't use ::clear_all_solo_state() here because during + session loading at program startup, that will queue a call + to rt_clear_all_solo_state() that will not execute until + AFTER solo states have been established (thus throwing away + the session's saved solo state). So just explicitly turn + them all off. + */ + set_controls (route_list_to_control_list (get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup); + } else { + clear_all_solo_state (get_routes()); + } } } @@ -6222,6 +6261,10 @@ Session::route_removed_from_route_group (RouteGroup* rg, boost::weak_ptr { update_route_record_state (); RouteRemovedFromRouteGroup (rg, r); /* EMIT SIGNAL */ + + if (!rg->has_control_master () && !rg->has_subgroup () && rg->empty()) { + remove_route_group (*rg); + } } boost::shared_ptr @@ -6276,12 +6319,12 @@ Session::goto_end () } void -Session::goto_start () +Session::goto_start (bool and_roll) { if (_session_range_location) { - request_locate (_session_range_location->start(), false); + request_locate (_session_range_location->start(), and_roll); } else { - request_locate (0, false); + request_locate (0, and_roll); } } @@ -6347,6 +6390,7 @@ Session::start_time_changed (framepos_t old) if (l && l->start() == old) { l->set_start (s->start(), true); } + set_dirty (); } void @@ -6366,6 +6410,7 @@ Session::end_time_changed (framepos_t old) if (l && l->end() == old) { l->set_end (s->end(), true); } + set_dirty (); } std::vector @@ -6841,6 +6886,12 @@ Session::auto_connect_route (boost::shared_ptr route, bool connect_inputs input_start, output_start, input_offset, output_offset)); + auto_connect_thread_wakeup (); +} + +void +Session::auto_connect_thread_wakeup () +{ if (pthread_mutex_trylock (&_auto_connect_mutex) == 0) { pthread_cond_signal (&_auto_connect_cond); pthread_mutex_unlock (&_auto_connect_mutex); @@ -6851,10 +6902,7 @@ void Session::queue_latency_recompute () { g_atomic_int_inc (&_latency_recompute_pending); - if (pthread_mutex_trylock (&_auto_connect_mutex) == 0) { - pthread_cond_signal (&_auto_connect_cond); - pthread_mutex_unlock (&_auto_connect_mutex); - } + auto_connect_thread_wakeup (); } void @@ -6893,8 +6941,12 @@ Session::auto_connect (const AutoConnectRequest& ar) vector physinputs; vector physoutputs; - _engine.get_physical_outputs (*t, physoutputs); - _engine.get_physical_inputs (*t, physinputs); + + /* for connecting track inputs we only want MIDI ports marked + * for "music". + */ + + get_physical_ports (physinputs, physoutputs, *t, MidiPortMusic); if (!physinputs.empty() && ar.connect_inputs) { uint32_t nphysical_in = physinputs.size(); @@ -6977,10 +7029,7 @@ Session::auto_connect_thread_terminate () } } - if (pthread_mutex_lock (&_auto_connect_mutex) == 0) { - pthread_cond_signal (&_auto_connect_cond); - pthread_mutex_unlock (&_auto_connect_mutex); - } + auto_connect_thread_wakeup (); void *status; pthread_join (_auto_connect_thread, &status); @@ -7036,6 +7085,8 @@ Session::auto_connect_thread_run () } } + AudioEngine::instance()->clear_pending_port_deletions (); + pthread_cond_wait (&_auto_connect_cond, &_auto_connect_mutex); } pthread_mutex_unlock (&_auto_connect_mutex);