X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession.cc;h=431cadfca0628cc0a8e2edd99f480db5295fe721;hb=6946bdc0830c9f0971d2cd0d54b27e343c54d96a;hp=00055844031fa5c60e1cda4142029ff3e0e73853;hpb=00caabf73583fa029601b7d4e9ccdb9b2da7925c;p=ardour.git diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 0005584403..431cadfca0 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" @@ -114,7 +113,7 @@ #include "LuaBridge/LuaBridge.h" -#include "i18n.h" +#include "pbd/i18n.h" #include @@ -178,6 +177,7 @@ Session::Session (AudioEngine &eng, , _record_status (Disabled) , _transport_frame (0) , _session_range_location (0) + , _session_range_end_is_free (true) , _slave (0) , _silent (false) , _transport_speed (0) @@ -212,7 +212,9 @@ Session::Session (AudioEngine &eng, , post_export_position (0) , _exporting (false) , _export_rolling (false) + , _realtime_export (false) , _export_preroll (0) + , _export_latency (0) , _pre_export_mmc_enabled (false) , _name (snapshot_name) , _is_new (true) @@ -237,7 +239,7 @@ Session::Session (AudioEngine &eng, , pending_locate_flush (false) , pending_abort (false) , pending_auto_loop (false) - , _mempool ("Session", 1048576) + , _mempool ("Session", 2097152) , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool)) , _n_lua_scripts (0) , _butler (new Butler (*this)) @@ -249,6 +251,7 @@ Session::Session (AudioEngine &eng, , _rt_thread_active (false) , _rt_emit_pending (false) , _ac_thread_active (false) + , _latency_recompute_pending (0) , step_speed (0) , outbound_mtc_timecode_frame (0) , next_quarter_frame_to_send (-1) @@ -907,6 +910,41 @@ Session::setup_click_state (const XMLNode* node) } } +void +Session::get_physical_ports (vector& inputs, vector& outputs, DataType type, bool excluding) +{ + _engine.get_physical_inputs (type, inputs); + + if (excluding) { + /* rip out ControlOnly ports, and ALSA MIDI Through ports */ + + for (vector::iterator si = inputs.begin(); si != inputs.end(); ) { + if (PortManager::port_is_control_only (*si)) { + si = inputs.erase (si); + } else if ((*si).find (X_("Midi Through")) != string::npos || (*si).find (X_("Midi-Through")) != string::npos) { + si = inputs.erase (si); + } else { + ++si; + } + } + } + _engine.get_physical_outputs (type, outputs); + + if (excluding) { + /* rip out ControlOnly ports, and ALSA MIDI Through ports */ + + for (vector::iterator si = outputs.begin(); si != outputs.end(); ) { + if (PortManager::port_is_control_only (*si)) { + si = outputs.erase (si); + } else if ((*si).find (X_("Midi Through")) != string::npos || (*si).find (X_("Midi-Through")) != string::npos) { + si = outputs.erase (si); + } else { + ++si; + } + } + } +} + void Session::setup_bundles () { @@ -925,9 +963,9 @@ 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)), true); } /* Create a set of Bundle objects that map @@ -2026,59 +2064,55 @@ framepos_t Session::audible_frame () const { framepos_t ret; - framepos_t tf; - framecnt_t offset; - offset = worst_playback_latency (); + frameoffset_t offset = worst_playback_latency (); // - _engine.samples_since_cycle_start (); + offset *= transport_speed (); if (synced_to_engine()) { /* Note: this is basically just sync-to-JACK */ - tf = _engine.transport_frame(); + ret = _engine.transport_frame(); } else { - tf = _transport_frame; + ret = _transport_frame; } - ret = tf; - - if (!non_realtime_work_pending()) { - - /* MOVING */ + if (transport_rolling()) { + ret -= offset; /* Check to see if we have passed the first guaranteed - audible frame past our last start position. if not, - return that last start point because in terms - of audible frames, we have not moved yet. - - `Start position' in this context means the time we last - either started, located, or changed transport direction. - */ + * audible frame past our last start position. if not, + * return that last start point because in terms + * of audible frames, we have not moved yet. + * + * `Start position' in this context means the time we last + * either started, located, or changed transport direction. + */ if (_transport_speed > 0.0f) { if (!play_loop || !have_looped) { - if (tf < _last_roll_or_reversal_location + offset) { + if (ret < _last_roll_or_reversal_location) { return _last_roll_or_reversal_location; } + } else { + // latent loops + Location *location = _locations->auto_loop_location(); + frameoffset_t lo = location->start() - ret; + if (lo > 0) { + ret = location->end () - lo; + } } - - /* forwards */ - ret -= offset; - } else if (_transport_speed < 0.0f) { /* XXX wot? no backward looping? */ - if (tf > _last_roll_or_reversal_location - offset) { + if (ret > _last_roll_or_reversal_location) { return _last_roll_or_reversal_location; - } else { - /* backwards */ - ret += offset; } } } - return ret; + return std::max ((framepos_t)0, ret); } void @@ -2580,6 +2614,7 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name route_group->add (bus); } + bus->add_internal_return (); ret.push_back (bus); } @@ -2938,17 +2973,18 @@ Session::ensure_route_presentation_info_gap (PresentationInfo::order_t first_new /* create a gap in the presentation info to accomodate @param how_many * new objects. */ - boost::shared_ptr rd = routes.reader(); + StripableList sl; + get_stripables (sl); - for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) { - boost::shared_ptr rt (*ri); + for (StripableList::iterator si = sl.begin(); si != sl.end(); ++si) { + boost::shared_ptr s (*si); - if (rt->presentation_info().special()) { + if (s->is_monitor() || s->is_auditioner()) { continue; } - if (rt->presentation_info().order () >= first_new_order) { - rt->set_presentation_order (rt->presentation_info().order () + how_many); + if (s->presentation_info().order () >= first_new_order) { + s->set_presentation_order (s->presentation_info().order () + how_many); } } } @@ -3156,7 +3192,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; @@ -3164,11 +3201,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; @@ -3338,9 +3375,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 (); } @@ -3416,6 +3453,7 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool r->output()->changed.connect_same_thread (*this, boost::bind (&Session::set_worst_io_latencies_x, this, _1, _2)); r->processors_changed.connect_same_thread (*this, boost::bind (&Session::route_processors_changed, this, _1)); + r->processor_latency_changed.connect_same_thread (*this, boost::bind (&Session::queue_latency_recompute, this)); if (r->is_master()) { _master_out = r; @@ -3448,7 +3486,7 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool if (order == PresentationInfo::max_order) { /* just add to the end */ - r->set_presentation_order_explicit (n_routes + added); + r->set_presentation_order (n_routes + added, false); DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order not set, set to NR %1 + %2 = %3\n", n_routes, added, n_routes + added)); } else { r->set_presentation_order (order + added); @@ -3459,7 +3497,7 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool } } -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(__FreeBSD__) /* clang complains: 'operator<<' should be declared prior to the call site or in an associated namespace of one of its * arguments std::ostream& operator<<(std::ostream& o, ARDOUR::PresentationInfo const& rid)" */ @@ -3896,6 +3934,8 @@ Session::route_solo_changed (bool self_solo_changed, Controllable::GroupControlD if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) { /* route does not get solo propagated to it */ + DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 excluded from solo because iso = %2 can_solo = %3\n", (*i)->name(), (*i)->solo_isolate_control()->solo_isolated(), + (*i)->can_solo())); continue; } @@ -4230,33 +4270,33 @@ Session::get_remote_nth_route (PresentationInfo::order_t n) const } boost::shared_ptr -Session::get_nth_stripable (PresentationInfo::order_t n) const +Session::get_remote_nth_stripable (PresentationInfo::order_t n, PresentationInfo::Flag flags) const { StripableList sl; + PresentationInfo::order_t match_cnt = 0; get_stripables (sl); + sl.sort (Stripable::PresentationOrderSorter()); for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) { - if ((*s)->presentation_info().order() == n) { - return *s; - } - } - /* there is no nth stripable */ + 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. - return boost::shared_ptr(); -} - -boost::shared_ptr -Session::get_remote_nth_stripable (PresentationInfo::order_t n, PresentationInfo::Flag flags) const -{ - StripableList sl; - PresentationInfo::order_t match_cnt = 0; + 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. + */ - get_stripables (sl); - sl.sort (Stripable::PresentationOrderSorter()); + if (! (flags & PresentationInfo::Hidden)) { + continue; + } + } - for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) { if ((*s)->presentation_info().flag_match (flags)) { if (match_cnt++ == n) { return *s; @@ -4402,12 +4442,18 @@ Session::maybe_update_session_range (framepos_t a, framepos_t b) _session_range_location->set_start (a); } - if (b > _session_range_location->end()) { + if (_session_range_end_is_free && (b > _session_range_location->end())) { _session_range_location->set_end (b); } } } +void +Session::set_end_is_free (bool yn) +{ + _session_range_end_is_free = yn; +} + void Session::playlist_ranges_moved (list > const & ranges) { @@ -5186,6 +5232,7 @@ Session::try_run_lua (pframes_t nframes) Glib::Threads::Mutex::Lock tm (lua_lock, Glib::Threads::TRY_LOCK); if (tm.locked ()) { try { (*_lua_run)(nframes); } catch (luabridge::LuaException const& e) { } + lua.collect_garbage_step (); } } @@ -5195,6 +5242,7 @@ Session::setup_lua () #ifndef NDEBUG lua.Print.connect (&_lua_print); #endif + lua.tweak_rt_gc (); lua.do_command ( "function ArdourSession ()" " local self = { scripts = {}, instances = {} }" @@ -6281,12 +6329,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); } } @@ -6352,6 +6400,7 @@ Session::start_time_changed (framepos_t old) if (l && l->start() == old) { l->set_start (s->start(), true); } + set_dirty (); } void @@ -6371,6 +6420,7 @@ Session::end_time_changed (framepos_t old) if (l && l->end() == old) { l->set_end (s->end(), true); } + set_dirty (); } std::vector @@ -6852,6 +6902,16 @@ Session::auto_connect_route (boost::shared_ptr route, bool connect_inputs } } +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); + } +} + void Session::auto_connect (const AutoConnectRequest& ar) { @@ -6888,8 +6948,7 @@ Session::auto_connect (const AutoConnectRequest& ar) vector physinputs; vector physoutputs; - _engine.get_physical_outputs (*t, physoutputs); - _engine.get_physical_inputs (*t, physinputs); + get_physical_ports (physinputs, physoutputs, *t, true); if (!physinputs.empty() && ar.connect_inputs) { uint32_t nphysical_in = physinputs.size(); @@ -7017,7 +7076,32 @@ Session::auto_connect_thread_run () } } + if (!actively_recording ()) { // might not be needed, + /* this is only used for updating plugin latencies, the + * graph does not change. so it's safe in general. + * BUT.. + * .. update_latency_compensation () entails set_capture_offset() + * which calls Diskstream::set_capture_offset () which + * modifies the capture offset... which can be a proplem + * in "prepare_to_stop" + */ + while (g_atomic_int_and (&_latency_recompute_pending, 0)) { + update_latency_compensation (); + } + } + pthread_cond_wait (&_auto_connect_cond, &_auto_connect_mutex); } pthread_mutex_unlock (&_auto_connect_mutex); } + +void +Session::cancel_all_solo () +{ + StripableList sl; + + get_stripables (sl); + + set_controls (stripable_list_to_control_list (sl, &Stripable::solo_control), 0.0, Controllable::NoGroup); + clear_all_solo_state (routes.reader()); +}