correct comment
[ardour.git] / libs / ardour / session_export.cc
index 62eb61ab83e16654eb13890d2cddbcbe9e5feb50..879f34020af63004387fe0314a118004c9e54fc7 100644 (file)
@@ -31,7 +31,7 @@
 #include "ardour/session.h"
 #include "ardour/track.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
@@ -73,23 +73,27 @@ Session::pre_export ()
                }
        }
 
-       /* make sure we are actually rolling */
+       /* prepare transport */
+
+       realtime_stop (true, true);
 
        if (get_record_enabled()) {
                disable_record (false);
        }
 
+       unset_play_loop ();
+
        /* no slaving */
 
        post_export_sync = config.get_external_sync ();
-       post_export_position = _transport_frame;
+       post_export_position = _transport_sample;
 
        config.set_external_sync (false);
 
        _exporting = true;
-       export_status->running = true;
+       export_status->set_running (true);
        export_status->Finished.connect_same_thread (*this, boost::bind (&Session::finalize_audio_export, this));
-       
+
        /* disable MMC output early */
 
        _pre_export_mmc_enabled = _mmc->send_enabled ();
@@ -100,18 +104,34 @@ Session::pre_export ()
 
 /** Called for each range that is being exported */
 int
-Session::start_audio_export (framepos_t position)
+Session::start_audio_export (samplepos_t position, bool realtime, bool region_export)
 {
        if (!_exporting) {
                pre_export ();
        }
-       _export_started = false;
+
+       _realtime_export = realtime;
+       _region_export = region_export;
+
+       if (region_export) {
+               _export_preroll = 0;
+       }
+       else if (realtime) {
+               _export_preroll = nominal_sample_rate ();
+       } else {
+               _export_preroll = Config->get_export_preroll() * nominal_sample_rate ();
+       }
+
+       if (_export_preroll == 0) {
+               // must be > 0 so that transport is started in sync.
+               _export_preroll = 1;
+       }
 
        /* We're about to call Track::seek, so the butler must have finished everything
           up otherwise it could be doing do_refill in its thread while we are doing
           it here.
        */
-       
+
        _butler->wait_until_finished ();
 
        /* get everyone to the right position */
@@ -131,11 +151,17 @@ Session::start_audio_export (framepos_t position)
        }
 
        /* we just did the core part of a locate() call above, but
-          for the sake of any GUI, put the _transport_frame in
+          for the sake of any GUI, put the _transport_sample in
           the right place too.
        */
 
-       _transport_frame = position;
+       _transport_sample = position;
+
+       if (!region_export) {
+               _remaining_latency_preroll = worst_latency_preroll ();
+       } else {
+               _remaining_latency_preroll = 0;
+       }
        export_status->stop = false;
 
        /* get transport ready. note how this is calling butler functions
@@ -151,26 +177,45 @@ Session::start_audio_export (framepos_t position)
        }
 
        _engine.Freewheel.connect_same_thread (export_freewheel_connection, boost::bind (&Session::process_export_fw, this, _1));
-       _export_rolling = true;
-       return _engine.freewheel (true);
+
+       if (_realtime_export) {
+               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+               _export_rolling = true;
+               process_function = &Session::process_export_fw;
+               return 0;
+       } else {
+               _export_rolling = true;
+               return _engine.freewheel (true);
+       }
 }
 
-int
+void
 Session::process_export (pframes_t nframes)
 {
        if (_export_rolling && export_status->stop) {
                stop_audio_export ();
        }
 
-       if (_export_rolling) {
-               /* make sure we've caught up with disk i/o, since
-               we're running faster than realtime c/o JACK.
-               */
-               _butler->wait_until_finished ();
+       /* for Region Raw or Fades, we can skip this
+        * RegionExportChannelFactory::update_buffers() does not care
+        * about anything done here
+        */
+       if (!_region_export) {
+               if (_export_rolling) {
+                       if (!_realtime_export)  {
+                               /* make sure we've caught up with disk i/o, since
+                                * we're running faster than realtime c/o JACK.
+                                */
+                               _butler->wait_until_finished ();
+                       }
 
-               /* do the usual stuff */
+                       /* do the usual stuff */
 
-               process_without_events (nframes);
+                       process_without_events (nframes);
+
+               } else if (_realtime_export) {
+                       fail_roll (nframes); // somehow we need to silence _ALL_ output buffers
+               }
        }
 
        try {
@@ -181,29 +226,70 @@ Session::process_export (pframes_t nframes)
        } catch (std::exception & e) {
                error << string_compose (_("Export ended unexpectedly: %1"), e.what()) << endmsg;
                export_status->abort (true);
-               return -1;
        }
-
-       return 0;
 }
 
-int
+void
 Session::process_export_fw (pframes_t nframes)
 {
-       if (!_export_started) {
-               _export_started = true;
-               set_transport_speed (1.0, false);
+       const bool need_buffers = _engine.freewheeling ();
+       if (_export_preroll > 0) {
+
+               if (need_buffers) {
+                       _engine.main_thread()->get_buffers ();
+               }
+               fail_roll (nframes);
+               if (need_buffers) {
+                       _engine.main_thread()->drop_buffers ();
+               }
+
+               _export_preroll -= std::min ((samplepos_t)nframes, _export_preroll);
+
+               if (_export_preroll > 0) {
+                       // clear out buffers (reverb tails etc).
+                       return;
+               }
+
+               set_transport_speed (1.0, 0, false);
                butler_transport_work ();
                g_atomic_int_set (&_butler->should_do_transport_work, 0);
                post_transport ();
-               return 0;
+
+               return;
+       }
+
+       if (_remaining_latency_preroll > 0) {
+               samplepos_t remain = std::min ((samplepos_t)nframes, _remaining_latency_preroll);
+
+               if (need_buffers) {
+                       _engine.main_thread()->get_buffers ();
+               }
+
+               process_without_events (remain);
+
+               if (need_buffers) {
+                       _engine.main_thread()->drop_buffers ();
+               }
+
+               _remaining_latency_preroll -= remain;
+               _transport_sample -= remain;
+               nframes -= remain;
+
+               if (nframes == 0) {
+                       return;
+               }
+               _engine.split_cycle (remain);
+       }
+
+       if (need_buffers) {
+               _engine.main_thread()->get_buffers ();
        }
-       
-        _engine.main_thread()->get_buffers ();
        process_export (nframes);
-        _engine.main_thread()->drop_buffers ();
+       if (need_buffers) {
+               _engine.main_thread()->drop_buffers ();
+       }
 
-       return 0;
+       return;
 }
 
 int
@@ -232,10 +318,13 @@ Session::finalize_audio_export ()
 
        /* Clean up */
 
+       if (_realtime_export) {
+               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+               process_function = &Session::process_with_events;
+       }
        _engine.freewheel (false);
-
        export_freewheel_connection.disconnect();
-       
+
        _mmc->enable_send (_pre_export_mmc_enabled);
 
        /* maybe write CUE/TOC */