From dbb816b1f9a9f0dc2557fb42a43388b880bb7e4a Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 7 Jan 2022 12:46:04 -0700 Subject: [PATCH] triggerbox: add "final sample" concept to start dealing with post-data playout --- libs/ardour/ardour/triggerbox.h | 9 ++++-- libs/ardour/triggerbox.cc | 52 +++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/libs/ardour/ardour/triggerbox.h b/libs/ardour/ardour/triggerbox.h index 119988c065..4b470a4f62 100644 --- a/libs/ardour/ardour/triggerbox.h +++ b/libs/ardour/ardour/triggerbox.h @@ -95,7 +95,11 @@ class LIBARDOUR_API Trigger : public PBD::Stateful { * during the current call to ::run(). By the end of that call, it will * have transitioned to Stopped. */ - Stopping + Stopping, + /* a Trigger in this state has played all of its data and is + * now silent-filling until we reach the "true end" of the trigger + */ + Playout, }; Trigger (uint32_t index, TriggerBox&); @@ -363,7 +367,8 @@ class LIBARDOUR_API AudioTrigger : public Trigger { /* computed after data is reset */ samplecnt_t usable_length; - samplepos_t last_sample; + samplepos_t last_sample; /* where the data runs out */ + samplepos_t final_sample; /* where we stop playing */ /* computed during run */ diff --git a/libs/ardour/triggerbox.cc b/libs/ardour/triggerbox.cc index 3cc2da97db..562c084a28 100644 --- a/libs/ardour/triggerbox.cc +++ b/libs/ardour/triggerbox.cc @@ -499,6 +499,7 @@ Trigger::process_state_requests (BufferSet& bufs, pframes_t dest_offset) switch (_state) { case Running: + case Playout: switch (launch_style()) { case OneShot: /* do nothing, just let it keep playing */ @@ -543,6 +544,7 @@ Trigger::process_state_requests (BufferSet& bufs, pframes_t dest_offset) switch (_state) { case Running: + case Playout: begin_stop (true); DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 unbanged, now in WaitingToStop\n", index())); break; @@ -859,6 +861,7 @@ AudioTrigger::set_state (const XMLNode& node, int version) node.get_property (X_("length"), t); usable_length = t.samples(); last_sample = _start_offset + usable_length; + final_sample = _start_offset + usable_length; return 0; } @@ -907,6 +910,7 @@ AudioTrigger::set_usable_length () default: usable_length = data.length; last_sample = _start_offset + usable_length; + final_sample = last_sample; return; } @@ -915,6 +919,7 @@ AudioTrigger::set_usable_length () if (q == Temporal::BBT_Offset ()) { usable_length = data.length; last_sample = _start_offset + usable_length; + final_sample = last_sample; return; } @@ -923,6 +928,7 @@ AudioTrigger::set_usable_length () timecnt_t len (Temporal::Beats (q.beats, q.ticks), timepos_t (Temporal::Beats())); usable_length = len.samples(); last_sample = _start_offset + usable_length; + final_sample = last_sample; // std::cerr << name() << " SUL ul " << usable_length << " of " << data.length << " so " << _start_offset << " ls " << last_sample << std::endl; } @@ -1175,6 +1181,7 @@ AudioTrigger::load_data (boost::shared_ptr ar) if (!usable_length || usable_length > data.length) { usable_length = data.length; last_sample = _start_offset + usable_length; + final_sample = last_sample; } drop_data (); @@ -1233,6 +1240,7 @@ AudioTrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa /* did everything we could do */ return nframes; case Running: + case Playout: case WaitingToStop: case Stopping: /* stuff to do */ @@ -1298,7 +1306,7 @@ AudioTrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa } } - while (nframes) { + while (nframes && (_state != Playout)) { pframes_t to_stretcher; pframes_t from_stretcher; @@ -1414,19 +1422,53 @@ AudioTrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa avail = _stretcher->available (); dest_offset += from_stretcher; - if (read_index >= last_sample && (_apparent_tempo == 0. || avail <= 0)) { - _state = Stopped; - _loop_cnt++; + if (read_index >= last_sample && (!do_stretch || avail <= 0)) { + + if (last_sample < final_sample) { + _state = Playout; + } else { + _state = Stopped; + _loop_cnt++; + } DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 reached end, now stopped, retrieved %2, avail %3\n", index(), retrieved, avail)); break; } } + + pframes_t covered_frames = orig_nframes - nframes; + + if (_state == Playout) { + + const pframes_t remaining_frames_for_run= orig_nframes - covered_frames; + const pframes_t remaining_frames_till_final = final_sample - read_index; + const pframes_t to_fill = std::min (remaining_frames_till_final, remaining_frames_for_run); + + for (uint32_t chn = 0; chn < bufs.count().n_audio(); ++chn) { + + uint32_t channel = chn % data.size(); + AudioBuffer& buf (bufs.get_audio (chn)); + + buf.silence (to_fill, dest_offset + covered_frames); + } + + read_index += to_fill; + covered_frames += to_fill; + + if (read_index < final_sample) { + /* more playout to be done */ + return covered_frames; + } + + _state == Stopped; + _loop_cnt++; + } + if (_state == Stopped || _state == Stopping) { when_stopped_during_run (bufs, dest_offset); } - return orig_nframes - nframes; + return covered_frames; } void