From 34f088576cff12d7bfe1b21a0cebd3e194371a64 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 28 Sep 2015 17:42:02 -0400 Subject: [PATCH] get loop recording working when using seam-ed looping --- libs/ardour/ardour/butler.h | 2 + libs/ardour/butler.cc | 94 +++++++++++++++++--------------- libs/ardour/session_transport.cc | 38 +++++++++++++ 3 files changed, 89 insertions(+), 45 deletions(-) diff --git a/libs/ardour/ardour/butler.h b/libs/ardour/ardour/butler.h index 7f0847498e..3a2d8090d5 100644 --- a/libs/ardour/ardour/butler.h +++ b/libs/ardour/ardour/butler.h @@ -67,6 +67,8 @@ class LIBARDOUR_API Butler : public SessionHandleRef framecnt_t audio_diskstream_playback_buffer_size() const { return audio_dstream_playback_buffer_size; } uint32_t midi_diskstream_buffer_size() const { return midi_dstream_buffer_size; } + bool flush_tracks_to_disk (boost::shared_ptr, uint32_t& errors, bool force_flush); + static void* _thread_work(void *arg); void* thread_work(); diff --git a/libs/ardour/butler.cc b/libs/ardour/butler.cc index 95ba2a3ffe..8542f5e0cb 100644 --- a/libs/ardour/butler.cc +++ b/libs/ardour/butler.cc @@ -268,44 +268,7 @@ Butler::thread_work () goto restart; } - for (i = rl->begin(); !transport_work_requested() && should_run && i != rl->end(); ++i) { - // cerr << "write behind for " << (*i)->name () << endl; - - boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); - - if (!tr) { - continue; - } - - /* note that we still try to flush diskstreams attached to inactive routes - */ - - gint64 before, after; - int ret; - - DEBUG_TRACE (DEBUG::Butler, string_compose ("butler flushes track %1 capture load %2\n", tr->name(), tr->capture_buffer_load())); - before = g_get_monotonic_time (); - ret = tr->do_flush (ButlerContext); - after = g_get_monotonic_time (); - switch (ret) { - case 0: - DEBUG_TRACE (DEBUG::Butler, string_compose ("\tflush complete for %1, %2 usecs\n", tr->name(), after - before)); - break; - - case 1: - DEBUG_TRACE (DEBUG::Butler, string_compose ("\tflush not finished for %1, %2 usecs\n", tr->name(), after - before)); - disk_work_outstanding = true; - break; - - default: - err++; - error << string_compose(_("Butler write-behind failure on dstream %1"), (*i)->name()) << endmsg; - std::cerr << string_compose(_("Butler write-behind failure on dstream %1"), (*i)->name()) << std::endl; - /* don't break - try to flush all streams in case they - are split across disks. - */ - } - } + disk_work_outstanding = flush_tracks_to_disk (rl, err, false); if (err && _session.actively_recording()) { /* stop the transport and try to catch as much possible @@ -315,12 +278,6 @@ Butler::thread_work () _session.request_stop (); } - if (i != rl->begin() && i != rl->end()) { - /* we didn't get to all the streams */ - DEBUG_TRACE (DEBUG::Butler, "not all tracks processed, will need to go back for more\n"); - disk_work_outstanding = true; - } - if (!err && transport_work_requested()) { DEBUG_TRACE (DEBUG::Butler, "transport work requested during flush, back to restart\n"); goto restart; @@ -330,7 +287,6 @@ Butler::thread_work () _session.refresh_disk_space (); } - { Glib::Threads::Mutex::Lock lm (request_lock); @@ -351,6 +307,54 @@ Butler::thread_work () return (0); } +bool +Butler::flush_tracks_to_disk (boost::shared_ptr rl, uint32_t& errors, bool force) +{ + bool disk_work_outstanding = false; + + for (RouteList::iterator i = rl->begin(); (force || !transport_work_requested()) && should_run && i != rl->end(); ++i) { + + // cerr << "write behind for " << (*i)->name () << endl; + + boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); + + if (!tr) { + continue; + } + + /* note that we still try to flush diskstreams attached to inactive routes + */ + + gint64 before, after; + int ret; + + DEBUG_TRACE (DEBUG::Butler, string_compose ("butler flushes track %1 capture load %2\n", tr->name(), tr->capture_buffer_load())); + before = g_get_monotonic_time (); + ret = tr->do_flush (ButlerContext, force); + after = g_get_monotonic_time (); + switch (ret) { + case 0: + DEBUG_TRACE (DEBUG::Butler, string_compose ("\tflush complete for %1, %2 usecs\n", tr->name(), after - before)); + break; + + case 1: + DEBUG_TRACE (DEBUG::Butler, string_compose ("\tflush not finished for %1, %2 usecs\n", tr->name(), after - before)); + disk_work_outstanding = true; + break; + + default: + errors++; + error << string_compose(_("Butler write-behind failure on dstream %1"), (*i)->name()) << endmsg; + std::cerr << string_compose(_("Butler write-behind failure on dstream %1"), (*i)->name()) << std::endl; + /* don't break - try to flush all streams in case they + are split across disks. + */ + } + } + + return disk_work_outstanding; +} + void Butler::schedule_transport_work () { diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 72ec1ebdd8..3b2060d2ac 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -326,6 +326,37 @@ Session::butler_transport_work () DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler transport work, todo = %1 at %2\n", enum_2_string (ptw), (before = g_get_monotonic_time()))); + + if (ptw & PostTransportLocate) { + + if (get_play_loop() && !Config->get_seamless_loop() && actively_recording()) { + + /* this locate is happening while we are doing loop + * recording but with seam-ed (non-seamless) looping. + * We must flush any data to disk before resetting + * buffers as part of the pending locate (which happens + * a little later in this method). + */ + + bool more_disk_io_to_do = false; + uint32_t errors = 0; + + do { + more_disk_io_to_do = _butler->flush_tracks_to_disk (r, errors, true); + + if (errors) { + break; + } + + if (more_disk_io_to_do) { + continue; + } + + } while (false); + + } + } + if (ptw & PostTransportAdjustPlaybackBuffering) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); @@ -1067,6 +1098,13 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool target_frame, with_roll, with_flush, for_loop_enabled, force, with_mmc)); if (!force && _transport_frame == target_frame && !loop_changing && !for_loop_enabled) { + + /* already at the desired position. Not forced to locate, + the loop isn't changing, so unless we're told to + start rolling also, there's nothing to do but + tell the world where we are (again). + */ + if (with_roll) { set_transport_speed (1.0, 0, false); } -- 2.30.2