compensate for processor latency during bounce
[ardour.git] / libs / ardour / session.cc
index 05fa883a9d3b02343d8cec6553ad1f1893021e8d..bd33201199842e2c0c9a7b98244cd4e34c4965b1 100644 (file)
@@ -4133,6 +4133,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
        framepos_t position;
        framecnt_t this_chunk;
        framepos_t to_do;
+       framepos_t latency_skip;
        BufferSet buffers;
        SessionDirectory sdir(get_best_session_directory_for_new_source ());
        const string sound_dir = sdir.sound_path();
@@ -4153,6 +4154,16 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
 
        block_processing ();
 
+       {
+               // synchronize with AudioEngine::process_callback()
+               // make sure processing is not currently running
+               // and processing_blocked() is honored before
+               // acquiring thread buffers
+               Glib::Threads::Mutex::Lock lm (_engine.process_lock());
+       }
+
+       _engine.main_thread()->get_buffers ();
+
        /* call tree *MUST* hold route_lock */
 
        if ((playlist = track.playlist()) == 0) {
@@ -4198,9 +4209,12 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
 
        position = start;
        to_do = len;
+       latency_skip = track.bounce_get_latency (endpoint, include_endpoint, for_export);
 
        /* create a set of reasonably-sized buffers */
-       buffers.ensure_buffers (DataType::AUDIO, max_proc.n_audio(), chunk_size);
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               buffers.ensure_buffers(*t, max_proc.get(*t), chunk_size);
+       }
        buffers.set_count (max_proc);
 
        for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
@@ -4217,22 +4231,50 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
                        goto out;
                }
 
+               start += this_chunk;
+               to_do -= this_chunk;
+               itt.progress = (float) (1.0 - ((double) to_do / len));
+
+               if (latency_skip >= chunk_size) {
+                       latency_skip -= chunk_size;
+                       continue;
+               }
+
+               const framecnt_t current_chunk = this_chunk - latency_skip;
+
                uint32_t n = 0;
                for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) {
                        boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
 
                        if (afs) {
-                               if (afs->write (buffers.get_audio(n).data(), this_chunk) != this_chunk) {
+                               if (afs->write (buffers.get_audio(n).data(latency_skip), current_chunk) != current_chunk) {
                                        goto out;
                                }
                        }
                }
+               latency_skip = 0;
+       }
 
-               start += this_chunk;
-               to_do -= this_chunk;
+       /* post-roll, pick up delayed processor output */
+       latency_skip = track.bounce_get_latency (endpoint, include_endpoint, for_export);
 
-               itt.progress = (float) (1.0 - ((double) to_do / len));
+       while (latency_skip && !itt.cancel) {
+               this_chunk = min (latency_skip, chunk_size);
+               latency_skip -= this_chunk;
 
+               buffers.silence (this_chunk, 0);
+               track.bounce_process (buffers, start, this_chunk, endpoint, include_endpoint, for_export);
+
+               uint32_t n = 0;
+               for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) {
+                       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
+
+                       if (afs) {
+                               if (afs->write (buffers.get_audio(n).data(), this_chunk) != this_chunk) {
+                                       goto out;
+                               }
+                       }
+               }
        }
 
        if (!itt.cancel) {
@@ -4264,6 +4306,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
        }
 
   out:
+       _engine.main_thread()->drop_buffers ();
        if (!result) {
                for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
                        boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);