From ca84e02b48e0c36755963a35713d272c409d9317 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 18 Mar 2011 20:21:51 +0000 Subject: fix (?) capture alignment by making sure we use non-public latency information for playback latency, thus avoiding counting plugin latency twice git-svn-id: svn://localhost/ardour2/branches/3.0@9168 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/audioengine.h | 5 ++-- libs/ardour/ardour/delivery.h | 1 + libs/ardour/audio_diskstream.cc | 31 ++++++++------------- libs/ardour/audioengine.cc | 25 +++++++++++------ libs/ardour/delivery.cc | 17 ++++++++++++ libs/ardour/diskstream.cc | 37 ++++++++++--------------- libs/ardour/graph.cc | 6 +++- libs/ardour/io.cc | 4 +++ libs/ardour/port.cc | 59 ++++++++++++++++++++++++++++++---------- libs/ardour/session.cc | 27 +++++++++++++++--- 10 files changed, 141 insertions(+), 71 deletions(-) diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 8e68581e12..fa13fa827c 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -253,8 +253,9 @@ _ the regular process() call to session->process() is not made. */ PBD::Signal3 PortConnectedOrDisconnected; - std::string make_port_name_relative (std::string); - std::string make_port_name_non_relative (std::string); + std::string make_port_name_relative (std::string) const; + std::string make_port_name_non_relative (std::string) const; + bool port_is_mine (const std::string&) const; static AudioEngine* instance() { return _instance; } void died (); diff --git a/libs/ardour/ardour/delivery.h b/libs/ardour/ardour/delivery.h index cf6b0fe9ea..309eff8511 100644 --- a/libs/ardour/ardour/delivery.h +++ b/libs/ardour/ardour/delivery.h @@ -108,6 +108,7 @@ public: boost::shared_ptr _mute_master; bool no_panner_reset; boost::shared_ptr _panshell; + framecnt_t scnt; static bool panners_legal; static PBD::Signal0 PannersLegal; diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index abe75b6ea2..335e263898 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -441,16 +441,6 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca (*chan)->current_playback_buffer = 0; } - /* two conditions to test for here: - - A: this track is rec-enabled, and the session has confirmed that we can record - B: this track is rec-enabled, has been recording, and we are set up for auto-punch-in - - The second test is necessary to capture the extra material that arrives AFTER the transport - frame has left the punch range (which will cause the "can_record" argument to be false). - */ - - // Safeguard against situations where process() goes haywire when autopunching // and last_recordable_frame < first_recordable_frame @@ -458,14 +448,16 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca last_recordable_frame = max_framepos; } - OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes); - - calculate_record_range (ot, transport_frame, nframes, rec_nframes, rec_offset); + if (record_enabled()) { - if (rec_nframes && !was_recording) { - capture_captured = 0; - was_recording = true; - } + OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes); + calculate_record_range (ot, transport_frame, nframes, rec_nframes, rec_offset); + + if (rec_nframes && !was_recording) { + capture_captured = 0; + was_recording = true; + } + } if (can_record && !_last_capture_sources.empty()) { _last_capture_sources.clear (); @@ -1479,8 +1471,9 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo string region_name; RegionFactory::region_name (region_name, whole_file_region_name, false); - - // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add region " << region_name << endl; + + DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture start @ %2 length %3 add new region %4\n", + _name, (*ci)->start, (*ci)->frames, region_name)); try { diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 6067da55b7..1c74dd13c7 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -993,12 +993,10 @@ AudioEngine::get_port_by_name (const string& portname) } } - if (portname.find_first_of (':') != string::npos) { - if (portname.substr (0, jack_client_name.length ()) != jack_client_name) { - /* not an ardour: port */ - return 0; - } - } + if (!port_is_mine (portname)) { + /* not an ardour port */ + return 0; + } std::string const rel = make_port_name_relative (portname); @@ -1416,7 +1414,7 @@ AudioEngine::update_total_latencies () } string -AudioEngine::make_port_name_relative (string portname) +AudioEngine::make_port_name_relative (string portname) const { string::size_type len; string::size_type n; @@ -1437,7 +1435,7 @@ AudioEngine::make_port_name_relative (string portname) } string -AudioEngine::make_port_name_non_relative (string portname) +AudioEngine::make_port_name_non_relative (string portname) const { string str; @@ -1452,6 +1450,17 @@ AudioEngine::make_port_name_non_relative (string portname) return str; } +bool +AudioEngine::port_is_mine (const string& portname) const +{ + if (portname.find_first_of (':') != string::npos) { + if (portname.substr (0, jack_client_name.length ()) != jack_client_name) { + return false; + } + } + return true; +} + bool AudioEngine::is_realtime () const { diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc index dfc38d761d..efdb4d9ad0 100644 --- a/libs/ardour/delivery.cc +++ b/libs/ardour/delivery.cc @@ -62,6 +62,7 @@ Delivery::Delivery (Session& s, boost::shared_ptr io, boost::shared_ptr(new PannerShell (_name, _session, pannable)); _display_to_user = false; @@ -83,6 +84,7 @@ Delivery::Delivery (Session& s, boost::shared_ptr pannable, boost::sha , _no_outs_cuz_we_no_monitor (false) , _mute_master (mm) , no_panner_reset (false) + , scnt (0) { _panshell = boost::shared_ptr(new PannerShell (_name, _session, pannable)); _display_to_user = false; @@ -280,6 +282,21 @@ Delivery::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pf panner = _panshell->panner(); +#if 0 + if (_session.transport_rolling()) { + cerr << name() << " first value written : " << scnt << endl; + for (BufferSet::audio_iterator b = bufs.audio_begin(); b != bufs.audio_end(); ++b) { + Sample* p = b->data (); + float s = (float) scnt; + for (pframes_t n = 0; n < nframes; ++n) { + p[n] = s * 0.001; + s += 1.0; + } + } + scnt += nframes; + } +#endif + if (panner && !panner->bypassed()) { // Use the panner to distribute audio to output port buffers diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index affda7b56a..bba28eeacd 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -655,35 +655,26 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record) return; } - /* we transitioned to recording. lets see if its transport based or a punch */ - - first_recordable_frame = transport_frame + _capture_offset; - last_recordable_frame = max_framepos; capture_start_frame = _session.transport_frame(); + first_recordable_frame = capture_start_frame + _capture_offset; + last_recordable_frame = max_framepos; - /* in theory, we should be offsetting by _session.worst_playback_latency() when we adjust - for ExistingMaterial alignment. But that number includes the worst processor latency - across all routes, and each track will already be roll-delay adjusted to handle that. - so don't use worst_playback_latency(), just worst_output_latency() which covers - only downstream latency from IO ports. - */ - - DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 basic FRF = %2 CSF = %4 CO = %5, EMO = %6 RD = %8\n", + DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 (%9) FRF = %2 CSF = %4 CO = %5, EMO = %6 RD = %8 WOL %10 WTL %11\n", name(), first_recordable_frame, last_recordable_frame, capture_start_frame, _capture_offset, existing_material_offset, transport_frame, - _roll_delay)); + _roll_delay, + _session.transport_frame(), + _session.worst_output_latency(), + _session.worst_track_latency())); + if (_alignment_style == ExistingMaterial) { first_recordable_frame += existing_material_offset; DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tshift FRF by EMO %1\n", first_recordable_frame)); - } else { - capture_start_frame += _roll_delay; - DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tshift CFS by roll delay of %1 to %2\n", - _roll_delay, capture_start_frame)); - } + } prepare_record_status (capture_start_frame); @@ -703,13 +694,11 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record) } else { /* punch out */ - last_recordable_frame = transport_frame + _capture_offset; + last_recordable_frame = _session.transport_frame() + _capture_offset; if (_alignment_style == ExistingMaterial) { last_recordable_frame += existing_material_offset; - } else { - last_recordable_frame += _roll_delay; - } + } } } } @@ -766,6 +755,10 @@ Diskstream::calculate_record_range(OverlapType ot, framepos_t transport_frame, f rec_offset = first_recordable_frame - transport_frame; break; } + + DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 rec? %2 @ %3 (for %4) FRF %5 LRF %6 : rf %7 @ %8\n", + _name, enum_2_string (ot), transport_frame, nframes, + first_recordable_frame, last_recordable_frame, rec_nframes, rec_offset)); } void diff --git a/libs/ardour/graph.cc b/libs/ardour/graph.cc index f52180f98e..0403053bab 100644 --- a/libs/ardour/graph.cc +++ b/libs/ardour/graph.cc @@ -113,12 +113,16 @@ Graph::reset_thread_list () drop_threads (); } +#if 0 + /* XXX this only makes sense when we can use just the AudioEngine thread + and still keep the graph current with the route list + */ if (num_threads <= 1) { /* no point creating 1 thread - the AudioEngine already gives us one */ return; } - +#endif if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this), &a_thread, 100000) == 0) { _thread_list.push_back (a_thread); } diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index 27f8ca819d..55eaeb7a32 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -1156,6 +1156,10 @@ IO::latency () const for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) { if ((latency = i->private_latency_range (_direction == Output).max) > max_latency) { + DEBUG_TRACE (DEBUG::Latency, string_compose ("port %1 has %2 latency of %3 - use\n", + name(), + ((_direction == Output) ? "PLAYBACK" : "CAPTURE"), + latency)); max_latency = latency; } } diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index df1690da37..bc802aa81e 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -346,21 +346,50 @@ Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) c for (vector::const_iterator c = connections.begin(); c != connections.end(); ++c) { - jack_port_t* remote_port = jack_port_by_name (_engine->jack(), (*c).c_str()); - jack_latency_range_t lr; - - if (remote_port) { - jack_port_get_latency_range ( - remote_port, - (playback ? JackPlaybackLatency : JackCaptureLatency), - &lr); - - DEBUG_TRACE (DEBUG::Latency, string_compose ( - "\t%1 <-> %2 : latter has latency range %3 .. %4\n", - name(), *c, lr.min, lr.max)); - range.min = min (range.min, lr.min); - range.max = max (range.max, lr.max); - } + jack_latency_range_t lr; + + if (!AudioEngine::instance()->port_is_mine (*c)) { + + /* port belongs to some other JACK client, use + * JACK to lookup its latency information. + */ + + jack_port_t* remote_port = jack_port_by_name (_engine->jack(), (*c).c_str()); + + if (remote_port) { + jack_port_get_latency_range ( + remote_port, + (playback ? JackPlaybackLatency : JackCaptureLatency), + &lr); + + DEBUG_TRACE (DEBUG::Latency, string_compose ( + "\t%1 <-> %2 : latter has latency range %3 .. %4\n", + name(), *c, lr.min, lr.max)); + + range.min = min (range.min, lr.min); + range.max = max (range.max, lr.max); + } + + } else { + + /* port belongs to this instance of ardour, + so look up its latency information + internally, because our published/public + values already contain our plugin + latency compensation. + */ + + Port* remote_port = AudioEngine::instance()->get_port_by_name (*c); + if (remote_port) { + lr = remote_port->private_latency_range ((playback ? JackPlaybackLatency : JackCaptureLatency)); + DEBUG_TRACE (DEBUG::Latency, string_compose ( + "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n", + name(), *c, lr.min, lr.max)); + + range.min = min (range.min, lr.min); + range.max = max (range.max, lr.max); + } + } } } else { diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 19c7f5638f..84eb2bc2f2 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -1200,6 +1200,26 @@ Session::set_block_size (pframes_t nframes) struct RouteSorter { /** @return true to run r1 before r2, otherwise false */ + bool sort_by_rec_enabled (const boost::shared_ptr& r1, const boost::shared_ptr& r2) { + if (r1->record_enabled()) { + if (r2->record_enabled()) { + /* both rec-enabled, just use signal order */ + return r1->order_key(N_("signal")) < r2->order_key(N_("signal")); + } else { + /* r1 rec-enabled, r2 not rec-enabled, run r2 early */ + return false; + } + } else { + if (r2->record_enabled()) { + /* r2 rec-enabled, r1 not rec-enabled, run r1 early */ + return true; + } else { + /* neither rec-enabled, use signal order */ + return r1->order_key(N_("signal")) < r2->order_key(N_("signal")); + } + } + } + bool operator() (boost::shared_ptr r1, boost::shared_ptr r2) { if (r2->feeds (r1)) { /* r1 fed by r2; run r2 early */ @@ -1210,8 +1230,8 @@ struct RouteSorter { } else { if (r1->not_fed ()) { if (r2->not_fed ()) { - /* no ardour-based connections inbound to either route. just use signal order */ - return r1->order_key(N_("signal")) < r2->order_key(N_("signal")); + /* no ardour-based connections inbound to either route. */ + return sort_by_rec_enabled (r1, r2); } else { /* r2 has connections, r1 does not; run r1 early */ return true; @@ -1497,8 +1517,7 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m failed: if (!new_routes.empty()) { - add_routes (new_routes, true, false); - save_state (_current_snapshot_name); + add_routes (new_routes, true, true); } return ret; -- cgit v1.2.3