From 6b50ba341da426805ce3c92609c0fa12c52b67ac Mon Sep 17 00:00:00 2001 From: Sakari Bergen Date: Sun, 28 Sep 2008 11:11:38 +0000 Subject: [PATCH] * Improved export error handling, streamlined ExportFailed * 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 --- gtk2_ardour/export_main_dialog.cc | 46 ++++----- gtk2_ardour/export_main_dialog.h | 8 +- .../ardour/export_channel_configuration.h | 6 +- libs/ardour/ardour/export_failed.h | 8 +- libs/ardour/ardour/export_file_io.h | 52 ++++++++-- libs/ardour/ardour/export_formats.h | 4 + libs/ardour/ardour/export_handler.h | 2 + libs/ardour/ardour/export_processor.h | 13 +-- libs/ardour/ardour/export_status.h | 10 +- libs/ardour/ardour/export_timespan.h | 5 +- libs/ardour/ardour/session.h | 33 ++++--- libs/ardour/export_channel_configuration.cc | 28 +++--- libs/ardour/export_file_io.cc | 94 +++++++++++++++++-- libs/ardour/export_format_manager.cc | 12 ++- libs/ardour/export_formats.cc | 22 +++++ libs/ardour/export_handler.cc | 27 +++--- libs/ardour/export_multiplication.cc | 20 ++-- libs/ardour/export_processor.cc | 82 +++------------- libs/ardour/export_profile_manager.cc | 3 + libs/ardour/export_status.cc | 18 ++++ libs/ardour/export_timespan.cc | 10 +- libs/ardour/export_utilities.cc | 6 +- libs/ardour/session_export.cc | 50 +++++----- 23 files changed, 343 insertions(+), 216 deletions(-) diff --git a/gtk2_ardour/export_main_dialog.cc b/gtk2_ardour/export_main_dialog.cc index 16a2b9e6e1..e653a48bf0 100644 --- a/gtk2_ardour/export_main_dialog.cc +++ b/gtk2_ardour/export_main_dialog.cc @@ -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; } diff --git a/gtk2_ardour/export_main_dialog.h b/gtk2_ardour/export_main_dialog.h index 9c4429856d..e578833515 100644 --- a/gtk2_ardour/export_main_dialog.h +++ b/gtk2_ardour/export_main_dialog.h @@ -21,6 +21,8 @@ #ifndef __export_main_dialog_h__ #define __export_main_dialog_h__ +#include + #include #include @@ -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 HandlerPtr; typedef boost::shared_ptr FormatPtr; typedef boost::shared_ptr ManagerPtr; + typedef boost::shared_ptr 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 ***/ diff --git a/libs/ardour/ardour/export_channel_configuration.h b/libs/ardour/ardour/export_channel_configuration.h index 234cd5d127..80ad29b435 100644 --- a/libs/ardour/ardour/export_channel_configuration.h +++ b/libs/ardour/ardour/export_channel_configuration.h @@ -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 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; diff --git a/libs/ardour/ardour/export_failed.h b/libs/ardour/ardour/export_failed.h index de00fba87e..1b375f3cb8 100644 --- a/libs/ardour/ardour/export_failed.h +++ b/libs/ardour/ardour/export_failed.h @@ -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; }; diff --git a/libs/ardour/ardour/export_file_io.h b/libs/ardour/ardour/export_file_io.h index e0b1c95323..6705b7736a 100644 --- a/libs/ardour/ardour/export_file_io.h +++ b/libs/ardour/ardour/export_file_io.h @@ -21,11 +21,20 @@ #ifndef __ardour_export_file_io_h__ #define __ardour_export_file_io_h__ -#include +#include +#include + +#include +#include +#include #include #include #include +#include +#include + +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 class SndfileWriter : public SndfileWriterBase, public GraphSink { - 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, public GraphSource }; +class ExportFileFactory +{ + public: + typedef boost::shared_ptr FormatPtr; + typedef GraphSink FloatSink; + typedef boost::shared_ptr FloatSinkPtr; + typedef boost::shared_ptr FileWriterPtr; + + typedef std::pair 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__ */ diff --git a/libs/ardour/ardour/export_formats.h b/libs/ardour/ardour/export_formats.h index 558223d75a..34227526fc 100644 --- a/libs/ardour/ardour/export_formats.h +++ b/libs/ardour/ardour/export_formats.h @@ -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; } diff --git a/libs/ardour/ardour/export_handler.h b/libs/ardour/ardour/export_handler.h index 99de563fa9..6142869fe0 100644 --- a/libs/ardour/ardour/export_handler.h +++ b/libs/ardour/ardour/export_handler.h @@ -93,6 +93,7 @@ class ExportHandler : public ExportElementFactory, public sigc::trackable typedef std::multimap ConfigMap; typedef boost::shared_ptr ProcessorPtr; + typedef boost::shared_ptr 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; diff --git a/libs/ardour/ardour/export_processor.h b/libs/ardour/ardour/export_processor.h index fdb8213c68..5034831da4 100644 --- a/libs/ardour/ardour/export_processor.h +++ b/libs/ardour/ardour/export_processor.h @@ -52,14 +52,6 @@ class ExportProcessor typedef boost::shared_ptr NormalizerPtr; typedef boost::shared_ptr TempFilePtr; - typedef boost::shared_ptr > ShortConverterPtr; - typedef boost::shared_ptr > IntConverterPtr; - typedef boost::shared_ptr > FloatConverterPtr; - - typedef boost::shared_ptr > ShortWriterPtr; - typedef boost::shared_ptr > IntWriterPtr; - typedef boost::shared_ptr > FloatWriterPtr; - typedef GraphSink FloatSink; typedef boost::shared_ptr FloatSinkPtr; typedef std::vector 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 status; /* these are initalized in prepare() */ diff --git a/libs/ardour/ardour/export_status.h b/libs/ardour/ardour/export_status.h index 3ca5905a22..88c2feb493 100644 --- a/libs/ardour/ardour/export_status.h +++ b/libs/ardour/ardour/export_status.h @@ -47,8 +47,13 @@ struct ExportStatus { volatile bool running; sigc::signal Aborting; - void abort () { _aborted = true; Aborting(); } + void abort (bool error_occurred = false); bool aborted () const { return _aborted; } + bool errors () const { return _errors; } + + sigc::signal 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 diff --git a/libs/ardour/ardour/export_timespan.h b/libs/ardour/ardour/export_timespan.h index 7995da36d2..e19013e822 100644 --- a/libs/ardour/ardour/export_timespan.h +++ b/libs/ardour/ardour/export_timespan.h @@ -43,10 +43,11 @@ class ExportTimespan : public sigc::trackable typedef boost::shared_ptr TempFilePtr; typedef std::pair ChannelFilePair; typedef std::map TempFileMap; + typedef boost::shared_ptr 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; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index b6d8f15101..eef953ac2c 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -51,7 +51,6 @@ #include #include -#include #include #include #include @@ -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 get_export_handler (); - void release_export_handler (); + boost::shared_ptr 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 ProcessExport; - sigc::signal ExportFinished; + sigc::signal ExportReadFinished; static sigc::signal Exported; - sigc::connection export_freewheel_connection; - sigc::connection export_abort_connection; void add_source (boost::shared_ptr); void remove_source (boost::weak_ptr); @@ -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 export_handler; + boost::shared_ptr 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); diff --git a/libs/ardour/export_channel_configuration.cc b/libs/ardour/export_channel_configuration.cc index 97b05c2f1e..e6eb84be06 100644 --- a/libs/ardour/export_channel_configuration.cc +++ b/libs/ardour/export_channel_configuration.cc @@ -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 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; diff --git a/libs/ardour/export_file_io.cc b/libs/ardour/export_file_io.cc index 7da6e8a60c..d4aa1870ba 100644 --- a/libs/ardour/export_file_io.cc +++ b/libs/ardour/export_file_io.cc @@ -21,6 +21,7 @@ #include #include + #include #include @@ -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::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::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 > ShortConverterPtr; + typedef boost::shared_ptr > IntConverterPtr; + typedef boost::shared_ptr > FloatConverterPtr; + + typedef boost::shared_ptr > ShortWriterPtr; + typedef boost::shared_ptr > IntWriterPtr; + typedef boost::shared_ptr > 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 (channels, format->dither_type(), data_width)); + ShortWriterPtr sfw = ShortWriterPtr (new SndfileWriter (channels, format->sample_rate(), real_format, filename)); + sfc->pipe_to (sfw); + + return std::make_pair (boost::static_pointer_cast (sfc), boost::static_pointer_cast (sfw)); + + } else if (data_width == 24 || data_width == 32) { + + IntConverterPtr sfc = IntConverterPtr (new SampleFormatConverter (channels, format->dither_type(), data_width)); + IntWriterPtr sfw = IntWriterPtr (new SndfileWriter (channels, format->sample_rate(), real_format, filename)); + sfc->pipe_to (sfw); + + return std::make_pair (boost::static_pointer_cast (sfc), boost::static_pointer_cast (sfw)); + + } else { + + FloatConverterPtr sfc = FloatConverterPtr (new SampleFormatConverter (channels, format->dither_type(), data_width)); + FloatWriterPtr sfw = FloatWriterPtr (new SndfileWriter (channels, format->sample_rate(), real_format, filename)); + sfc->pipe_to (sfw); + + return std::make_pair (boost::static_pointer_cast (sfc), boost::static_pointer_cast (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 diff --git a/libs/ardour/export_format_manager.cc b/libs/ardour/export_format_manager.cc index e9e722dfec..a1d1b72629 100644 --- a/libs/ardour/export_format_manager.cc +++ b/libs/ardour/export_format_manager.cc @@ -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 diff --git a/libs/ardour/export_formats.cc b/libs/ardour/export_formats.cc index 7df54bad1c..f3c8f7197c 100644 --- a/libs/ardour/export_formats.cc +++ b/libs/ardour/export_formats.cc @@ -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) { diff --git a/libs/ardour/export_handler.cc b/libs/ardour/export_handler.cc index 0e22fdad27..ba26821a5b 100644 --- a/libs/ardour/export_handler.cc +++ b/libs/ardour/export_handler.cc @@ -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::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 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 */ diff --git a/libs/ardour/export_multiplication.cc b/libs/ardour/export_multiplication.cc index da10d54eaa..943ca5a172 100644 --- a/libs/ardour/export_multiplication.cc +++ b/libs/ardour/export_multiplication.cc @@ -19,7 +19,7 @@ ExportProfileManager::register_all_configs () TimespanNodePtr ts_node; if (!(ts_node = boost::dynamic_pointer_cast (*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 (*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 (*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 (*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 (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 (*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 (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 (*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 (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 (*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()); diff --git a/libs/ardour/export_processor.cc b/libs/ardour/export_processor.cc index 87f1772c90..8659514dbf 100644 --- a/libs/ardour/export_processor.cc +++ b/libs/ardour/export_processor.cc @@ -30,7 +30,6 @@ #include #include #include -#include #include "i18n.h" @@ -43,7 +42,7 @@ sigc::signal 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 (channels, format->dither_type(), data_width)); - ShortWriterPtr sfw = ShortWriterPtr (new SndfileWriter (channels, format->sample_rate(), real_format, filename)); - - writer_list.push_back (boost::static_pointer_cast (sfw)); - - sfc->pipe_to (sfw); - return boost::static_pointer_cast (sfc); - - } else if (data_width == 24 || data_width == 32) { - - IntConverterPtr sfc = IntConverterPtr (new SampleFormatConverter (channels, format->dither_type(), data_width)); - IntWriterPtr sfw = IntWriterPtr (new SndfileWriter (channels, format->sample_rate(), real_format, filename)); - - writer_list.push_back (boost::static_pointer_cast (sfw)); - - sfc->pipe_to (sfw); - return boost::static_pointer_cast (sfc); - - } else { - - FloatConverterPtr sfc = FloatConverterPtr (new SampleFormatConverter (channels, format->dither_type(), data_width)); - FloatWriterPtr sfw = FloatWriterPtr (new SndfileWriter (channels, format->sample_rate(), real_format, filename)); - - writer_list.push_back (boost::static_pointer_cast (sfw)); - - sfc->pipe_to (sfw); - return boost::static_pointer_cast (sfc); - } - -} - }; // namespace ARDOUR diff --git a/libs/ardour/export_profile_manager.cc b/libs/ardour/export_profile_manager.cc index e9edf5feef..dee9a9a991 100644 --- a/libs/ardour/export_profile_manager.cc +++ b/libs/ardour/export_profile_manager.cc @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -691,6 +692,8 @@ ExportProfileManager::check_config (boost::shared_ptr 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"), diff --git a/libs/ardour/export_status.cc b/libs/ardour/export_status.cc index c64a03fe23..a31e66dc39 100644 --- a/libs/ardour/export_status.cc +++ b/libs/ardour/export_status.cc @@ -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 diff --git a/libs/ardour/export_timespan.cc b/libs/ardour/export_timespan.cc index 14273d835f..d6996a5a48 100644 --- a/libs/ardour/export_timespan.cc +++ b/libs/ardour/export_timespan.cc @@ -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 */ diff --git a/libs/ardour/export_utilities.cc b/libs/ardour/export_utilities.cc index 64fa62ded5..a9223e2e1b 100644 --- a/libs/ardour/export_utilities.cc +++ b/libs/ardour/export_utilities.cc @@ -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; diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index aed32e278b..3ddceb6b00 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -49,17 +50,20 @@ Session::get_export_handler () return export_handler; } -void -Session::release_export_handler () +boost::shared_ptr +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 (); -} -- 2.30.2