fix (?) capture alignment by making sure we use non-public latency information for...
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 18 Mar 2011 20:21:51 +0000 (20:21 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 18 Mar 2011 20:21:51 +0000 (20:21 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@9168 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/audioengine.h
libs/ardour/ardour/delivery.h
libs/ardour/audio_diskstream.cc
libs/ardour/audioengine.cc
libs/ardour/delivery.cc
libs/ardour/diskstream.cc
libs/ardour/graph.cc
libs/ardour/io.cc
libs/ardour/port.cc
libs/ardour/session.cc

index 8e68581e122db4d1e37fab79c1492bd331e66371..fa13fa827cffa3c6103afb3507079d9874f488a1 100644 (file)
@@ -253,8 +253,9 @@ _      the regular process() call to session->process() is not made.
         */
        PBD::Signal3<void, Port *, Port *, bool> 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 ();
index cf6b0fe9eaf327460a4e5ab22c68de834faa1f0d..309eff85111aad987d6e66c5cdb9a3eae24d51ed 100644 (file)
@@ -108,6 +108,7 @@ public:
        boost::shared_ptr<MuteMaster> _mute_master;
        bool         no_panner_reset;
        boost::shared_ptr<PannerShell> _panshell;
+        framecnt_t   scnt;
 
        static bool panners_legal;
        static PBD::Signal0<int>            PannersLegal;
index abe75b6ea274750940b2c65e39370f2070b288e5..335e263898b95696f2d8fc006ad5981b8692263d 100644 (file)
@@ -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 {
 
index 6067da55b7a53b76dfbfe04d7db3053ed785c5ef..1c74dd13c74214b1e26f92d308f7c0818d0cb036 100644 (file)
@@ -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
 {
index dfc38d761de36fa4ea6b9d301a7e4e85ddaeb436..efdb4d9ad0a354f4540a7c539727aacc916999dc 100644 (file)
@@ -62,6 +62,7 @@ Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<Pann
        , _no_outs_cuz_we_no_monitor (false)
        , _mute_master (mm)
        , no_panner_reset (false)
+        , scnt (0)
 {
        _panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable));
        _display_to_user = false;
@@ -83,6 +84,7 @@ Delivery::Delivery (Session& s, boost::shared_ptr<Pannable> pannable, boost::sha
        , _no_outs_cuz_we_no_monitor (false)
        , _mute_master (mm)
        , no_panner_reset (false)
+        , scnt (0)
 {
        _panshell = boost::shared_ptr<PannerShell>(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
index affda7b56af41aad06e21ccbcb25a6ef04562ede..bba28eeacd7dbf53b3df6f0e5231dfa887a84492 100644 (file)
@@ -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
index f52180f98e2914d98200311085b1305c985136a7..0403053babf67f7e324416a4aa82950ebc9c6779 100644 (file)
@@ -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);
        }
index 27f8ca819dcdca6889dc87082c364681545ad3c4..55eaeb7a3295e4bbd4a294a66f323f1b95370d3a 100644 (file)
@@ -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;
                }
        }
index df1690da37faff7ab2ee6a6130ae6de43020bfd8..bc802aa81e39373c3e0c2ed862ed5196fdfa5966 100644 (file)
@@ -346,21 +346,50 @@ Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) c
                for (vector<string>::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 {
index 19c7f5638f3bf9d76b139316b653c5611b0cc3dc..84eb2bc2f2d3a14b124c99426b01274a152db925 100644 (file)
@@ -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<Route>& r1, const boost::shared_ptr<Route>& 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<Route> r1, boost::shared_ptr<Route> 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;