NOOP, remove trailing tabs/whitespace.
[ardour.git] / libs / ardour / session_export.cc
index aed32e278b61edf9db9558dfa54781611a88076a..ea4a07dd1f66cd883a0aa4a4ba1f87d9d1cc92eb 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 1999-2008 Paul Davis 
+    Copyright (C) 1999-2008 Paul Davis
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 
 */
 
-#include <sigc++/bind.h>
 
-#include <pbd/error.h>
-#include <glibmm/thread.h>
+#include "pbd/error.h"
+#include <glibmm/threads.h>
 
-#include <ardour/export_failed.h>
-#include <ardour/export_file_io.h>
-#include <ardour/export_utilities.h>
-#include <ardour/export_handler.h>
-#include <ardour/timestamps.h>
-#include <ardour/ardour.h>
-#include <ardour/session.h>
-#include <ardour/audioengine.h>
-#include <ardour/audio_diskstream.h>
-#include <ardour/panner.h>
+#include <midi++/mmc.h>
+
+#include "ardour/audioengine.h"
+#include "ardour/butler.h"
+#include "ardour/export_handler.h"
+#include "ardour/export_status.h"
+#include "ardour/process_thread.h"
+#include "ardour/session.h"
+#include "ardour/track.h"
 
 #include "i18n.h"
 
@@ -45,23 +43,25 @@ Session::get_export_handler ()
        if (!export_handler) {
                export_handler.reset (new ExportHandler (*this));
        }
-       
+
        return export_handler;
 }
 
-void
-Session::release_export_handler ()
+boost::shared_ptr<ExportStatus>
+Session::get_export_status ()
 {
-       if (!_exporting) {
-               export_handler.reset();
+       if (!export_status) {
+               export_status.reset (new ExportStatus ());
        }
+
+       return export_status;
 }
 
+
 int
 Session::pre_export ()
 {
-
-       wait_till_butler_finished ();
+       get_export_status (); // Init export_status
 
        /* take everyone out of awrite to avoid disasters */
 
@@ -81,28 +81,47 @@ Session::pre_export ()
 
        /* no slaving */
 
-       post_export_slave = Config->get_slave_source ();
+       post_export_sync = config.get_external_sync ();
        post_export_position = _transport_frame;
 
-       Config->set_slave_source (None);
-       
+       config.set_external_sync (false);
+
        _exporting = true;
-       export_status.running = true;
-       export_abort_connection = export_status.Aborting.connect (sigc::mem_fun (*this, &Session::abort_audio_export));
+       export_status->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 ();
+       _mmc->enable_send (false);
 
        return 0;
 }
 
+/** Called for each range that is being exported */
 int
-Session::start_audio_export (nframes_t position, bool realtime)
+Session::start_audio_export (framepos_t position)
 {
+       if (!_exporting) {
+               pre_export ();
+       }
+       _export_started = false;
+
+       /* 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 */
 
        {
-               boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
+               boost::shared_ptr<RouteList> rl = routes.reader();
 
-               for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-                       if ((*i)-> seek (position, true)) {
+               for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                       boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+                       if (tr && tr->seek (position, true)) {
                                error << string_compose (_("%1: cannot seek to %2 for export"),
                                                  (*i)->name(), position)
                                      << endmsg;
@@ -117,9 +136,7 @@ Session::start_audio_export (nframes_t position, bool realtime)
        */
 
        _transport_frame = position;
-       
-       _exporting_realtime = realtime;
-       export_status.stop = false;
+       export_status->stop = false;
 
        /* get transport ready. note how this is calling butler functions
           from a non-butler thread. we waited for the butler to stop
@@ -127,126 +144,110 @@ Session::start_audio_export (nframes_t position, bool realtime)
           since then has re-awakened it.
         */
 
-       set_transport_speed (1.0, false);
-       butler_transport_work ();
-       g_atomic_int_set (&butler_should_do_transport_work, 0);
-       post_transport ();
-
        /* we are ready to go ... */
-       
+
        if (!_engine.connected()) {
                return -1;
        }
 
-       if (realtime) {
-               last_process_function = process_function;
-               process_function = &Session::process_export;
-       } else {
-               export_freewheel_connection = _engine.Freewheel.connect (sigc::mem_fun (*this, &Session::process_export_fw));
-               return _engine.freewheel (true);
-       }
-
-       return 0;
+       _engine.Freewheel.connect_same_thread (export_freewheel_connection, boost::bind (&Session::process_export_fw, this, _1));
+       _export_rolling = true;
+       return _engine.freewheel (true);
 }
 
-void
-Session::process_export (nframes_t nframes)
+int
+Session::process_export (pframes_t nframes)
 {
-       try {
+       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 ();
 
-               if (export_status.stop) {
-                       stop_audio_export ();
-                       return;
-               }
-       
-               if (!_exporting_realtime) {
-                       /* make sure we've caught up with disk i/o, since
-                       we're running faster than realtime c/o JACK.
-                       */
-                       
-                       wait_till_butler_finished ();
-               }
-       
                /* do the usual stuff */
-       
+
                process_without_events (nframes);
-       
-               /* handle export */
-       
-               ProcessExport (nframes);
+       }
 
-       } catch (ExportFailed e) {
+       try {
+               /* handle export - XXX what about error handling? */
 
-               std::cerr << e.what() << std::endl;
-               stop_audio_export();
-               finalize_audio_export();
+               ProcessExport (nframes);
 
+       } catch (std::exception & e) {
+               error << string_compose (_("Export ended unexpectedly: %1"), e.what()) << endmsg;
+               export_status->abort (true);
+               return -1;
        }
+
+       return 0;
 }
 
 int
-Session::process_export_fw (nframes_t nframes)
+Session::process_export_fw (pframes_t nframes)
 {
-       process_export (nframes);       
+       if (!_export_started) {
+               _export_started = true;
+               set_transport_speed (1.0, 0, false);
+               butler_transport_work ();
+               g_atomic_int_set (&_butler->should_do_transport_work, 0);
+               post_transport ();
+               return 0;
+       }
+
+        _engine.main_thread()->get_buffers ();
+       process_export (nframes);
+        _engine.main_thread()->drop_buffers ();
+
        return 0;
 }
 
 int
 Session::stop_audio_export ()
 {
-       if (_exporting_realtime) {
-               process_function = last_process_function;
-       } else {
-               export_freewheel_connection.disconnect();
-       }
-
        /* can't use stop_transport() here because we need
           an immediate halt and don't require all the declick
           stuff that stop_transport() implements.
        */
 
-       realtime_stop (true);
-       schedule_butler_transport_work ();
+       realtime_stop (true, true);
+       _export_rolling = false;
+       _butler->schedule_transport_work ();
 
-       if (!export_status.aborted()) {
-               ExportFinished ();
-       }
-       
        return 0;
-
 }
 
 void
 Session::finalize_audio_export ()
 {
        _exporting = false;
-       export_status.running = false;
 
-       if (!_exporting_realtime) {
-               _engine.freewheel (false);
-               _exporting_realtime = false;
+       if (_export_rolling) {
+               stop_audio_export ();
        }
 
        /* Clean up */
-       
-       ProcessExport.clear();
-       ExportFinished.clear();
+
+       _engine.freewheel (false);
+
        export_freewheel_connection.disconnect();
-       export_abort_connection.disconnect();
+
+       _mmc->enable_send (_pre_export_mmc_enabled);
+
+       /* maybe write CUE/TOC */
+
        export_handler.reset();
+       export_status.reset();
 
        /* restart slaving */
 
-       if (post_export_slave != None) {
-               Config->set_slave_source (post_export_slave);
+       if (post_export_sync) {
+               config.set_external_sync (true);
        } else {
-               locate (post_export_position, false, false, false);
+               locate (post_export_position, false, false, false, false, false);
        }
 }
-
-void
-Session::abort_audio_export ()
-{
-       stop_audio_export ();
-       finalize_audio_export ();
-}