From 6bc4f69c5c85a2494dab3936d121833b1dcca15a Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 29 Jan 2020 01:22:48 +0100 Subject: [PATCH] Fix loop recording alignment DiskWriter::transport_looped() is called from the session when engine loops. This does not take local disk-reader run() latency offset into account. finish_capture() needs to be postponed until the disk-writer itself reaches the loop-position. This is achieved by postponing loop() and calling it once loop-length of samples has been captured. This works because engaging loop always seeks to the loop-position and first loop resets _capture_captured. --- libs/ardour/ardour/disk_writer.h | 5 ++++ libs/ardour/disk_writer.cc | 45 +++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/libs/ardour/ardour/disk_writer.h b/libs/ardour/ardour/disk_writer.h index c17c2e539e..fab54e2404 100644 --- a/libs/ardour/ardour/disk_writer.h +++ b/libs/ardour/ardour/disk_writer.h @@ -169,6 +169,8 @@ private: void check_record_status (samplepos_t transport_sample, double speed, bool can_record); void finish_capture (boost::shared_ptr c); + void loop (samplepos_t); + CaptureInfos capture_info; mutable Glib::Threads::Mutex capture_info_lock; @@ -187,6 +189,9 @@ private: volatile gint _num_captured_loops; samplepos_t _accumulated_capture_offset; + bool _transport_looped; + samplepos_t _transport_loop_sample; + boost::shared_ptr _midi_write_source; std::list > _last_capture_sources; diff --git a/libs/ardour/disk_writer.cc b/libs/ardour/disk_writer.cc index cb62f932b6..cddfe7b09b 100644 --- a/libs/ardour/disk_writer.cc +++ b/libs/ardour/disk_writer.cc @@ -59,6 +59,8 @@ DiskWriter::DiskWriter (Session& s, string const & str, DiskIOProcessor::Flag f) , _samples_pending_write (0) , _num_captured_loops (0) , _accumulated_capture_offset (0) + , _transport_looped (false) + , _transport_loop_sample (0) , _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI)) { DiskIOProcessor::init (); @@ -397,6 +399,29 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp _need_butler = false; + const Location* const loop_loc = _loop_location; + samplepos_t loop_start = 0; + samplepos_t loop_end = 0; + samplepos_t loop_length = 0; + + if (_transport_looped && _capture_captured == 0) { + _transport_looped = false; + } + + if (loop_loc) { + get_location_times (loop_loc, &loop_start, &loop_end, &loop_length); + + if (_was_recording && _transport_looped && _capture_captured >= loop_length) { + samplecnt_t remain = _capture_captured - loop_length; + _capture_captured = loop_length; + loop (_transport_loop_sample); + _capture_captured = remain; + } + + } else { + _transport_looped = false; + } + #ifndef NDEBUG if (speed != 0 && re) { DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: run() start: %2 end: %3 NF: %4\n", _name, start_sample, end_sample, nframes)); @@ -418,15 +443,6 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp _last_recordable_sample = max_samplepos; } - const Location* const loop_loc = _loop_location; - samplepos_t loop_start = 0; - samplepos_t loop_end = 0; - samplepos_t loop_length = 0; - - if (loop_loc) { - get_location_times (loop_loc, &loop_start, &loop_end, &loop_length); - } - if (nominally_recording || (re && _was_recording && _session.get_record_enabled() && punch_in)) { Evoral::OverlapType ot = Evoral::coverage (_first_recordable_sample, _last_recordable_sample, start_sample, end_sample); @@ -1318,6 +1334,17 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo void DiskWriter::transport_looped (samplepos_t transport_sample) { + if (_capture_captured) { + _transport_looped = true; + _transport_loop_sample = transport_sample; + _first_recordable_sample = transport_sample; + } +} + +void +DiskWriter::loop (samplepos_t transport_sample) +{ + _transport_looped = false; if (_was_recording) { // all we need to do is finish this capture, with modified capture length boost::shared_ptr c = channels.reader();