diff options
author | Robin Gareus <robin@gareus.org> | 2020-03-05 20:18:54 +0100 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2020-03-06 01:49:44 +0100 |
commit | 18514408637c9b49a1858443a4f1a37023244599 (patch) | |
tree | b640ccf40bc2ed28fd011eb4fb4a2808850f2c78 | |
parent | 128a45954cfbfeaa0fd70c626a5d0c3c86e2ff7a (diff) |
Fix realtime export of multiple time-spans
After exporting a time-span, the next time-span was started
directly from the rt-callback. This had various issues.
In particular with realtime export.
Post-processing of a realtime-export enables freewheeling
and is driven by freewheel callbacks. Freewheeling needs to be
safely disabled for an upcoming realtime export.
A similar issues existed when mixing realtime and non-realtime exports.
-rw-r--r-- | libs/ardour/ardour/export_handler.h | 2 | ||||
-rw-r--r-- | libs/ardour/export_graph_builder.cc | 10 | ||||
-rw-r--r-- | libs/ardour/export_handler.cc | 28 | ||||
-rw-r--r-- | libs/ardour/session_export.cc | 25 |
4 files changed, 58 insertions, 7 deletions
diff --git a/libs/ardour/ardour/export_handler.h b/libs/ardour/ardour/export_handler.h index 1178eb9e79..d270f4d82d 100644 --- a/libs/ardour/ardour/export_handler.h +++ b/libs/ardour/ardour/export_handler.h @@ -146,6 +146,8 @@ class LIBARDOUR_API ExportHandler : public ExportElementFactory, public sigc::tr /* Timespan management */ + static void* start_timespan_bg (void*); + void start_timespan (); int process_timespan (samplecnt_t samples); int post_process (); diff --git a/libs/ardour/export_graph_builder.cc b/libs/ardour/export_graph_builder.cc index 2a2eb63671..f4d6d21f2d 100644 --- a/libs/ardour/export_graph_builder.cc +++ b/libs/ardour/export_graph_builder.cc @@ -25,6 +25,7 @@ #include <vector> #include <glibmm/miscutils.h> +#include <glibmm/timer.h> #include "pbd/uuid.h" #include "pbd/file_utils.h" @@ -655,10 +656,17 @@ ExportGraphBuilder::Intermediate::prepare_post_processing() void ExportGraphBuilder::Intermediate::start_post_processing() { - // called in disk-thread (when exporting in realtime) + /* called in disk-thread (when exporting in realtime) */ tmp_file->seek (0, SEEK_SET); + /* RT Stem export has multiple TmpFileRt threads, + * prevent concurrent calls to enable freewheel () + */ + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); if (!AudioEngine::instance()->freewheeling ()) { AudioEngine::instance()->freewheel (true); + while (!AudioEngine::instance()->freewheeling ()) { + Glib::usleep (AudioEngine::instance()->usecs_per_cycle ()); + } } } diff --git a/libs/ardour/export_handler.cc b/libs/ardour/export_handler.cc index 4aed0ee97e..76869c7a79 100644 --- a/libs/ardour/export_handler.cc +++ b/libs/ardour/export_handler.cc @@ -172,6 +172,14 @@ ExportHandler::start_timespan () { export_status->timespan++; + /* stop freewheeling and wait for latency callbacks */ + if (AudioEngine::instance()->freewheeling ()) { + AudioEngine::instance()->freewheel (false); + do { + Glib::usleep (AudioEngine::instance()->usecs_per_cycle ()); + } while (AudioEngine::instance()->freewheeling ()); + } + if (config_map.empty()) { // freewheeling has to be stopped from outside the process cycle export_status->set_running (false); @@ -266,10 +274,11 @@ ExportHandler::process (samplecnt_t samples) // wait until we're freewheeling return 0; } - } else { + } else if (samples > 0) { Glib::Threads::Mutex::Lock l (export_status->lock()); return process_timespan (samples); } + return 0; } int @@ -338,6 +347,16 @@ ExportHandler::command_output(std::string output, size_t size) info << output << endmsg; } +void* +ExportHandler::start_timespan_bg (void* eh) +{ + ExportHandler* self = static_cast<ExportHandler*> (eh); + self->process_connection.disconnect (); + Glib::Threads::Mutex::Lock l (self->export_status->lock()); + self->start_timespan (); + return 0; +} + void ExportHandler::finish_timespan () { @@ -474,7 +493,12 @@ ExportHandler::finish_timespan () config_map.erase (config_map.begin()); } - start_timespan (); + /* finish timespan is called in freewheeling rt-context, + * we cannot start a new export from here */ + assert (AudioEngine::instance()->freewheeling ()); + pthread_t tid; + pthread_create (&tid, NULL, ExportHandler::start_timespan_bg, this); + pthread_detach (tid); } void diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index c4ef004550..93ca0d5afe 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -111,9 +111,10 @@ Session::start_audio_export (samplepos_t position, bool realtime, bool region_ex { if (!_exporting) { pre_export (); + } else { + realtime_stop (true, true); } - _realtime_export = realtime; _region_export = region_export; if (region_export) { @@ -165,7 +166,6 @@ Session::start_audio_export (samplepos_t position, bool realtime, bool region_ex } else { _remaining_latency_preroll = 0; } - 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 @@ -179,15 +179,27 @@ Session::start_audio_export (samplepos_t position, bool realtime, bool region_ex return -1; } - _engine.Freewheel.connect_same_thread (export_freewheel_connection, boost::bind (&Session::process_export_fw, this, _1)); + assert (!_engine.freewheeling ()); + assert (!_engine.in_process_thread ()); - if (_realtime_export) { + if (realtime) { Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); _export_rolling = true; + _realtime_export = true; + export_status->stop = false; process_function = &Session::process_export_fw; + /* this is required for ExportGraphBuilder::Intermediate::start_post_processing */ + _engine.Freewheel.connect_same_thread (export_freewheel_connection, boost::bind (&Session::process_export_fw, this, _1)); return 0; } else { + if (_realtime_export) { + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + process_function = &Session::process_with_events; + } + _realtime_export = false; _export_rolling = true; + export_status->stop = false; + _engine.Freewheel.connect_same_thread (export_freewheel_connection, boost::bind (&Session::process_export_fw, this, _1)); return _engine.freewheel (true); } } @@ -235,6 +247,11 @@ Session::process_export (pframes_t nframes) void Session::process_export_fw (pframes_t nframes) { + if (!_export_rolling) { + ProcessExport (0); + return; + } + const bool need_buffers = _engine.freewheeling (); if (_export_preroll > 0) { |