X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession.cc;h=2c3e1d2ef2f1b3c522583eab56d37d3526c2cd8b;hb=446041d6b9cecca1906975d191446b8d14a91a23;hp=4f005b1001a802c77cc11128ba4f7d22272def5f;hpb=39903a00235a6bd222da23bab177a960ce1c5947;p=ardour.git diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 4f005b1001..2c3e1d2ef2 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -222,7 +222,6 @@ Session::Session (AudioEngine &eng, , _is_new (true) , _send_qf_mtc (false) , _pframes_since_last_mtc (0) - , session_midi_feedback (0) , play_loop (false) , loop_changing (false) , last_loopend (0) @@ -241,7 +240,7 @@ Session::Session (AudioEngine &eng, , pending_locate_flush (false) , pending_abort (false) , pending_auto_loop (false) - , _mempool ("Session", 2097152) + , _mempool ("Session", 3145728) , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool)) , _n_lua_scripts (0) , _butler (new Butler (*this)) @@ -252,7 +251,7 @@ Session::Session (AudioEngine &eng, , _ignore_skips_updates (false) , _rt_thread_active (false) , _rt_emit_pending (false) - , _ac_thread_active (false) + , _ac_thread_active (0) , _latency_recompute_pending (0) , step_speed (0) , outbound_mtc_timecode_frame (0) @@ -301,9 +300,13 @@ Session::Session (AudioEngine &eng, , click_length (0) , click_emphasis_length (0) , _clicks_cleared (0) + , _count_in_samples (0) , _play_range (false) , _range_selection (-1,-1) , _object_selection (-1,-1) + , _preroll_record_punch_pos (-1) + , _preroll_record_trim_len (0) + , _count_in_once (false) , main_outs (0) , first_file_data_format_reset (true) , first_file_header_format_reset (true) @@ -333,7 +336,7 @@ Session::Session (AudioEngine &eng, init_name_id_counter (1); // reset for new sessions, start at 1 VCA::set_next_vca_number (1); // reset for new sessions, start at 1 - pre_engine_init (fullpath); + pre_engine_init (fullpath); // sets _is_new setup_lua (); @@ -416,6 +419,8 @@ Session::Session (AudioEngine &eng, _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty); + PresentationInfo::Change.connect_same_thread (*this, boost::bind (&Session::notify_presentation_info_change, this)); + Config->ParameterChanged.connect_same_thread (*this, boost::bind (&Session::config_changed, this, _1, false)); config.ParameterChanged.connect_same_thread (*this, boost::bind (&Session::config_changed, this, _1, true)); @@ -479,6 +484,8 @@ Session::Session (AudioEngine &eng, } #endif + ensure_subdirs (); // archived or zipped sessions may lack peaks/ analysis/ etc + _is_new = false; session_loaded (); @@ -607,9 +614,6 @@ Session::destroy () _state_of_the_state = StateOfTheState (CannotSave|Deletion); - /* stop autoconnecting */ - auto_connect_thread_terminate (); - /* disconnect from any and all signals that we are connected to */ Port::PortSignalDrop (); /* EMIT SIGNAL */ @@ -621,6 +625,9 @@ Session::destroy () ControlProtocolManager::instance().drop_protocols (); + /* stop autoconnecting */ + auto_connect_thread_terminate (); + MIDI::Name::MidiPatchManager::instance().remove_search_path(session_directory().midi_patch_path()); _engine.remove_session (); @@ -779,6 +786,7 @@ Session::destroy () case SessionEvent::Skip: case SessionEvent::PunchIn: case SessionEvent::PunchOut: + case SessionEvent::RecordStart: case SessionEvent::StopOnce: case SessionEvent::RangeStop: case SessionEvent::RangeLocate: @@ -818,8 +826,10 @@ Session::setup_ltc () { Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); _ltc_input->ensure_io (ChanCount (DataType::AUDIO, 1), true, this); + // TODO use auto-connect thread somehow (needs a route currently) + // see note in Session::auto_connect_thread_run() why process lock is needed. + reconnect_ltc_input (); } - reconnect_ltc_input (); } if (state_tree && (child = find_named_node (*state_tree->root(), X_("LTC Out"))) != 0) { @@ -828,8 +838,9 @@ Session::setup_ltc () { Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); _ltc_output->ensure_io (ChanCount (DataType::AUDIO, 1), true, this); + // TODO use auto-connect thread + reconnect_ltc_output (); } - reconnect_ltc_output (); } /* fix up names of LTC ports because we don't want the normal @@ -1677,7 +1688,7 @@ Session::set_session_extents (framepos_t start, framepos_t end) Location* existing; if ((existing = _locations->session_range_location()) == 0) { //if there is no existing session, we need to make a new session location (should never happen) - existing = new Location (*this, 0, 0, _("session"), Location::IsSessionRange); + existing = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0); } if (end <= start) { @@ -1866,6 +1877,17 @@ Session::location_added (Location *location) location->EndChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location)); location->Changed.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location)); location->FlagsChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location)); + location->PositionLockStyleChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location)); + } + + if (location->is_range_marker()) { + /* listen for per-location signals that require us to do any * global updates for marks */ + + location->StartChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location)); + location->EndChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location)); + location->Changed.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location)); + location->FlagsChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location)); + location->PositionLockStyleChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location)); } if (location->is_skip()) { @@ -1875,6 +1897,7 @@ Session::location_added (Location *location) location->EndChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_skips, this, location, true)); location->Changed.connect_same_thread (skip_update_connections, boost::bind (&Session::update_skips, this, location, true)); location->FlagsChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_skips, this, location, false)); + location->PositionLockStyleChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location)); update_skips (location, true); } @@ -1994,6 +2017,7 @@ Session::disable_record (bool rt_context, bool force) if (!rt_context) { remove_pending_capture_state (); } + unset_preroll_record_punch (); } } @@ -2011,7 +2035,7 @@ Session::step_back_from_record () } void -Session::maybe_enable_record () +Session::maybe_enable_record (bool rt_context) { if (_step_editors > 0) { return; @@ -2020,15 +2044,18 @@ Session::maybe_enable_record () g_atomic_int_set (&_record_status, Enabled); /* This function is currently called from somewhere other than an RT thread. - This save_state() call therefore doesn't impact anything. Doing it here - means that we save pending state of which sources the next record will use, - which gives us some chance of recovering from a crash during the record. - */ + * (except maybe lua scripts, which can use rt_context = true) + * This save_state() call therefore doesn't impact anything. Doing it here + * means that we save pending state of which sources the next record will use, + * which gives us some chance of recovering from a crash during the record. + */ - save_state ("", true); + if (!rt_context) { + save_state ("", true); + } if (_transport_speed) { - if (!config.get_punch_in()) { + if (!config.get_punch_in() && !preroll_record_punch_enabled ()) { enable_record (); } } else { @@ -2094,6 +2121,22 @@ Session::audible_frame () const return std::max ((framepos_t)0, ret); } + +framecnt_t +Session::preroll_samples (framepos_t pos) const +{ + const float pr = Config->get_preroll_seconds(); + if (pos >= 0 && pr < 0) { + const Tempo& tempo = _tempo_map->tempo_at_frame (pos); + const Meter& meter = _tempo_map->meter_at_frame (pos); + return meter.frames_per_bar (tempo, frame_rate()) * -pr; + } + if (pr < 0) { + return 0; + } + return pr * frame_rate(); +} + void Session::set_frame_rate (framecnt_t frames_per_second) { @@ -2446,9 +2489,10 @@ Session::default_track_name_pattern (DataType t) * @param instrument plugin info for the instrument to insert pre-fader, if any */ list > -Session::new_midi_track (const ChanCount& input, const ChanCount& output, +Session::new_midi_track (const ChanCount& input, const ChanCount& output, bool strict_io, boost::shared_ptr instrument, Plugin::PresetRecord* pset, - RouteGroup* route_group, uint32_t how_many, string name_template, PresentationInfo::order_t order, + RouteGroup* route_group, uint32_t how_many, + string name_template, PresentationInfo::order_t order, TrackMode mode) { string track_name; @@ -2475,7 +2519,7 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, goto failed; } - if (Profile->get_mixbus ()) { + if (strict_io) { track->set_strict_io (true); } @@ -2541,8 +2585,16 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, if (pset) { plugin->load_preset (*pset); } - boost::shared_ptr p (new PluginInsert (*this, plugin)); - (*r)->add_processor (p, PreFader); + boost::shared_ptr pi (new PluginInsert (*this, plugin)); + if (strict_io) { + pi->set_strict_io (true); + } + + (*r)->add_processor (pi, PreFader); + + if (Profile->get_mixbus () && pi->configured () && pi->output_streams().n_audio() > 2) { + (*r)->move_instrument_down (false); + } } } } @@ -2551,7 +2603,8 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, } RouteList -Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name_template, boost::shared_ptr instrument, Plugin::PresetRecord* pset, +Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name_template, bool strict_io, + boost::shared_ptr instrument, Plugin::PresetRecord* pset, PresentationInfo::Flag flag, PresentationInfo::order_t order) { string bus_name; @@ -2574,7 +2627,7 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name goto failure; } - if (Profile->get_mixbus ()) { + if (strict_io) { bus->set_strict_io (true); } @@ -2632,8 +2685,16 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name if (pset) { plugin->load_preset (*pset); } - boost::shared_ptr p (new PluginInsert (*this, plugin)); - (*r)->add_processor (p, PreFader); + boost::shared_ptr pi (new PluginInsert (*this, plugin)); + if (strict_io) { + pi->set_strict_io (true); + } + + (*r)->add_processor (pi, PreFader); + + if (Profile->get_mixbus () && pi->configured () && pi->output_streams().n_audio() > 2) { + (*r)->move_instrument_down (false); + } } } } @@ -3248,7 +3309,15 @@ Session::new_route_from_template (uint32_t how_many, PresentationInfo::order_t i boost::shared_ptr playlist = playlists->by_name (playlist_name); // Use same name as Route::set_name_in_state so playlist copy // is picked up when creating the Route in XMLRouteFactory below - PlaylistFactory::create (playlist, string_compose ("%1.1", name)); + playlist = PlaylistFactory::create (playlist, string_compose ("%1.1", name)); + playlist->reset_shares (); + } + } else if (pd == SharePlaylist) { + XMLNode* ds_node = find_named_node (node_copy, "Diskstream"); + if (ds_node) { + const std::string playlist_name = ds_node->property (X_("playlist"))->value (); + boost::shared_ptr playlist = playlists->by_name (playlist_name); + playlist->share_with ((node_copy.property (X_("id")))->value()); } } @@ -3415,84 +3484,109 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool } } + /* auditioner and monitor routes are not part of the order */ + if (auditioner) { + assert (n_routes > 0); + --n_routes; + } + if (_monitor_out) { + assert (n_routes > 0); + --n_routes; + } + DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("ensure order gap starting at %1 for %2\n", order, new_routes.size())); ensure_route_presentation_info_gap (order, new_routes.size()); - for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x, ++added) { + { + PresentationInfo::ChangeSuspender cs; - boost::weak_ptr wpr (*x); - boost::shared_ptr r (*x); + for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x, ++added) { - r->solo_control()->Changed.connect_same_thread (*this, boost::bind (&Session::route_solo_changed, this, _1, _2,wpr)); - r->solo_isolate_control()->Changed.connect_same_thread (*this, boost::bind (&Session::route_solo_isolated_changed, this, wpr)); - r->mute_control()->Changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this)); + boost::weak_ptr wpr (*x); + boost::shared_ptr r (*x); - 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)); + r->solo_control()->Changed.connect_same_thread (*this, boost::bind (&Session::route_solo_changed, this, _1, _2,wpr)); + r->solo_isolate_control()->Changed.connect_same_thread (*this, boost::bind (&Session::route_solo_isolated_changed, this, wpr)); + r->mute_control()->Changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this)); - if (r->is_master()) { - _master_out = r; - } + 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_monitor()) { - _monitor_out = r; - } + if (r->is_master()) { + _master_out = r; + } - boost::shared_ptr tr = boost::dynamic_pointer_cast (r); - if (tr) { - tr->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::track_playlist_changed, this, boost::weak_ptr (tr))); - track_playlist_changed (boost::weak_ptr (tr)); - tr->rec_enable_control()->Changed.connect_same_thread (*this, boost::bind (&Session::update_route_record_state, this)); - - boost::shared_ptr mt = boost::dynamic_pointer_cast (tr); - 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))); + if (r->is_monitor()) { + _monitor_out = r; + } + + boost::shared_ptr tr = boost::dynamic_pointer_cast (r); + if (tr) { + tr->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::track_playlist_changed, this, boost::weak_ptr (tr))); + track_playlist_changed (boost::weak_ptr (tr)); + tr->rec_enable_control()->Changed.connect_same_thread (*this, boost::bind (&Session::update_route_record_state, this)); + + boost::shared_ptr mt = boost::dynamic_pointer_cast (tr); + 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))); + } } - } - if (!r->presentation_info().special()) { + if (!r->presentation_info().special()) { - DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("checking PI state for %1\n", r->name())); + DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("checking PI state for %1\n", r->name())); - /* presentation info order may already have been set from XML */ + /* presentation info order may already have been set from XML */ - if (!r->presentation_info().order_set()) { + if (!r->presentation_info().order_set()) { + /* this is only useful for headless sessions, + * Editor::add_routes() and Mixer_UI::add_routes() will + * override it following the RouteAdded signal. + * + * Also routes should be sorted before VCAs (like the GUI does). + * Session::ensure_route_presentation_info_gap() does not special case VCAs either. + * + * ... but not to worry, the GUI's + * gtk2_ardour/route_sorter.h and various ::sync_presentation_info_from_treeview() + * handle this :) + */ - if (order == PresentationInfo::max_order) { - /* just add to the end */ - 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)); + if (order == PresentationInfo::max_order) { + /* just add to the end */ + r->set_presentation_order (n_routes + added); + 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); + DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order not set, set to %1 + %2 = %3\n", order, added, order + added)); + } } else { - r->set_presentation_order (order + added); - DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order not set, set to %1 + %2 = %3\n", order, added, order + added)); + DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order already set to %1\n", r->presentation_info().order())); } - } else { - DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order already set to %1\n", r->presentation_info().order())); } - } #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)" - */ - DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("added route %1, group order %2 type %3 (summary: %4)\n", - r->name(), - r->presentation_info().order(), - enum_2_string (r->presentation_info().flags()), - r->presentation_info())); + /* 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)" + */ + DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("added route %1, group order %2 type %3 (summary: %4)\n", + r->name(), + r->presentation_info().order(), + enum_2_string (r->presentation_info().flags()), + r->presentation_info())); #endif - if (input_auto_connect || output_auto_connect) { - auto_connect_route (r, input_auto_connect, ChanCount (), ChanCount (), existing_inputs, existing_outputs); - existing_inputs += r->n_inputs(); - existing_outputs += r->n_outputs(); - } + if (input_auto_connect || output_auto_connect) { + auto_connect_route (r, input_auto_connect, ChanCount (), ChanCount (), existing_inputs, existing_outputs); + existing_inputs += r->n_inputs(); + existing_outputs += r->n_outputs(); + } - ARDOUR::GUIIdle (); + ARDOUR::GUIIdle (); + } } if (_monitor_out && IO::connecting_legal) { @@ -3707,7 +3801,10 @@ Session::remove_routes (boost::shared_ptr routes_to_remove) return; } - PresentationInfo::Change(); /* EMIT SIGNAL */ + PropertyChange so; + so.add (Properties::selected); + so.add (Properties::order); + PresentationInfo::Change (PropertyChange (so)); /* save the new state of the world */ @@ -4282,18 +4379,6 @@ Session::get_remote_nth_stripable (PresentationInfo::order_t n, PresentationInfo return boost::shared_ptr(); } -boost::shared_ptr -Session::route_by_selected_count (uint32_t id) const -{ - boost::shared_ptr r = routes.reader (); - - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - /* NOT IMPLEMENTED */ - } - - return boost::shared_ptr ((Route*) 0); -} - struct PresentationOrderSorter { bool operator() (boost::shared_ptr a, boost::shared_ptr b) { if (a->presentation_info().special() && !b->presentation_info().special()) { @@ -4308,6 +4393,27 @@ struct PresentationOrderSorter { } }; +boost::shared_ptr +Session::route_by_selected_count (uint32_t id) const +{ + RouteList r (*(routes.reader ())); + PresentationOrderSorter sorter; + r.sort (sorter); + + RouteList::iterator i; + + for (i = r.begin(); i != r.end(); ++i) { + if ((*i)->presentation_info().selected()) { + if (id == 0) { + return *i; + } + --id; + } + } + + return boost::shared_ptr (); +} + void Session::reassign_track_numbers () { @@ -5165,6 +5271,9 @@ Session::register_lua_function ( tbl_arg[(*i)->name] = (*i)->value; } (*_lua_add)(name, bytecode, tbl_arg); // throws luabridge::LuaException + lm.release(); + + LuaScriptsChanged (); /* EMIT SIGNAL */ set_dirty(); } @@ -5174,6 +5283,9 @@ Session::unregister_lua_function (const std::string& name) Glib::Threads::Mutex::Lock lm (lua_lock); (*_lua_del)(name); // throws luabridge::LuaException lua.collect_garbage (); + lm.release(); + + LuaScriptsChanged (); /* EMIT SIGNAL */ set_dirty(); } @@ -5234,7 +5346,7 @@ Session::setup_lua () " assert(self.scripts[n] == nil, 'Callback \"'.. n ..'\" already exists.')" " self.scripts[n] = { ['f'] = f, ['a'] = a }" " local env = _ENV; env.f = nil env.io = nil env.os = nil env.loadfile = nil env.require = nil env.dofile = nil env.package = nil env.debug = nil" - " local env = { print = print, tostring = tostring, assert = assert, ipairs = ipairs, error = error, select = select, string = string, type = type, tonumber = tonumber, collectgarbage = collectgarbage, pairs = pairs, math = math, table = table, pcall = pcall, Session = Session, PBD = PBD, Timecode = Timecode, Evoral = Evoral, C = C, ARDOUR = ARDOUR }" + " local env = { print = print, tostring = tostring, assert = assert, ipairs = ipairs, error = error, select = select, string = string, type = type, tonumber = tonumber, collectgarbage = collectgarbage, pairs = pairs, math = math, table = table, pcall = pcall, bit32=bit32, Session = Session, PBD = PBD, Timecode = Timecode, Evoral = Evoral, C = C, ARDOUR = ARDOUR }" " self.instances[n] = load (string.dump(f, true), nil, nil, env)(a)" " Session:scripts_changed()" // call back " end" @@ -5563,21 +5675,11 @@ Session::tempo_map_changed (const PropertyChange&) set_dirty (); } -void -Session::gui_tempo_map_changed () -{ - clear_clicks (); - - playlists->update_after_tempo_map_change (); - - _locations->apply (*this, &Session::update_locations_after_tempo_map_change); -} - void Session::update_locations_after_tempo_map_change (const Locations::LocationList& loc) { for (Locations::LocationList::const_iterator i = loc.begin(); i != loc.end(); ++i) { - (*i)->recompute_frames_from_bbt (); + (*i)->recompute_frames_from_beat (); } } @@ -6335,7 +6437,7 @@ Session::current_end_frame () const void Session::set_session_range_location (framepos_t start, framepos_t end) { - _session_range_location = new Location (*this, start, end, _("session"), Location::IsSessionRange); + _session_range_location = new Location (*this, start, end, _("session"), Location::IsSessionRange, 0); _locations->add (_session_range_location); } @@ -6765,7 +6867,6 @@ Session::notify_presentation_info_change () return; } - PresentationInfo::Change (); /* EMIT SIGNAL */ reassign_track_numbers(); #ifdef USE_TRACKS_CODE_FEATURES @@ -6992,7 +7093,7 @@ Session::auto_connect (const AutoConnectRequest& ar) void Session::auto_connect_thread_start () { - if (_ac_thread_active) { + if (g_atomic_int_get (&_ac_thread_active)) { return; } @@ -7000,19 +7101,18 @@ Session::auto_connect_thread_start () _auto_connect_queue.pop (); } - _ac_thread_active = true; + g_atomic_int_set (&_ac_thread_active, 1); if (pthread_create (&_auto_connect_thread, NULL, auto_connect_thread, this)) { - _ac_thread_active = false; + g_atomic_int_set (&_ac_thread_active, 0); } } void Session::auto_connect_thread_terminate () { - if (!_ac_thread_active) { + if (!g_atomic_int_get (&_ac_thread_active)) { return; } - _ac_thread_active = false; { Glib::Threads::Mutex::Lock lx (_auto_connect_queue_lock); @@ -7021,7 +7121,14 @@ Session::auto_connect_thread_terminate () } } - auto_connect_thread_wakeup (); + /* cannot use auto_connect_thread_wakeup() because that is allowed to + * fail to wakeup the thread. + */ + + pthread_mutex_lock (&_auto_connect_mutex); + g_atomic_int_set (&_ac_thread_active, 0); + pthread_cond_signal (&_auto_connect_cond); + pthread_mutex_unlock (&_auto_connect_mutex); void *status; pthread_join (_auto_connect_thread, &status); @@ -7043,7 +7150,7 @@ Session::auto_connect_thread_run () SessionEvent::create_per_thread_pool (X_("autoconnect"), 1024); PBD::notify_event_loops_about_thread_creation (pthread_self(), X_("autoconnect"), 1024); pthread_mutex_lock (&_auto_connect_mutex); - while (_ac_thread_active) { + while (g_atomic_int_get (&_ac_thread_active)) { if (!_auto_connect_queue.empty ()) { // Why would we need the process lock ?? @@ -7077,7 +7184,12 @@ Session::auto_connect_thread_run () } } - AudioEngine::instance()->clear_pending_port_deletions (); + { + // this may call ARDOUR::Port::drop ... jack_port_unregister () + // jack1 cannot cope with removing ports while processing + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + AudioEngine::instance()->clear_pending_port_deletions (); + } pthread_cond_wait (&_auto_connect_cond, &_auto_connect_mutex); }