* Improved export error handling, streamlined ExportFailed
authorSakari Bergen <sakari.bergen@beatwaves.net>
Sun, 28 Sep 2008 11:11:38 +0000 (11:11 +0000)
committerSakari Bergen <sakari.bergen@beatwaves.net>
Sun, 28 Sep 2008 11:11:38 +0000 (11:11 +0000)
* Cleaned out export related visibility in Session, and simpified Session <--> export component communication in general
* Removed export_status.h header dependency from session.h
* Added check for libsndfile FLAC and Ogg Vorbis compatibility
* Added ExportFileFactory, leading in cleaner code in ExportProcessor, and better extensibility for possible future non-libsndfile formats

git-svn-id: svn://localhost/ardour2/branches/3.0@3818 d708f5d6-7413-0410-9779-e7cbd77b26cf

23 files changed:
gtk2_ardour/export_main_dialog.cc
gtk2_ardour/export_main_dialog.h
libs/ardour/ardour/export_channel_configuration.h
libs/ardour/ardour/export_failed.h
libs/ardour/ardour/export_file_io.h
libs/ardour/ardour/export_formats.h
libs/ardour/ardour/export_handler.h
libs/ardour/ardour/export_processor.h
libs/ardour/ardour/export_status.h
libs/ardour/ardour/export_timespan.h
libs/ardour/ardour/session.h
libs/ardour/export_channel_configuration.cc
libs/ardour/export_file_io.cc
libs/ardour/export_format_manager.cc
libs/ardour/export_formats.cc
libs/ardour/export_handler.cc
libs/ardour/export_multiplication.cc
libs/ardour/export_processor.cc
libs/ardour/export_profile_manager.cc
libs/ardour/export_status.cc
libs/ardour/export_timespan.cc
libs/ardour/export_utilities.cc
libs/ardour/session_export.cc

index 16a2b9e6e132c04d1cebcffac5243b4bbfe7970c..e653a48bf0151c82f7a9266acd159ffba8b00a93 100644 (file)
@@ -143,9 +143,6 @@ ExportMainDialog::ExportMainDialog (PublicEditor & editor) :
 
 ExportMainDialog::~ExportMainDialog ()
 {
-       if (session) {
-               session->release_export_handler();
-       }
 }
 
 void
@@ -156,6 +153,7 @@ ExportMainDialog::set_session (ARDOUR::Session* s)
        /* Init handler and profile manager */
        
        handler = session->get_export_handler ();
+       status = session->get_export_status ();
        profile_manager.reset (new ExportProfileManager (*session));
        
        /* Selection range  */
@@ -190,6 +188,7 @@ ExportMainDialog::set_session (ARDOUR::Session* s)
        
        timespan_selector.CriticalSelectionChanged.connect (sigc::mem_fun (*this, &ExportMainDialog::update_warnings));
        channel_selector.CriticalSelectionChanged.connect (sigc::mem_fun (*this, &ExportMainDialog::update_warnings));
+       status->Aborting.connect (sigc::mem_fun (*this, &ExportMainDialog::notify_errors));
        
        update_warnings ();
 }
@@ -202,12 +201,20 @@ ExportMainDialog::select_timespan (Glib::ustring id)
 }
 
 void
-ExportMainDialog::close_dialog ()
+ExportMainDialog::notify_errors ()
 {
-       ExportStatus & status = session->export_status;
+       if (status->errors()) {
+               Glib::ustring txt = _("Export has been aborted due to an error!\nSee the Log for details.");
+               Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
+               msg.run();
+       }
+}
 
-       if (status.running) {
-               status.abort();
+void
+ExportMainDialog::close_dialog ()
+{
+       if (status->running) {
+               status->abort();
        }
        
        hide_all ();
@@ -341,8 +348,7 @@ ExportMainDialog::export_fw ()
 void
 ExportMainDialog::show_progress ()
 {
-       ARDOUR::ExportStatus & status = session->export_status;
-       status.running = true;
+       status->running = true;
 
        cancel_button->set_label (_("Stop Export"));
        rt_export_button->set_sensitive (false);
@@ -355,7 +361,7 @@ ExportMainDialog::show_progress ()
        progress_connection = Glib::signal_timeout().connect (mem_fun(*this, &ExportMainDialog::progress_timeout), 100);
        
        gtk_main_iteration ();
-       while (status.running) {
+       while (status->running) {
                if (gtk_events_pending()) {
                        gtk_main_iteration ();
                } else {
@@ -377,30 +383,28 @@ ExportMainDialog::get_nth_format_name (uint32_t n)
 gint
 ExportMainDialog::progress_timeout ()
 {
-       ARDOUR::ExportStatus & status = session->export_status;
-
-       switch (status.stage) {
+       switch (status->stage) {
          case export_None:
                progress_label.set_text ("");
                break;
          case export_ReadTimespan:
-               progress_label.set_text (string_compose (_("Reading timespan %1 of %2"), status.timespan, status.total_timespans));
+               progress_label.set_text (string_compose (_("Reading timespan %1 of %2"), status->timespan, status->total_timespans));
                break;
          case export_PostProcess:
                progress_label.set_text (string_compose (_("Processing file %2 of %3 (%1) from timespan %4 of %5"),
-                                                        get_nth_format_name (status.format),
-                                                        status.format, status.total_formats,
-                                                        status.timespan, status.total_timespans));
+                                                        get_nth_format_name (status->format),
+                                                        status->format, status->total_formats,
+                                                        status->timespan, status->total_timespans));
                break;
          case export_Write:
                progress_label.set_text (string_compose (_("Encoding file %2 of %3 (%1) from timespan %4 of %5"),
-                                                        get_nth_format_name (status.format),
-                                                        status.format, status.total_formats,
-                                                        status.timespan, status.total_timespans));
+                                                        get_nth_format_name (status->format),
+                                                        status->format, status->total_formats,
+                                                        status->timespan, status->total_timespans));
                break;
        }
 
-       progress_bar.set_fraction (status.progress);
+       progress_bar.set_fraction (status->progress);
        return TRUE;
 }
 
index 9c4429856de5c78171d87cdcda04b458d959d825..e5788335156d93b7b1344c2aac62a8ef09cb3c52 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef __export_main_dialog_h__
 #define __export_main_dialog_h__
 
+#include <boost/shared_ptr.hpp>
+
 #include <ardour/export_handler.h>
 #include <ardour/export_profile_manager.h>
 
@@ -37,6 +39,7 @@ namespace ARDOUR {
        class ExportFilename;
        class ExportFormatSpecification;
        class ExportChannelConfiguration;
+       class ExportStatus;
 }
 
 class ExportTimespanSelector;
@@ -64,7 +67,8 @@ class ExportMainDialog : public ArdourDialog {
        };
 
   private:
-       
+
+       void notify_errors ();
        void close_dialog ();
        
        void sync_with_manager ();
@@ -82,6 +86,7 @@ class ExportMainDialog : public ArdourDialog {
        typedef boost::shared_ptr<ARDOUR::ExportHandler> HandlerPtr;
        typedef boost::shared_ptr<ARDOUR::ExportFormatSpecification> FormatPtr;
        typedef boost::shared_ptr<ARDOUR::ExportProfileManager> ManagerPtr;
+       typedef boost::shared_ptr<ARDOUR::ExportStatus> StatusPtr;
 
        void export_rt ();
        void export_fw ();
@@ -95,6 +100,7 @@ class ExportMainDialog : public ArdourDialog {
        PublicEditor &  editor;
        HandlerPtr      handler;
        ManagerPtr      profile_manager;
+       StatusPtr       status;
        
        /*** GUI components ***/
        
index 234cd5d127244cea4b1c3f18e0eca07141845482..80ad29b4353dae17bdc03e42d77e37bc59529d7c 100644 (file)
@@ -80,7 +80,7 @@ class ExportChannelConfiguration
 
   private:
        friend class ExportElementFactory;
-       ExportChannelConfiguration (ExportStatus & status, Session & session);
+       ExportChannelConfiguration (Session & session);
        
   public:
        XMLNode & get_state ();
@@ -115,6 +115,8 @@ class ExportChannelConfiguration
        
   private:
 
+       typedef boost::shared_ptr<ExportStatus> ExportStatusPtr;
+
         Session & session;
 
        // processor has to be prepared before doing this.
@@ -124,7 +126,7 @@ class ExportChannelConfiguration
        static void *  _write_files (void *arg);
        WriterThread    writer_thread;
        ProcessorPtr    processor;
-       ExportStatus &  status;
+       ExportStatusPtr status;
 
        bool            files_written;
 
index de00fba87e165cd6e8bbf00232d0f70cfa624e75..1b375f3cb82f5c5856cc03594be13942489e56ed 100644 (file)
@@ -35,9 +35,8 @@ namespace ARDOUR
 class ExportFailed : public std::exception
 {
   public:
-       ExportFailed (std::string const & reason, std::string const & description) :
-         reason (reason.c_str()),
-         description (description.c_str())
+       ExportFailed (std::string const & reason) :
+         reason (reason.c_str())
        {
                error << string_compose (_("Export failed: %1"), reason) << endmsg;
        }
@@ -46,13 +45,12 @@ class ExportFailed : public std::exception
        
        const char* what() const throw()
        {
-               return description;
+               return reason;
        }
        
   private:
 
        const char * reason;
-       const char * description;
 
 };
 
index e0b1c95323db5c3c87642a522de8bafa00ed4bd3..6705b7736a15cc135e56b79bfcb146d2c63f2e56 100644 (file)
 #ifndef __ardour_export_file_io_h__
 #define __ardour_export_file_io_h__
 
-#include <sndfile.h>
+#include <stdint.h>
+#include <utility>
+
+#include <boost/shared_ptr.hpp>
+#include <glibmm/ustring.h>
+#include <ardour/sndfile_helpers.h>
 
 #include <ardour/graph.h>
 #include <ardour/types.h>
 #include <ardour/ardour.h>
+#include <ardour/export_format_specification.h>
+#include <ardour/export_utilities.h>
+
+using Glib::ustring;
 
 namespace ARDOUR
 {
@@ -34,15 +43,16 @@ namespace ARDOUR
 class ExportFileWriter
 {
   public:
-       ExportFileWriter (string filename) : _filename (filename) {}
        virtual ~ExportFileWriter () {}
-       
+
        string filename () const { return _filename; }
        nframes_t position () const { return _position; }
        
        void set_position (nframes_t position) { _position = position; }
        
   protected:
+       ExportFileWriter (string filename) : _filename (filename) {}
+
        string _filename;
        nframes_t _position;
 };
@@ -51,12 +61,13 @@ class ExportFileWriter
 class SndfileWriterBase : public ExportFileWriter
 {
   public:
-       SndfileWriterBase (int channels, nframes_t samplerate, int format, string const & path);
-       virtual ~SndfileWriterBase ();
 
        SNDFILE * get_sndfile () const { return sndfile; }
 
   protected:
+       SndfileWriterBase (int channels, nframes_t samplerate, int format, string const & path);
+       virtual ~SndfileWriterBase ();
+
        SF_INFO        sf_info;
        SNDFILE *      sndfile;
 };
@@ -66,13 +77,17 @@ class SndfileWriterBase : public ExportFileWriter
 template <typename T>
 class SndfileWriter : public SndfileWriterBase, public GraphSink<T>
 {
-  public:
+  protected:
+       // Should only be created vie ExportFileFactory and derived classes
+       friend class ExportFileFactory;
        SndfileWriter (int channels, nframes_t samplerate, int format, string const & path);
-       virtual ~SndfileWriter () {}
-       
+
+  public:
        nframes_t write (T * data, nframes_t frames);
-       
+       virtual ~SndfileWriter () {}
+
   protected:
+
        sf_count_t (*write_func)(SNDFILE *, const T *, sf_count_t);
 
   private:
@@ -139,6 +154,25 @@ class ExportTempFile : public SndfileWriter<float>, public GraphSource<float>
        
 };
 
+class ExportFileFactory
+{
+  public:
+       typedef boost::shared_ptr<ExportFormatSpecification const> FormatPtr;
+       typedef GraphSink<float> FloatSink;
+       typedef boost::shared_ptr<FloatSink> FloatSinkPtr;
+       typedef boost::shared_ptr<ExportFileWriter> FileWriterPtr;
+       
+       typedef std::pair<FloatSinkPtr, FileWriterPtr> FilePair;
+
+       static FilePair create (FormatPtr format, uint32_t channels, ustring const & filename);
+       static bool check (FormatPtr format, uint32_t channels);
+
+  private:
+
+       static FilePair create_sndfile (FormatPtr format, unsigned int channels, ustring const & filename);
+       static bool check_sndfile (FormatPtr format, unsigned int channels);
+};
+
 } // namespace ARDOUR
 
 #endif /* __ardour_export_file_io_h__ */
index 558223d75ac676edd4b0a4370ecdb7cb95458a11..34227526fc7bb35331ed514e2903768c47bea05a 100644 (file)
@@ -170,6 +170,8 @@ class ExportFormatOggVorbis : public ExportFormat {
        ExportFormatOggVorbis ();
        ~ExportFormatOggVorbis () {};
        
+       static bool check_system_compatibility ();
+       
        bool set_compatibility_state (ExportFormatCompatibility const & compatibility);
        Type get_type () const { return T_Sndfile; }
        SampleFormat get_explicit_sample_format () const { return SF_Vorbis; }
@@ -181,6 +183,8 @@ class ExportFormatFLAC : public ExportFormat, public HasSampleFormat {
        ExportFormatFLAC ();
        ~ExportFormatFLAC () {};
        
+       static bool check_system_compatibility ();
+       
        bool set_compatibility_state (ExportFormatCompatibility const & compatibility);
        Type get_type () const { return T_Sndfile; }
        
index 99de563fa9bd7c7e6d6580d736b3c47ee7b8eea3..6142869fe0fc8273d24ceae1e6aa841ff60423c2 100644 (file)
@@ -93,6 +93,7 @@ class ExportHandler : public ExportElementFactory, public sigc::trackable
        typedef std::multimap<TimespanPtr, FileSpec> ConfigMap;
        
        typedef boost::shared_ptr<ExportProcessor> ProcessorPtr;
+       typedef boost::shared_ptr<ExportStatus> StatusPtr;
 
   private:
        /* Session::get_export_handler() should be used to obtain an export handler
@@ -112,6 +113,7 @@ class ExportHandler : public ExportElementFactory, public sigc::trackable
 
        Session &          session;
        ProcessorPtr       processor;
+       StatusPtr          export_status;
        ConfigMap          config_map;
        
        bool               realtime;
index fdb8213c68bad10c6fdbd6d993c9248f490b3797..5034831da4e8f8c7749e33b488718f7c00a5bbf0 100644 (file)
@@ -52,14 +52,6 @@ class ExportProcessor
        typedef boost::shared_ptr<Normalizer> NormalizerPtr;
        typedef boost::shared_ptr<ExportTempFile> TempFilePtr;
        
-       typedef boost::shared_ptr<SampleFormatConverter<short> > ShortConverterPtr;
-       typedef boost::shared_ptr<SampleFormatConverter<int> > IntConverterPtr;
-       typedef boost::shared_ptr<SampleFormatConverter<float> > FloatConverterPtr;
-       
-       typedef boost::shared_ptr<SndfileWriter<short> > ShortWriterPtr;
-       typedef boost::shared_ptr<SndfileWriter<int> > IntWriterPtr;
-       typedef boost::shared_ptr<SndfileWriter<float> > FloatWriterPtr;
-       
        typedef GraphSink<float> FloatSink;
        typedef boost::shared_ptr<FloatSink> FloatSinkPtr;
        typedef std::vector<FloatSinkPtr> FloatSinkVect;
@@ -96,10 +88,9 @@ class ExportProcessor
   private:
        
        void reset ();
-       FloatSinkPtr prepare_sndfile_writer (FormatPtr format, uint32_t channels, ustring const & filename);
        
-       Session &        session;
-       ExportStatus &   status;
+       Session &                       session;
+       boost::shared_ptr<ExportStatus> status;
        
        /* these are initalized in prepare() */
        
index 3ca5905a222698f3c2b7906a3fd16c830cbd1d99..88c2feb4937ad6556c36ee40569adedacec5656b 100644 (file)
@@ -47,8 +47,13 @@ struct ExportStatus {
        volatile bool           running;
        
        sigc::signal<void>      Aborting;
-       void abort () { _aborted = true; Aborting(); }
+       void abort (bool error_occurred = false);
        bool aborted () const { return _aborted; }
+       bool errors () const { return _errors; }
+       
+       sigc::signal<void>      Finished;
+       void finish ();
+       bool finished () const { return _aborted; }
        
        /* Progress info */
        
@@ -66,6 +71,9 @@ struct ExportStatus {
        
   private:
        volatile bool          _aborted;
+       volatile bool          _errors;
+       volatile bool          _finished;
+       
 };
 
 } // namespace ARDOUR
index 7995da36d2c30320c05a811806fac5c581f53332..e19013e822d72ded54fc1417bb020b441d5d0135 100644 (file)
@@ -43,10 +43,11 @@ class ExportTimespan : public sigc::trackable
        typedef boost::shared_ptr<ExportTempFile> TempFilePtr;
        typedef std::pair<ExportChannel const, TempFilePtr> ChannelFilePair;
        typedef std::map<ExportChannel const, TempFilePtr> TempFileMap;
+       typedef boost::shared_ptr<ExportStatus> ExportStatusPtr;
 
   private:
        friend class ExportElementFactory;
-       ExportTimespan (ExportStatus & status, nframes_t frame_rate);
+       ExportTimespan (ExportStatusPtr status, nframes_t frame_rate);
        
   public:
        ~ExportTimespan ();
@@ -78,7 +79,7 @@ class ExportTimespan : public sigc::trackable
 
   private:
 
-       ExportStatus & status;
+       ExportStatusPtr status;
 
        nframes_t      start_frame;
        nframes_t      end_frame;
index b6d8f1510145304ce1ca655d27920714e214b888..eef953ac2c982f25326dce0af4cbfd3c5ff593fd 100644 (file)
@@ -51,7 +51,6 @@
 
 #include <ardour/ardour.h>
 #include <ardour/configuration.h>
-#include <ardour/export_status.h>
 #include <ardour/location.h>
 #include <ardour/gain.h>
 #include <ardour/io.h>
@@ -111,6 +110,7 @@ class SMFSource;
 class SessionDirectory;
 class SessionMetadata;
 class ExportHandler;
+class ExportStatus;
 
 struct RouteGroup;
 
@@ -618,27 +618,14 @@ class Session : public PBD::StatefulDestructible
        bool sample_rate_convert (import_status&, string infile, string& outfile);
        string build_tmp_convert_name (string file);
 
-       /* Export stuff */
-
-       SlaveSource post_export_slave;
-       nframes_t post_export_position;
-
-       ExportStatus export_status;
-       
        boost::shared_ptr<ExportHandler> get_export_handler ();
-       void release_export_handler ();
+       boost::shared_ptr<ExportStatus> get_export_status ();
 
-       int  pre_export ();
-       int  start_audio_export (nframes_t position, bool realtime);
-       int  stop_audio_export ();
-       void finalize_audio_export ();
-       void abort_audio_export ();
+       int  start_audio_export (nframes_t position, bool realtime);    
 
        sigc::signal<int, nframes_t> ProcessExport;
-       sigc::signal<void> ExportFinished;
+       sigc::signal<void> ExportReadFinished;
        static sigc::signal<void, std::string, std::string> Exported;
-       sigc::connection export_freewheel_connection;
-       sigc::connection export_abort_connection;
 
        void add_source (boost::shared_ptr<Source>);
        void remove_source (boost::weak_ptr<Source>);
@@ -1080,9 +1067,21 @@ class Session : public PBD::StatefulDestructible
        bool follow_slave (nframes_t, nframes_t);
        void set_slave_source (SlaveSource);
 
+       SlaveSource post_export_slave;
+       nframes_t post_export_position;
+
        bool _exporting;
        bool _exporting_realtime;
+       
        boost::shared_ptr<ExportHandler> export_handler;
+       boost::shared_ptr<ExportStatus>  export_status;
+
+       int  pre_export ();
+       int  stop_audio_export ();
+       void finalize_audio_export ();
+       
+       sigc::connection export_freewheel_connection;
+       sigc::connection export_abort_connection;
 
        void prepare_diskstreams ();
        void commit_diskstreams (nframes_t, bool& session_requires_butler);
index 97b05c2f1eee17574670c972ab9498bc7308b578..e6eb84be0651a31e12a44eff2fd70dd8040a0229 100644 (file)
@@ -57,10 +57,10 @@ ExportChannel::read_ports (float * data, nframes_t frames) const
 
 /* ExportChannelConfiguration */
 
-ExportChannelConfiguration::ExportChannelConfiguration (ExportStatus & status,  Session & session) :
+ExportChannelConfiguration::ExportChannelConfiguration (Session & session) :
   session (session),
   writer_thread (*this),
-  status (status),
+  status (session.get_export_status ()),
   files_written (false),
   split (false)
 {
@@ -143,7 +143,7 @@ ExportChannelConfiguration::write_files (boost::shared_ptr<ExportProcessor> new_
        files_written = true;
 
        if (!timespan) {
-               throw ExportFailed (_("Export failed due to a programming error"), _("No timespan registered to channel configuration when requesting files to be written"));
+               throw ExportFailed (X_("Programming error: No timespan registered to channel configuration when requesting files to be written"));
        }
        
        /* Take a local copy of the processor to be used in the thread that is created below */
@@ -175,7 +175,7 @@ ExportChannelConfiguration::write_file ()
        uint32_t channel;
        
        do {
-               if (status.aborted()) { break; }
+               if (status->aborted()) { break; }
        
                channel = 0;
                for (ChannelList::iterator it = channels.begin(); it != channels.end(); ++it) {
@@ -194,7 +194,7 @@ ExportChannelConfiguration::write_file ()
                }
                
                progress += frames_read;
-               status.progress = (float) progress / timespan_length;
+               status->progress = (float) progress / timespan_length;
                
        } while (processor->process (file_buffer, frames_read) > 0);
        
@@ -211,14 +211,18 @@ ExportChannelConfiguration::_write_files (void *arg)
        // cc can be trated like 'this'
        WriterThread & cc (*((WriterThread *) arg));
        
-       for (FileConfigList::iterator it = cc->file_configs.begin(); it != cc->file_configs.end(); ++it) {
-               if (cc->status.aborted()) {
-                       break;
+       try {
+               for (FileConfigList::iterator it = cc->file_configs.begin(); it != cc->file_configs.end(); ++it) {
+                       if (cc->status->aborted()) {
+                               break;
+                       }
+                       cc->processor->prepare (it->first, it->second, cc->channels.size(), cc->split, cc->timespan->get_start());
+                       cc->write_file (); // Writes tempfile
+                       cc->processor->prepare_post_processors ();
+                       cc->processor->write_files();
                }
-               cc->processor->prepare (it->first, it->second, cc->channels.size(), cc->split, cc->timespan->get_start());
-               cc->write_file (); // Writes tempfile
-               cc->processor->prepare_post_processors ();
-               cc->processor->write_files();
+       } catch (ExportFailed & e) {
+               cc->status->abort (true);
        }
        
        cc.running = false;
index 7da6e8a60c881ab51cd71894276ef2eacaf825ec..d4aa1870baa57a2aaf71d7653b78f96f9c2991a0 100644 (file)
@@ -21,6 +21,7 @@
 #include <string.h>
 
 #include <ardour/export_file_io.h>
+
 #include <ardour/export_failed.h>
 #include <pbd/failed_constructor.h>
 
@@ -43,11 +44,11 @@ SndfileWriterBase::SndfileWriterBase (int channels, nframes_t samplerate, int fo
        sf_info.format = format;
        
        if (!sf_format_check (&sf_info)) {
-               throw ExportFailed (_("Export failed due to a programming error"), "Invalid format given for SndfileWriter!");
+               throw ExportFailed (X_("Invalid format given for SndfileWriter!"));
        }
        
        if (path.length() == 0) {
-               throw ExportFailed (_("Export failed due to a programming error"), "No output file specified for SndFileWriter");
+               throw ExportFailed (X_("No output file specified for SndFileWriter"));
        }
 
        /* TODO add checks that the directory path exists, and also 
@@ -58,13 +59,12 @@ SndfileWriterBase::SndfileWriterBase (int channels, nframes_t samplerate, int fo
        if (path.compare ("temp")) {
                if ((sndfile = sf_open (path.c_str(), SFM_WRITE, &sf_info)) == 0) {
                        sf_error_str (0, errbuf, sizeof (errbuf) - 1);
-                       throw ExportFailed (string_compose(_("Export: cannot open output file \"%1\""), path),
-                                           string_compose(_("Export: cannot open output file \"%1\" for SndFileWriter (%2)"), path, errbuf));
+                       throw ExportFailed (string_compose(X_("Cannot open output file \"%1\" for SndFileWriter (%2)"), path, errbuf));
                }
        } else {
                FILE * file;
                if (!(file = tmpfile ())) {
-                       throw ExportFailed (_("Export failed due to a programming error"), "Cannot open tempfile");
+                       throw ExportFailed (X_("Cannot open tempfile"));
                }
                sndfile = sf_open_fd (fileno(file), SFM_RDWR, &sf_info, true);
        }
@@ -114,7 +114,7 @@ SndfileWriter<T>::write (T * data, nframes_t frames)
        nframes_t written = (*write_func) (sndfile, data, frames);
        if (written != frames) {
                sf_error_str (sndfile, errbuf, sizeof (errbuf) - 1);
-               throw ExportFailed (_("Writing export file failed"), string_compose(_("Could not write data to output file (%1)"), errbuf));
+               throw ExportFailed (string_compose(_("Could not write data to output file (%1)"), errbuf));
        }
        
        if (GraphSink<T>::end_of_input) {
@@ -198,7 +198,7 @@ ExportTempFile::read (float * data, nframes_t frames)
        /* Check for errors */
        
        if (read_status != to_read) {
-               throw ExportFailed (_("Reading export file failed"), _("Error reading temporary export file, export might not be complete!"));
+               throw ExportFailed (X_("Error reading temporary export file, export might not be complete!"));
        }
        
        /* Add silence at end */
@@ -365,4 +365,82 @@ ExportTempFile::_read (float * data, nframes_t frames)
        return sf_readf_float (sndfile, data, frames);
 }
 
-};
+ExportFileFactory::FilePair
+ExportFileFactory::create (FormatPtr format, uint32_t channels, ustring const & filename)
+{
+       switch (format->type()) {
+         case ExportFormatBase::T_Sndfile:
+               return create_sndfile (format, channels, filename);
+
+         default:
+               throw ExportFailed (X_("Invalid format given for ExportFileFactory::create!"));
+       }
+}
+
+bool
+ExportFileFactory::check (FormatPtr format, uint32_t channels)
+{
+       switch (format->type()) {
+         case ExportFormatBase::T_Sndfile:
+               return check_sndfile (format, channels);
+
+         default:
+               throw ExportFailed (X_("Invalid format given for ExportFileFactory::check!"));
+       }
+}
+
+ExportFileFactory::FilePair
+ExportFileFactory::create_sndfile (FormatPtr format, unsigned int channels, ustring const & filename)
+{
+       typedef boost::shared_ptr<SampleFormatConverter<short> > ShortConverterPtr;
+       typedef boost::shared_ptr<SampleFormatConverter<int> > IntConverterPtr;
+       typedef boost::shared_ptr<SampleFormatConverter<float> > FloatConverterPtr;
+       
+       typedef boost::shared_ptr<SndfileWriter<short> > ShortWriterPtr;
+       typedef boost::shared_ptr<SndfileWriter<int> > IntWriterPtr;
+       typedef boost::shared_ptr<SndfileWriter<float> > FloatWriterPtr;
+       
+       FilePair ret;
+
+       int real_format = format->format_id() | format->sample_format() | format->endianness();
+
+       uint32_t data_width = sndfile_data_width (real_format);
+
+       if (data_width == 8 || data_width == 16) {
+       
+               ShortConverterPtr sfc = ShortConverterPtr (new SampleFormatConverter<short> (channels, format->dither_type(), data_width));
+               ShortWriterPtr sfw = ShortWriterPtr (new SndfileWriter<short> (channels, format->sample_rate(), real_format, filename));
+               sfc->pipe_to (sfw);
+               
+               return std::make_pair (boost::static_pointer_cast<FloatSink> (sfc), boost::static_pointer_cast<ExportFileWriter> (sfw));
+
+       } else if (data_width == 24 || data_width == 32) {
+       
+               IntConverterPtr sfc = IntConverterPtr (new SampleFormatConverter<int> (channels, format->dither_type(), data_width));
+               IntWriterPtr sfw = IntWriterPtr (new SndfileWriter<int> (channels, format->sample_rate(), real_format, filename));
+               sfc->pipe_to (sfw);
+               
+               return std::make_pair (boost::static_pointer_cast<FloatSink> (sfc), boost::static_pointer_cast<ExportFileWriter> (sfw));
+
+       } else {
+       
+               FloatConverterPtr sfc = FloatConverterPtr (new SampleFormatConverter<float> (channels, format->dither_type(), data_width));
+               FloatWriterPtr sfw = FloatWriterPtr (new SndfileWriter<float> (channels, format->sample_rate(), real_format, filename));
+               sfc->pipe_to (sfw);
+               
+               return std::make_pair (boost::static_pointer_cast<FloatSink> (sfc), boost::static_pointer_cast<ExportFileWriter> (sfw));;
+       }
+}
+
+bool
+ExportFileFactory::check_sndfile (FormatPtr format, unsigned int channels)
+{
+       SF_INFO sf_info;
+       sf_info.channels = channels;
+       sf_info.samplerate = format->sample_rate ();
+       sf_info.format = format->format_id () | format->sample_format ();
+
+       return (sf_format_check (&sf_info) == SF_TRUE ? true : false);
+}
+
+} // namespace ARDOUR
index e9e722dfeccf93a7936df3e1e8646e0353a7c2a1..a1d1b726296248d77551a0a07c965e44fdf82a89 100644 (file)
@@ -185,11 +185,15 @@ ExportFormatManager::init_formats ()
        fl_ptr->set_extension ("raw");
        add_format (f_ptr);
        
-       f_ptr.reset (new ExportFormatOggVorbis ());
-       add_format (f_ptr);
+       if (ExportFormatOggVorbis::check_system_compatibility()) {
+               f_ptr.reset (new ExportFormatOggVorbis ());
+               add_format (f_ptr);
+       }
        
-       f_ptr.reset (new ExportFormatFLAC ());
-       add_format (f_ptr);
+       if (ExportFormatFLAC::check_system_compatibility()) {
+               f_ptr.reset (new ExportFormatFLAC ());
+               add_format (f_ptr);
+       }
 }
 
 void
index 7df54bad1c76f806349768412f89de354eddb1a6..f3c8f7197c31e0c4c225c48496af94f32a103f00 100644 (file)
@@ -251,6 +251,17 @@ ExportFormatOggVorbis::ExportFormatOggVorbis ()
        set_quality (Q_LossyCompression);
 }
 
+bool
+ExportFormatOggVorbis::check_system_compatibility ()
+{
+       SF_INFO sf_info;
+       sf_info.channels = 2;
+       sf_info.samplerate = SR_44_1;
+       sf_info.format = F_Ogg | SF_Vorbis;
+
+       return (sf_format_check (&sf_info) == SF_TRUE ? true : false);
+}
+
 bool
 ExportFormatOggVorbis::set_compatibility_state (ExportFormatCompatibility const & compatibility)
 {
@@ -284,6 +295,17 @@ ExportFormatFLAC::ExportFormatFLAC () :
        set_quality (Q_LosslessCompression);
 }
 
+bool
+ExportFormatFLAC::check_system_compatibility ()
+{
+       SF_INFO sf_info;
+       sf_info.channels = 2;
+       sf_info.samplerate = SR_44_1;
+       sf_info.format = F_FLAC | SF_16;
+
+       return (sf_format_check (&sf_info) == SF_TRUE ? true : false);
+}
+
 bool
 ExportFormatFLAC::set_compatibility_state (ExportFormatCompatibility const & compatibility)
 {
index 0e22fdad27b9418c2f6eae07518dfbacf4a690e9..ba26821a5b831b86fe65245887ee35001b5257ba 100644 (file)
@@ -55,13 +55,13 @@ ExportElementFactory::~ExportElementFactory ()
 ExportElementFactory::TimespanPtr
 ExportElementFactory::add_timespan ()
 {
-       return TimespanPtr (new ExportTimespan (session.export_status, session.frame_rate()));
+       return TimespanPtr (new ExportTimespan (session.get_export_status(), session.frame_rate()));
 }
 
 ExportElementFactory::ChannelConfigPtr
 ExportElementFactory::add_channel_config ()
 {
-       return ChannelConfigPtr (new ExportChannelConfiguration (session.export_status, session));
+       return ChannelConfigPtr (new ExportChannelConfiguration (session));
 }
 
 ExportElementFactory::FormatPtr
@@ -99,6 +99,7 @@ ExportElementFactory::add_filename_copy (FilenamePtr other)
 ExportHandler::ExportHandler (Session & session) :
   ExportElementFactory (session),
   session (session),
+  export_status (session.get_export_status ()),
   realtime (false)
 {
        processor.reset (new ExportProcessor (session));
@@ -108,7 +109,7 @@ ExportHandler::ExportHandler (Session & session) :
 
 ExportHandler::~ExportHandler ()
 {
-       if (session.export_status.aborted()) {
+       if (export_status->aborted()) {
                for (std::list<Glib::ustring>::iterator it = files_written.begin(); it != files_written.end(); ++it) {
                        sys::remove (sys::path (*it));
                }
@@ -133,7 +134,7 @@ ExportHandler::add_export_config (TimespanPtr timespan, ChannelConfigPtr channel
  * 1. Session is prepared in do_export
  * 2. start_timespan is called, which then registers all necessary channel configs to a timespan
  * 3. The timespan reads each unique channel into a tempfile and calls Session::stop_export when the end is reached
- * 4. stop_export emits ExportFinished after stopping the transport, this ends up calling finish_timespan
+ * 4. stop_export emits ExportReadFinished after stopping the transport, this ends up calling finish_timespan
  * 5. finish_timespan registers all the relevant formats and filenames to relevant channel configurations
  * 6. finish_timespan does a manual call to timespan_thread_finished, which gets the next channel configuration
  *    for the current timespan, calling write_files for it
@@ -148,20 +149,18 @@ ExportHandler::do_export (bool rt)
 {
        /* Count timespans */
 
-       ExportStatus & status = session.export_status;
-       status.init();
+       export_status->init();
        std::set<TimespanPtr> timespan_set;
        for (ConfigMap::iterator it = config_map.begin(); it != config_map.end(); ++it) {
                timespan_set.insert (it->first);
        }
-       status.total_timespans = timespan_set.size();
+       export_status->total_timespans = timespan_set.size();
 
        /* Start export */
 
        realtime = rt;
 
-       session.ExportFinished.connect (sigc::mem_fun (*this, &ExportHandler::finish_timespan));
-       session.pre_export ();
+       session.ExportReadFinished.connect (sigc::mem_fun (*this, &ExportHandler::finish_timespan));
        start_timespan ();
 }
 
@@ -442,10 +441,10 @@ ExportHandler::frames_to_cd_frames_string (char* buf, nframes_t when)
 void
 ExportHandler::start_timespan ()
 {
-       session.export_status.timespan++;
+       export_status->timespan++;
 
        if (config_map.empty()) {
-               session.finalize_audio_export();
+               export_status->finish ();
                return;
        }
 
@@ -472,12 +471,12 @@ ExportHandler::finish_timespan ()
        
        /* Register formats and filenames to relevant channel configs */
        
-       session.export_status.total_formats = 0;
-       session.export_status.format = 0;
+       export_status->total_formats = 0;
+       export_status->format = 0;
        
        for (ConfigMap::iterator it = timespan_bounds.first; it != timespan_bounds.second; ++it) {
        
-               session.export_status.total_formats++;
+               export_status->total_formats++;
        
                /* Setup filename */
                
index da10d54eaa05f6992ac8e5aa4928b613ad372408..943ca5a17268490404ddc81f351a715a136f4e0b 100644 (file)
@@ -19,7 +19,7 @@ ExportProfileManager::register_all_configs ()
        
                TimespanNodePtr ts_node;
                if (!(ts_node = boost::dynamic_pointer_cast<TimespanNode> (*tsl_it))) {
-                       throw ExportFailed (_("Export failed due to a programming error"), "Invalid pointer cast in ExportProfileManager");
+                       throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
                }
        
                TimespanListPtr ts_list = ts_node->data()->timespans;
@@ -30,19 +30,19 @@ ExportProfileManager::register_all_configs ()
                        
                        ChannelConfigNode * cc_node;
                        if (!(cc_node = dynamic_cast<ChannelConfigNode *> (*cc_it))) {
-                               throw ExportFailed (_("Export failed due to a programming error"), "Invalid pointer cast in ExportProfileManager");
+                               throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
                        }
                        ChannelConfigPtr channel_config = cc_node->data()->config;
                        
                        FormatNode * f_node;
                        if (!(f_node = dynamic_cast<FormatNode *> (*f_it))) {
-                               throw ExportFailed (_("Export failed due to a programming error"), "Invalid pointer cast in ExportProfileManager");
+                               throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
                        }
                        FormatPtr format = f_node->data()->format;
                        
                        FilenameNode * fn_node;
                        if (!(fn_node = dynamic_cast<FilenameNode *> (*fn_it))) {
-                               throw ExportFailed (_("Export failed due to a programming error"), "Invalid pointer cast in ExportProfileManager");
+                               throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
                        }
                        FilenamePtr filename = fn_node->data()->filename;
                        
@@ -443,7 +443,7 @@ ExportProfileManager::duplicate_timespan_children (TimespanNodePtr source, Times
        ChannelConfigNode * node_insertion_ptr;
        if (!insertion_point) { insertion_point = source->last_child(); }
        if (!(node_insertion_ptr = dynamic_cast<ChannelConfigNode *> (insertion_point))) {
-               throw ExportFailed (_("Export failed due to a programming error"), "Invalid pointer cast in ExportProfileManager");
+               throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
        }
        node_insertion_point = node_insertion_ptr->self_ptr();
        
@@ -460,7 +460,7 @@ ExportProfileManager::duplicate_timespan_children (TimespanNodePtr source, Times
                ChannelConfigNodePtr new_node;
                
                if (!(node = dynamic_cast<ChannelConfigNode *> (*it))) {
-                       throw ExportFailed (_("Export failed due to a programming error"), "Invalid pointer cast in ExportProfileManager");
+                       throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
                }
                
                new_node = duplicate_channel_config_node (node->self_ptr());
@@ -509,7 +509,7 @@ ExportProfileManager::duplicate_channel_config_children (ChannelConfigNodePtr so
        FormatNode * node_insertion_ptr;
        if (!insertion_point) { insertion_point = source->last_child(); }
        if (!(node_insertion_ptr = dynamic_cast<FormatNode *> (insertion_point))) {
-               throw ExportFailed (_("Export failed due to a programming error"), "Invalid pointer cast in ExportProfileManager");
+               throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
        }
        node_insertion_point = node_insertion_ptr->self_ptr();
 
@@ -526,7 +526,7 @@ ExportProfileManager::duplicate_channel_config_children (ChannelConfigNodePtr so
                FormatNodePtr new_node;
                
                if (!(node = dynamic_cast<FormatNode *> (*it))) {
-                       throw ExportFailed (_("Export failed due to a programming error"), "Invalid pointer cast in ExportProfileManager");
+                       throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
                }
                
                new_node = duplicate_format_node (node->self_ptr());
@@ -573,7 +573,7 @@ ExportProfileManager::duplicate_format_children (FormatNodePtr source, FormatNod
        FilenameNode * node_insertion_ptr;
        if (!insertion_point) { insertion_point = source->last_child(); }
        if (!(node_insertion_ptr = dynamic_cast<FilenameNode *> (insertion_point))) {
-               throw ExportFailed (_("Export failed due to a programming error"), "Invalid pointer cast in ExportProfileManager");
+               throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
        }
        node_insertion_point = node_insertion_ptr->self_ptr();
 
@@ -584,7 +584,7 @@ ExportProfileManager::duplicate_format_children (FormatNodePtr source, FormatNod
                FilenameNodePtr new_node;
                
                if (!(node = dynamic_cast<FilenameNode *> (*it))) {
-                       throw ExportFailed (_("Export failed due to a programming error"), "Invalid pointer cast in ExportProfileManager");
+                       throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
                }
                
                new_node = duplicate_filename_node (node->self_ptr());
index 87f1772c90f7e2998c1e098571dc39780c1142bc..8659514dbfe7f5af3e84f9caa9f0157583572d46 100644 (file)
@@ -30,7 +30,6 @@
 #include <ardour/export_filename.h>
 #include <ardour/export_status.h>
 #include <ardour/export_format_specification.h>
-#include <ardour/sndfile_helpers.h>
 
 #include "i18n.h"
 
@@ -43,7 +42,7 @@ sigc::signal<void, Glib::ustring> ExportProcessor::WritingFile;
 
 ExportProcessor::ExportProcessor (Session & session) :
   session (session),
-  status (session.export_status),
+  status (session.get_export_status()),
   blocksize (session.get_block_size()),
   frame_rate (session.frame_rate())
 {
@@ -70,7 +69,7 @@ ExportProcessor::reset ()
 int
 ExportProcessor::prepare (FormatPtr format, FilenamePtr fname, uint32_t chans, bool split, nframes_t start)
 {
-       session.export_status.format++;
+       status->format++;
        temp_file_length = 0;
 
        /* Reset just to be sure all references are dropped */
@@ -96,7 +95,7 @@ ExportProcessor::prepare (FormatPtr format, FilenamePtr fname, uint32_t chans, b
        
        /* Construct export pipe to temp file */
        
-       status.stage = export_PostProcess;
+       status->stage = export_PostProcess;
        
        if (normalize) {
                /* Normalizing => we need a normalizer, peak reader and tempfile */
@@ -122,27 +121,12 @@ ExportProcessor::prepare (FormatPtr format, FilenamePtr fname, uint32_t chans, b
                src->pipe_to (temp_file);
        }
 
-       /* File writer(s) */
-       
-       FloatSinkPtr (ExportProcessor::*prep_function) (FormatPtr, uint32_t, ustring const &);
-       
-       switch (format->type()) {
-         case ExportFormatBase::T_Sndfile:
-               prep_function = &ExportProcessor::prepare_sndfile_writer;
-               break;
-
-         default:
-               throw ExportFailed (_("Export failed due to a programming error"), "Invalid format given for ExportProcessor::prepare!");
-               break;
-       
-       }
-       
        /* Ensure directory exists */
        
        sys::path folder (filename->get_folder());
        if (!sys::exists (folder)) {
                if (!sys::create_directory (folder)) {
-                       throw ExportFailed ("Export could not create the directory you requested for", "sys::create_directory failed for export dir");
+                       throw ExportFailed (X_("sys::create_directory failed for export dir"));
                }
        }
        
@@ -152,12 +136,16 @@ ExportProcessor::prepare (FormatPtr format, FilenamePtr fname, uint32_t chans, b
                filename->include_channel = true;
                for (uint32_t chn = 1; chn <= channels; ++chn) {
                        filename->set_channel (chn);
-                       file_sinks.push_back ((this->*prep_function) (format, 1, filename->get_path (format)));
+                       ExportFileFactory::FilePair pair = ExportFileFactory::create (format, 1, filename->get_path (format));
+                       file_sinks.push_back (pair.first);
+                       writer_list.push_back (pair.second);
                        WritingFile (filename->get_path (format));
                }
 
        } else {
-               file_sinks.push_back ((this->*prep_function) (format, channels, filename->get_path (format)));
+               ExportFileFactory::FilePair pair = ExportFileFactory::create (format, channels, filename->get_path (format));
+               file_sinks.push_back (pair.first);
+               writer_list.push_back (pair.second);
                WritingFile (filename->get_path (format));
        }
        
@@ -229,7 +217,7 @@ ExportProcessor::write_files ()
 {
        /* Write to disk */
        
-       status.stage = export_Write;
+       status->stage = export_Write;
        temp_file_position = 0;
        
        uint32_t buffer_size = 4096; // TODO adjust buffer size?
@@ -270,9 +258,9 @@ ExportProcessor::write_files ()
                                disk_sink->write (chan_bufs[channel], frames_read);
                        }
                        
-                       if (status.aborted()) { break; }
+                       if (status->aborted()) { break; }
                        temp_file_position += frames_read;
-                       status.progress = (float) temp_file_position / temp_file_length;
+                       status->progress = (float) temp_file_position / temp_file_length;
                }
                
                /* Clean up */
@@ -285,9 +273,9 @@ ExportProcessor::write_files ()
                while ((frames_read = temp_file->read (buf, buffer_size)) > 0) {
                        disk_sink->write (buf, frames_read);
                        
-                       if (status.aborted()) { break; }
+                       if (status->aborted()) { break; }
                        temp_file_position += frames_read;
-                       status.progress = (float) temp_file_position / temp_file_length;
+                       status->progress = (float) temp_file_position / temp_file_length;
                }
        }
        
@@ -304,44 +292,4 @@ ExportProcessor::write_files ()
        }
 }
 
-ExportProcessor::FloatSinkPtr
-ExportProcessor::prepare_sndfile_writer (FormatPtr format, uint32_t channels, ustring const & filename)
-{
-       int real_format = format->format_id() | format->sample_format() | format->endianness();
-
-       uint32_t data_width = sndfile_data_width (real_format);
-
-       if (data_width == 8 || data_width == 16) {
-       
-               ShortConverterPtr sfc = ShortConverterPtr (new SampleFormatConverter<short> (channels, format->dither_type(), data_width));
-               ShortWriterPtr sfw = ShortWriterPtr (new SndfileWriter<short> (channels, format->sample_rate(), real_format, filename));
-               
-               writer_list.push_back (boost::static_pointer_cast<ExportFileWriter> (sfw));
-               
-               sfc->pipe_to (sfw);
-               return boost::static_pointer_cast<FloatSink> (sfc);
-
-       } else if (data_width == 24 || data_width == 32) {
-       
-               IntConverterPtr sfc = IntConverterPtr (new SampleFormatConverter<int> (channels, format->dither_type(), data_width));
-               IntWriterPtr sfw = IntWriterPtr (new SndfileWriter<int> (channels, format->sample_rate(), real_format, filename));
-               
-               writer_list.push_back (boost::static_pointer_cast<ExportFileWriter> (sfw));
-               
-               sfc->pipe_to (sfw);
-               return boost::static_pointer_cast<FloatSink> (sfc);
-
-       } else {
-       
-               FloatConverterPtr sfc = FloatConverterPtr (new SampleFormatConverter<float> (channels, format->dither_type(), data_width));
-               FloatWriterPtr sfw = FloatWriterPtr (new SndfileWriter<float> (channels, format->sample_rate(), real_format, filename));
-               
-               writer_list.push_back (boost::static_pointer_cast<ExportFileWriter> (sfw));
-               
-               sfc->pipe_to (sfw);
-               return boost::static_pointer_cast<FloatSink> (sfc);
-       }
-
-}
-
 }; // namespace ARDOUR
index e9edf5feef1042f04a044a4c91949f04e388f20c..dee9a9a991c7513b9c0b1b2f198618b81c8403e6 100644 (file)
@@ -30,6 +30,7 @@
 #include <pbd/convert.h>
 
 #include <ardour/export_failed.h>
+#include <ardour/export_file_io.h>
 #include <ardour/export_format_specification.h>
 #include <ardour/export_timespan.h>
 #include <ardour/export_channel_configuration.h>
@@ -691,6 +692,8 @@ ExportProfileManager::check_config (boost::shared_ptr<Warnings> warnings,
        /* Check format and maximum channel count */
        if (!format || !format->type()) {
                warnings->errors.push_back (_("No format selected!"));
+       } else if (!ExportFileFactory::check (format, channel_config->get_n_chans())) {
+               warnings->errors.push_back (_("One or more of the selected formats is not compatible with this system!"));
        } else if (format->channel_limit() < channel_config->get_n_chans()) {
                warnings->errors.push_back
                  (string_compose (_("%1 supports only %2 channels, but you have %3 channels in your channel configuration"),
index c64a03fe23776ce5ecfc10549b26e935ba59de6f..a31e66dc398e1f8a29f5a14024e08d5b25125363 100644 (file)
@@ -34,6 +34,8 @@ ExportStatus::init ()
        stop = false;
        running = false;
        _aborted = false;
+       _finished = false;
+       _errors = false;
        
        stage = export_None;
        progress = 0.0;
@@ -48,4 +50,20 @@ ExportStatus::init ()
        format = 0;
 }
 
+void
+ExportStatus::abort (bool error_occurred)
+{
+       _aborted = true;
+       _finished = true;
+       _errors = _errors || error_occurred;
+       Aborting ();
+}
+
+void
+ExportStatus::finish ()
+{
+       _finished = true;
+       Finished();
+}
+
 } // namespace ARDOUR
index 14273d835f2d8b4b2e119e5e3c259da3e750e0fa..d6996a5a48e3e619053f8fa8778ef335b10ffb77 100644 (file)
@@ -28,7 +28,7 @@
 namespace ARDOUR
 {
 
-ExportTimespan::ExportTimespan (ExportStatus & status, nframes_t frame_rate) :
+ExportTimespan::ExportTimespan (ExportStatusPtr status, nframes_t frame_rate) :
   status (status),
   start_frame (0),
   end_frame (0),
@@ -62,7 +62,7 @@ ExportTimespan::get_data (float * data, nframes_t frames, ExportChannel const &
 {
        TempFileMap::iterator it = filemap.find (channel);
        if (it == filemap.end()) {
-               throw ExportFailed (_("Export failed due to programming error"), _("Trying to get data from ExportTimespan for channel that was never registered!"));
+               throw ExportFailed (X_("Trying to get data from ExportTimespan for channel that was never registered!"));
        }
        
        return it->second->read (data, frames);
@@ -79,7 +79,7 @@ ExportTimespan::set_range (nframes_t start, nframes_t end)
 int
 ExportTimespan::process (nframes_t frames)
 {
-       status.stage = export_ReadTimespan;
+       status->stage = export_ReadTimespan;
 
        /* update position */
 
@@ -89,11 +89,11 @@ ExportTimespan::process (nframes_t frames)
                frames_to_read = frames;
        } else {
                frames_to_read = end_frame - position;
-               status.stop = true;
+               status->stop = true;
        }
        
        position += frames_to_read;
-       status.progress = (float) (position - start_frame) / (end_frame - start_frame);
+       status->progress = (float) (position - start_frame) / (end_frame - start_frame);
 
        /* Read channels from ports and save to tempfiles */
 
index 64fa62ded5df91cec2c7d381e1e5f6df2a930199..a9223e2e1b5d9ac0783d913e8b598e211c81b9db 100644 (file)
@@ -70,7 +70,7 @@ SampleRateConverter::SampleRateConverter (uint32_t channels, nframes_t in_rate,
        int err;
 
        if ((src_state = src_new (quality, channels, &err)) == 0) {
-               throw ExportFailed (string_compose (_("cannot initialize sample rate conversion: %1"), src_strerror (err)), "Cannot initialize sample rate conversion");
+               throw ExportFailed (string_compose (X_("Cannot initialize sample rate conversion: %1"), src_strerror (err)));
        }
        
        src_data.src_ratio = out_rate / (double) in_rate;
@@ -109,7 +109,7 @@ SampleRateConverter::process (float * data, nframes_t frames)
                max_leftover_frames = 4 * frames;
                leftover_data = (float *) realloc (leftover_data, max_leftover_frames * channels * sizeof (float));
                if (!leftover_data) {
-                       throw ExportFailed (_("A memory allocation error occured during sample rate conversion"), "Samplerate conversion failed");
+                       throw ExportFailed (X_("A memory allocation error occured during sample rate conversion"));
                }
                
                data_out_size = out_samples_max;
@@ -161,7 +161,7 @@ SampleRateConverter::process (float * data, nframes_t frames)
                ++cnt;
 
                if ((err = src_process (src_state, &src_data)) != 0) {
-                       throw ExportFailed (_("an error occured during sample rate conversion"), string_compose ("an error occured during sample rate conversion: %1", src_strerror (err)));
+                       throw ExportFailed (string_compose ("An error occured during sample rate conversion: %1", src_strerror (err)));
                }
        
                frames_out = src_data.output_frames_gen;
index aed32e278b61edf9db9558dfa54781611a88076a..3ddceb6b00bce5de374d308f4d09d492afffa181 100644 (file)
@@ -26,6 +26,7 @@
 #include <ardour/export_file_io.h>
 #include <ardour/export_utilities.h>
 #include <ardour/export_handler.h>
+#include <ardour/export_status.h>
 #include <ardour/timestamps.h>
 #include <ardour/ardour.h>
 #include <ardour/session.h>
@@ -49,17 +50,20 @@ Session::get_export_handler ()
        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 ()
 {
+       get_export_status (); // Init export_status
 
        wait_till_butler_finished ();
 
@@ -87,8 +91,8 @@ Session::pre_export ()
        Config->set_slave_source (None);
        
        _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_abort_connection = export_status->Aborting.connect (sigc::hide_return (sigc::mem_fun (*this, &Session::stop_audio_export)));
 
        return 0;
 }
@@ -96,6 +100,10 @@ Session::pre_export ()
 int
 Session::start_audio_export (nframes_t position, bool realtime)
 {
+       if (!_exporting) {
+               pre_export ();
+       }
+
        /* get everyone to the right position */
 
        {
@@ -119,7 +127,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
@@ -154,7 +162,7 @@ Session::process_export (nframes_t nframes)
 {
        try {
 
-               if (export_status.stop) {
+               if (export_status->stop) {
                        stop_audio_export ();
                        return;
                }
@@ -176,11 +184,7 @@ Session::process_export (nframes_t nframes)
                ProcessExport (nframes);
 
        } catch (ExportFailed e) {
-
-               std::cerr << e.what() << std::endl;
-               stop_audio_export();
-               finalize_audio_export();
-
+               export_status->abort (true);
        }
 }
 
@@ -208,8 +212,12 @@ Session::stop_audio_export ()
        realtime_stop (true);
        schedule_butler_transport_work ();
 
-       if (!export_status.aborted()) {
-               ExportFinished ();
+       if (!export_status->aborted()) {
+               ExportReadFinished ();
+       }
+       
+       if (export_status->finished()) {
+               finalize_audio_export ();
        }
        
        return 0;
@@ -220,7 +228,7 @@ void
 Session::finalize_audio_export ()
 {
        _exporting = false;
-       export_status.running = false;
+       export_status->running = false;
 
        if (!_exporting_realtime) {
                _engine.freewheel (false);
@@ -230,10 +238,11 @@ Session::finalize_audio_export ()
        /* Clean up */
        
        ProcessExport.clear();
-       ExportFinished.clear();
+       ExportReadFinished.clear();
        export_freewheel_connection.disconnect();
        export_abort_connection.disconnect();
        export_handler.reset();
+       export_status.reset();
 
        /* restart slaving */
 
@@ -243,10 +252,3 @@ Session::finalize_audio_export ()
                locate (post_export_position, false, false, false);
        }
 }
-
-void
-Session::abort_audio_export ()
-{
-       stop_audio_export ();
-       finalize_audio_export ();
-}