X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession.cc;h=19c7f5638f3bf9d76b139316b653c5611b0cc3dc;hb=4fc42bca44651b927d336110c23e789691f3bb48;hp=f1f2919b5f7244f2fe18c8f0c4e58c929cc65d1a;hpb=5e431d1d5806e8f617b9bfa10c5c8766e0b1a4ce;p=ardour.git diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index f1f2919b5f..19c7f5638f 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -132,11 +132,11 @@ static void clean_up_session_event (SessionEvent* ev) { delete ev; } const SessionEvent::RTeventCallback Session::rt_cleanup (clean_up_session_event); Session::Session (AudioEngine &eng, - const string& fullpath, - const string& snapshot_name, + const string& fullpath, + const string& snapshot_name, BusProfile* bus_profile, - string mix_template) - : _engine (eng) + string mix_template) + : _engine (eng) , _target_transport_speed (0.0) , _requested_return_frame (-1) , _session_dir (new SessionDirectory(fullpath)) @@ -207,7 +207,7 @@ Session::Session (AudioEngine &eng, StartTimeChanged.connect_same_thread (*this, boost::bind (&Session::start_time_changed, this, _1)); EndTimeChanged.connect_same_thread (*this, boost::bind (&Session::end_time_changed, this, _1)); - _is_new = false; + _is_new = false; } Session::~Session () @@ -245,7 +245,7 @@ Session::destroy () _butler->drop_references (); delete _butler; delete midi_control_ui; - delete _all_route_group; + delete _all_route_group; if (click_data != default_click) { delete [] click_data; @@ -325,24 +325,6 @@ Session::destroy () #endif } -void -Session::set_worst_io_latencies () -{ - _worst_output_latency = 0; - _worst_input_latency = 0; - - if (!_engine.connected()) { - return; - } - - boost::shared_ptr r = routes.reader (); - - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - _worst_output_latency = max (_worst_output_latency, (*i)->output()->latency()); - _worst_input_latency = max (_worst_input_latency, (*i)->input()->latency()); - } -} - void Session::when_engine_running () { @@ -429,8 +411,6 @@ Session::when_engine_running () BootMessage (_("Compute I/O Latencies")); - set_worst_io_latencies (); - if (_clicking) { // XXX HOW TO ALERT UI TO THIS ? DO WE NEED TO? } @@ -458,7 +438,7 @@ Session::when_engine_running () char buf[32]; snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1); - boost::shared_ptr c (new Bundle (buf, true)); + boost::shared_ptr c (new Bundle (buf, true)); c->add_channel (_("mono"), DataType::AUDIO); c->set_port (0, outputs[DataType::AUDIO][np]); @@ -487,7 +467,7 @@ Session::when_engine_running () char buf[32]; snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1); - boost::shared_ptr c (new Bundle (buf, false)); + boost::shared_ptr c (new Bundle (buf, false)); c->add_channel (_("mono"), DataType::AUDIO); c->set_port (0, inputs[DataType::AUDIO][np]); @@ -501,7 +481,7 @@ Session::when_engine_running () char buf[32]; snprintf (buf, sizeof(buf), _("in %" PRIu32 "+%" PRIu32), np + 1, np + 2); - boost::shared_ptr c (new Bundle (buf, false)); + boost::shared_ptr c (new Bundle (buf, false)); c->add_channel (_("L"), DataType::AUDIO); c->set_port (0, inputs[DataType::AUDIO][np]); c->add_channel (_("R"), DataType::AUDIO); @@ -517,7 +497,7 @@ Session::when_engine_running () string n = inputs[DataType::MIDI][np]; boost::erase_first (n, X_("alsa_pcm:")); - boost::shared_ptr c (new Bundle (n, false)); + boost::shared_ptr c (new Bundle (n, false)); c->add_channel ("", DataType::MIDI); c->set_port (0, inputs[DataType::MIDI][np]); add_bundle (c); @@ -529,7 +509,7 @@ Session::when_engine_running () string n = outputs[DataType::MIDI][np]; boost::erase_first (n, X_("alsa_pcm:")); - boost::shared_ptr c (new Bundle (n, true)); + boost::shared_ptr c (new Bundle (n, true)); c->add_channel ("", DataType::MIDI); c->set_port (0, outputs[DataType::MIDI][np]); add_bundle (c); @@ -541,9 +521,9 @@ Session::when_engine_running () if (_is_new && !no_auto_connect()) { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock()); + Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock()); - /* don't connect the master bus outputs if there is a monitor bus */ + /* don't connect the master bus outputs if there is a monitor bus */ if (_master_out && Config->get_auto_connect_standard_busses() && !_monitor_out) { @@ -615,7 +595,7 @@ Session::when_engine_running () } } else { - + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { uint32_t mod = n_physical_outputs.get (*t); uint32_t limit = _monitor_out->n_outputs().get(*t); @@ -644,16 +624,14 @@ Session::when_engine_running () } } - /* catch up on send+insert cnts */ - _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty)); /* hook us up to the engine */ BootMessage (_("Connect to engine")); - _engine.set_session (this); - _engine.update_total_latencies (); + + update_latency_compensation (true); } void @@ -700,11 +678,10 @@ 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. - */ + /* 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 r = routes.reader (); @@ -777,30 +754,26 @@ Session::record_enabling_legal () const return true; } +void +Session::set_track_monitor_input_status (bool yn) +{ + boost::shared_ptr rl = routes.reader (); + for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { + boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); + if (tr && tr->record_enabled ()) { + //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl; + tr->monitor_input (yn); + } + } +} + void Session::reset_input_monitor_state () { if (transport_rolling()) { - - boost::shared_ptr rl = routes.reader (); - for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { - boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); - if (tr && tr->record_enabled ()) { - //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl; - tr->monitor_input (Config->get_monitoring_model() == HardwareMonitoring && !config.get_auto_input()); - } - } - + set_track_monitor_input_status (Config->get_monitoring_model() == HardwareMonitoring && !config.get_auto_input()); } else { - - boost::shared_ptr rl = routes.reader (); - for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { - boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); - if (tr && tr->record_enabled ()) { - //cerr << "switching to input = " << !Config->get_auto_input() << __FILE__ << __LINE__ << endl << endl; - tr->monitor_input (Config->get_monitoring_model() == HardwareMonitoring); - } - } + set_track_monitor_input_status (Config->get_monitoring_model() == HardwareMonitoring); } } @@ -1011,14 +984,7 @@ Session::enable_record () MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordStrobe)); if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) { - - boost::shared_ptr rl = routes.reader (); - for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { - boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); - if (tr && tr->record_enabled ()) { - tr->monitor_input (true); - } - } + set_track_monitor_input_status (true); } RecordStateChanged (); @@ -1044,14 +1010,7 @@ Session::disable_record (bool rt_context, bool force) } if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) { - - boost::shared_ptr rl = routes.reader (); - for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { - boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); - if (tr && tr->record_enabled ()) { - tr->monitor_input (false); - } - } + set_track_monitor_input_status (false); } RecordStateChanged (); /* emit signal */ @@ -1068,14 +1027,7 @@ Session::step_back_from_record () if (g_atomic_int_compare_and_exchange (&_record_status, Recording, Enabled)) { if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) { - boost::shared_ptr rl = routes.reader (); - for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { - boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); - if (tr && tr->record_enabled ()) { - //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; - tr->monitor_input (false); - } - } + set_track_monitor_input_status (false); } } } @@ -1126,7 +1078,7 @@ Session::audible_frame () const in the absence of any plugin latency compensation */ - offset = _worst_output_latency; + offset = worst_playback_latency (); if (offset > current_block_size) { offset -= current_block_size; @@ -1280,7 +1232,7 @@ struct RouteSorter { static void trace_terminal (boost::shared_ptr r1, boost::shared_ptr rbase) { - boost::shared_ptr r2; + boost::shared_ptr r2; if (r1->feeds (rbase) && rbase->feeds (r1)) { info << string_compose(_("feedback loop setup between %1 and %2"), r1->name(), rbase->name()) << endmsg; @@ -1340,7 +1292,7 @@ Session::resort_routes () { RCUWriter writer (routes); - boost::shared_ptr r = writer.get_copy (); + boost::shared_ptr r = writer.get_copy (); resort_routes_using (r); /* writer goes out of scope and forces update */ } @@ -1447,17 +1399,21 @@ Session::find_route_name (string const & base, uint32_t& id, char* name, size_t return false; } -/** Count the total ins and outs of all non-hidden routes in the session and return them in in and out */ +/** Count the total ins and outs of all non-hidden tracks in the session and return them in in and out */ void -Session::count_existing_route_channels (ChanCount& in, ChanCount& out) +Session::count_existing_track_channels (ChanCount& in, ChanCount& out) { in = ChanCount::ZERO; out = ChanCount::ZERO; - boost::shared_ptr r = routes.reader (); + + boost::shared_ptr r = routes.reader (); + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (!(*i)->is_hidden()) { - in += (*i)->n_inputs(); - out += (*i)->n_outputs(); + boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); + if (tr && !tr->is_hidden()) { + cerr << "Using track i/o counts for " << tr->name() << endl; + in += tr->n_inputs(); + out += tr->n_outputs(); } } } @@ -1470,15 +1426,11 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m { char track_name[32]; uint32_t track_id = 0; - ChanCount existing_inputs; - ChanCount existing_outputs; string port; RouteList new_routes; list > ret; uint32_t control_id; - count_existing_route_channels (existing_inputs, existing_outputs); - control_id = ntracks() + nbusses(); bool const use_number = (how_many != 1); @@ -1489,7 +1441,7 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m goto failed; } - boost::shared_ptr track; + boost::shared_ptr track; try { track.reset (new MidiTrack (*this, track_name, Route::Flag (0), mode)); @@ -1516,8 +1468,6 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m } } - auto_connect_route (track.get(), existing_inputs, existing_outputs); - track->non_realtime_input_change(); if (route_group) { @@ -1547,23 +1497,32 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m failed: if (!new_routes.empty()) { - add_routes (new_routes, false); + add_routes (new_routes, true, false); save_state (_current_snapshot_name); } return ret; } -/** Caller must hold process lock. - * @param connect_inputs true to connect inputs as well as outputs, false to connect just outputs. +/** @param connect_inputs true to connect inputs as well as outputs, false to connect just outputs. * @param input_start Where to start from when auto-connecting inputs; e.g. if this is 0, auto-connect starting from input 0. * @param output_start As \a input_start, but for outputs. */ void -Session::auto_connect_route ( - Route* route, ChanCount& existing_inputs, ChanCount& existing_outputs, bool connect_inputs, ChanCount input_start, ChanCount output_start - ) +Session::auto_connect_route (Route* route, ChanCount& existing_inputs, ChanCount& existing_outputs, + bool with_lock, bool connect_inputs, ChanCount input_start, ChanCount output_start) { + if (!IO::connecting_legal) { + cerr << "Auto-connect ignored because connecting it not legal\n"; + return; + } + + Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::NOT_LOCK); + + if (with_lock) { + lm.acquire (); + } + /* If both inputs and outputs are auto-connected to physical ports, use the max of input and output offsets to ensure auto-connected port numbers always match up (e.g. the first audio input and the @@ -1572,14 +1531,18 @@ Session::auto_connect_route ( offset possible. */ + DEBUG_TRACE (DEBUG::Graph, + string_compose("Auto-connect: existing in = %1 out = %2\n", + existing_inputs, existing_outputs)); + const bool in_out_physical = - (Config->get_input_auto_connect() & AutoConnectPhysical) + (Config->get_input_auto_connect() & AutoConnectPhysical) && (Config->get_output_auto_connect() & AutoConnectPhysical) && connect_inputs; const ChanCount in_offset = in_out_physical ? ChanCount::max(existing_inputs, existing_outputs) - : existing_inputs; + : existing_inputs; const ChanCount out_offset = in_out_physical ? ChanCount::max(existing_inputs, existing_outputs) @@ -1594,15 +1557,28 @@ Session::auto_connect_route ( if (!physinputs.empty() && connect_inputs) { uint32_t nphysical_in = physinputs.size(); + + DEBUG_TRACE (DEBUG::Graph, + string_compose("There are %1 physical inputs of type %2\n", + nphysical_in, *t)); + for (uint32_t i = input_start.get(*t); i < route->n_inputs().get(*t) && i < nphysical_in; ++i) { string port; if (Config->get_input_auto_connect() & AutoConnectPhysical) { + DEBUG_TRACE (DEBUG::Graph, + string_compose("Get index %1 + %2 % %3 = %4\n", + in_offset.get(*t), i, nphysical_in, + (in_offset.get(*t) + i) % nphysical_in)); port = physinputs[(in_offset.get(*t) + i) % nphysical_in]; } + DEBUG_TRACE (DEBUG::Graph, + string_compose("Connect route %1 IN to %2\n", + route->name(), port)); + if (!port.empty() && route->input()->connect ( - route->input()->ports().port(*t, i), port, this)) { + route->input()->ports().port(*t, i), port, this)) { break; } } @@ -1622,6 +1598,10 @@ Session::auto_connect_route ( } } + DEBUG_TRACE (DEBUG::Graph, + string_compose("Connect route %1 OUT to %2\n", + route->name(), port)); + if (!port.empty() && route->output()->connect ( route->output()->ports().port(*t, i), port, this)) { break; @@ -1629,9 +1609,6 @@ Session::auto_connect_route ( } } } - - existing_inputs += route->n_inputs(); - existing_outputs += route->n_outputs(); } /** Caller must not hold process lock @@ -1644,15 +1621,11 @@ Session::new_audio_track ( { char track_name[32]; uint32_t track_id = 0; - ChanCount existing_inputs; - ChanCount existing_outputs; string port; RouteList new_routes; list > ret; uint32_t control_id; - count_existing_route_channels (existing_inputs, existing_outputs); - control_id = ntracks() + nbusses() + 1; bool const use_number = (how_many != 1); @@ -1663,7 +1636,7 @@ Session::new_audio_track ( goto failed; } - boost::shared_ptr track; + boost::shared_ptr track; try { track.reset (new AudioTrack (*this, track_name, Route::Flag (0), mode)); @@ -1695,8 +1668,6 @@ Session::new_audio_track ( << endmsg; goto failed; } - - auto_connect_route (track.get(), existing_inputs, existing_outputs); } if (route_group) { @@ -1729,7 +1700,7 @@ Session::new_audio_track ( failed: if (!new_routes.empty()) { - add_routes (new_routes, true); + add_routes (new_routes, true, true); } return ret; @@ -1741,7 +1712,7 @@ Session::set_remote_control_ids () RemoteModel m = Config->get_remote_model(); bool emit_signal = false; - boost::shared_ptr r = routes.reader (); + boost::shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (MixerOrdered == m) { @@ -1770,14 +1741,10 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r { char bus_name[32]; uint32_t bus_id = 0; - ChanCount existing_inputs; - ChanCount existing_outputs; string port; RouteList ret; uint32_t control_id; - count_existing_route_channels (existing_inputs, existing_outputs); - control_id = ntracks() + nbusses() + 1; bool const use_number = (how_many != 1); @@ -1814,8 +1781,6 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r << endmsg; goto failure; } - - auto_connect_route (bus.get(), existing_inputs, existing_outputs, false); } if (route_group) { @@ -1846,7 +1811,7 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r failure: if (!ret.empty()) { - add_routes (ret, true); + add_routes (ret, true, true); } return ret; @@ -1893,7 +1858,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template Track::zero_diskstream_id_in_xml (node_copy); try { - boost::shared_ptr route (XMLRouteFactory (node_copy, 3000)); + boost::shared_ptr route (XMLRouteFactory (node_copy, 3000)); if (route == 0) { error << _("Session: cannot create track/bus from template description") << endmsg; @@ -1936,18 +1901,23 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template out: if (!ret.empty()) { - add_routes (ret, true); + add_routes (ret, true, true); } return ret; } void -Session::add_routes (RouteList& new_routes, bool save) +Session::add_routes (RouteList& new_routes, bool auto_connect, bool save) { + ChanCount existing_inputs; + ChanCount existing_outputs; + + count_existing_track_channels (existing_inputs, existing_outputs); + { RCUWriter writer (routes); - boost::shared_ptr r = writer.get_copy (); + boost::shared_ptr r = writer.get_copy (); r->insert (r->end(), new_routes.begin(), new_routes.end()); @@ -1994,6 +1964,11 @@ Session::add_routes (RouteList& new_routes, bool save) mt->StepEditStatusChange.connect_same_thread (*this, boost::bind (&Session::step_edit_status_change, this, _1)); } } + + if (auto_connect) { + + auto_connect_route (r, existing_inputs, existing_outputs, true); + } } if (_monitor_out && IO::connecting_legal) { @@ -2110,7 +2085,7 @@ Session::remove_route (boost::shared_ptr route) { RCUWriter writer (routes); - boost::shared_ptr rs = writer.get_copy (); + boost::shared_ptr rs = writer.get_copy (); rs->remove (route); @@ -2163,7 +2138,7 @@ Session::remove_route (boost::shared_ptr route) } } - update_latency_compensation (false, false); + update_latency_compensation (); set_dirty(); /* Re-sort routes to remove the graph's current references to the one that is @@ -2242,23 +2217,23 @@ Session::route_solo_isolated_changed (void* /*src*/, boost::weak_ptr wpr) return; } - bool send_changed = false; - - if (route->solo_isolated()) { - if (_solo_isolated_cnt == 0) { - send_changed = true; - } - _solo_isolated_cnt++; - } else if (_solo_isolated_cnt > 0) { - _solo_isolated_cnt--; - if (_solo_isolated_cnt == 0) { - send_changed = true; - } - } + bool send_changed = false; - if (send_changed) { - IsolatedChanged (); /* EMIT SIGNAL */ - } + if (route->solo_isolated()) { + if (_solo_isolated_cnt == 0) { + send_changed = true; + } + _solo_isolated_cnt++; + } else if (_solo_isolated_cnt > 0) { + _solo_isolated_cnt--; + if (_solo_isolated_cnt == 0) { + send_changed = true; + } + } + + if (send_changed) { + IsolatedChanged (); /* EMIT SIGNAL */ + } } void @@ -2681,7 +2656,7 @@ Session::add_source (boost::shared_ptr source) } source->DropReferences.connect_same_thread (*this, boost::bind (&Session::remove_source, this, boost::weak_ptr (source))); - } + } } void @@ -3770,45 +3745,18 @@ BufferSet& Session::get_silent_buffers (ChanCount count) { return ProcessThread::get_silent_buffers (count); -#if 0 - assert(_silent_buffers->available() >= count); - _silent_buffers->set_count(count); - - for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { - for (size_t i= 0; i < count.get(*t); ++i) { - _silent_buffers->get(*t, i).clear(); - } - } - - return *_silent_buffers; -#endif } BufferSet& Session::get_scratch_buffers (ChanCount count) { return ProcessThread::get_scratch_buffers (count); -#if 0 - if (count != ChanCount::ZERO) { - assert(_scratch_buffers->available() >= count); - _scratch_buffers->set_count(count); - } else { - _scratch_buffers->set_count (_scratch_buffers->available()); - } - - return *_scratch_buffers; -#endif } BufferSet& Session::get_mix_buffers (ChanCount count) { return ProcessThread::get_mix_buffers (count); -#if 0 - assert(_mix_buffers->available() >= count); - _mix_buffers->set_count(count); - return *_mix_buffers; -#endif } uint32_t @@ -4180,7 +4128,7 @@ Session::ensure_search_path_includes (const string& path, DataType type) boost::shared_ptr Session::get_speakers() { - return _speakers; + return _speakers; } list @@ -4200,23 +4148,179 @@ Session::unknown_processors () const return p; } -#ifdef HAVE_JACK_NEW_LATENCY void Session::update_latency (bool playback) { - DEBUG_TRACE (DEBUG::Latency, "JACK latency callback\n"); + DEBUG_TRACE (DEBUG::Latency, string_compose ("JACK latency callback: %1\n", (playback ? "PLAYBACK" : "CAPTURE"))); + + if (_state_of_the_state & (InitialConnecting|Deletion)) { + return; + } boost::shared_ptr r = routes.reader (); + framecnt_t max_latency = 0; - if (playback) { - /* reverse the list so that we work backwards from the last route to run to the first */ - reverse (r->begin(), r->end()); - } + if (playback) { + /* reverse the list so that we work backwards from the last route to run to the first */ + reverse (r->begin(), r->end()); + } + + /* compute actual latency values for the given direction and store them all in per-port + structures. this will also publish the same values (to JACK) so that computation of latency + for routes can consistently use public latency values. + */ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - DEBUG_TRACE (DEBUG::Latency, string_compose ("------------- Working on latency for %1\n", (*i)->name())); - (*i)->set_latency_ranges (playback); - DEBUG_TRACE (DEBUG::Latency, string_compose ("------------- Done working on latency for %1\n\n", (*i)->name())); + max_latency = max (max_latency, (*i)->set_private_port_latencies (playback)); + } + + /* because we latency compensate playback, our published playback latencies should + be the same for all output ports - all material played back by ardour has + the same latency, whether its caused by plugins or by latency compensation. since + these may differ from the values computed above, reset all playback port latencies + to the same value. + */ + + DEBUG_TRACE (DEBUG::Latency, string_compose ("Set public port latencies to %1\n", max_latency)); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + (*i)->set_public_port_latencies (max_latency, playback); } + + if (playback) { + + post_playback_latency (); + + } else { + + post_capture_latency (); + } + + DEBUG_TRACE (DEBUG::Latency, "JACK latency callback: DONE\n"); } -#endif + +void +Session::post_playback_latency () +{ + set_worst_playback_latency (); + + boost::shared_ptr r = routes.reader (); + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if (!(*i)->is_hidden() && ((*i)->active())) { + _worst_track_latency = max (_worst_track_latency, (*i)->update_signal_latency ()); + } + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + (*i)->set_latency_compensation (_worst_track_latency); + } + } +} + +void +Session::post_capture_latency () +{ + set_worst_capture_latency (); + + /* reflect any changes in capture latencies into capture offsets + */ + + boost::shared_ptr rl = routes.reader(); + for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { + boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); + if (tr) { + tr->set_capture_offset (); + } + } +} + +void +Session::set_worst_io_latencies () +{ + set_worst_playback_latency (); + set_worst_capture_latency (); +} + +void +Session::set_worst_playback_latency () +{ + if (_state_of_the_state & (InitialConnecting|Deletion)) { + return; + } + + _worst_output_latency = 0; + + if (!_engine.connected()) { + return; + } + + boost::shared_ptr r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + _worst_output_latency = max (_worst_output_latency, (*i)->output()->latency()); + } + + DEBUG_TRACE (DEBUG::Latency, string_compose ("Worst output latency: %1\n", _worst_output_latency)); +} + +void +Session::set_worst_capture_latency () +{ + if (_state_of_the_state & (InitialConnecting|Deletion)) { + return; + } + + _worst_input_latency = 0; + + if (!_engine.connected()) { + return; + } + + boost::shared_ptr r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + _worst_input_latency = max (_worst_input_latency, (*i)->input()->latency()); + } + + DEBUG_TRACE (DEBUG::Latency, string_compose ("Worst input latency: %1\n", _worst_input_latency)); +} + +void +Session::update_latency_compensation (bool force_whole_graph) +{ + bool some_track_latency_changed = false; + + if (_state_of_the_state & (InitialConnecting|Deletion)) { + return; + } + + DEBUG_TRACE(DEBUG::Latency, "---------------------------- update latency compensation\n\n"); + + _worst_track_latency = 0; + + boost::shared_ptr r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if (!(*i)->is_hidden() && ((*i)->active())) { + framecnt_t tl; + if ((*i)->signal_latency () != (tl = (*i)->update_signal_latency ())) { + some_track_latency_changed = true; + } + _worst_track_latency = max (tl, _worst_track_latency); + } + } + + DEBUG_TRACE (DEBUG::Latency, string_compose ("worst signal processing latency: %1 (changed ? %2)\n", _worst_track_latency, + (some_track_latency_changed ? "yes" : "no"))); + + if (force_whole_graph || some_track_latency_changed) { + /* trigger a full recompute of latency numbers for the graph. + everything else that we need to do will be done in the latency + callback. + */ + _engine.update_total_latencies (); + return; // everything else will be done in the latency callback + } + + DEBUG_TRACE(DEBUG::Latency, "---------------------------- DONE update latency compensation\n\n") +} +