triggerbox: correct an error in the computation of "frames covered" for audio triggers

This commit is contained in:
Paul Davis 2022-07-07 16:44:56 -06:00
parent 4a30d8cebb
commit 97317f3f86
2 changed files with 42 additions and 26 deletions

View File

@ -269,7 +269,7 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
virtual pframes_t run (BufferSet&, samplepos_t start_sample, samplepos_t end_sample,
Temporal::Beats const & start, Temporal::Beats const & end,
pframes_t nframes, pframes_t offset, double bpm) = 0;
pframes_t nframes, pframes_t offset, double bpm, pframes_t& quantize_offset) = 0;
virtual void set_start (timepos_t const &) = 0;
virtual void set_end (timepos_t const &) = 0;
virtual void set_length (timecnt_t const &) = 0;
@ -336,7 +336,7 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
void start_and_roll_to (samplepos_t start_pos, samplepos_t end_position, TriggerType& trigger,
pframes_t (TriggerType::*run_method) (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample,
Temporal::Beats const & start_beats, Temporal::Beats const & end_beats,
pframes_t nframes, pframes_t dest_offset, double bpm));
pframes_t nframes, pframes_t dest_offset, double bpm, pframes_t&));
void set_next_trigger (int n);
int next_trigger() const { return _next_trigger; }
@ -473,10 +473,10 @@ class LIBARDOUR_API AudioTrigger : public Trigger {
template<bool actually_run> pframes_t audio_run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample,
Temporal::Beats const & start, Temporal::Beats const & end,
pframes_t nframes, pframes_t dest_offset, double bpm);
pframes_t nframes, pframes_t dest_offset, double bpm, pframes_t& quantize_offset);
pframes_t run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, Temporal::Beats const & start, Temporal::Beats const & end, pframes_t nframes, pframes_t dest_offset, double bpm) {
return audio_run<true> (bufs, start_sample, end_sample, start, end, nframes, dest_offset, bpm);
pframes_t run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, Temporal::Beats const & start, Temporal::Beats const & end, pframes_t nframes, pframes_t dest_offset, double bpm, pframes_t& quantize_offset) {
return audio_run<true> (bufs, start_sample, end_sample, start, end, nframes, dest_offset, bpm, quantize_offset);
}
StretchMode stretch_mode() const { return _stretch_mode; }
@ -555,10 +555,10 @@ class LIBARDOUR_API MIDITrigger : public Trigger {
~MIDITrigger ();
template<bool actually_run> pframes_t midi_run (BufferSet&, samplepos_t start_sample, samplepos_t end_sample,
Temporal::Beats const & start_beats, Temporal::Beats const & end_beats, pframes_t nframes, pframes_t offset, double bpm);
Temporal::Beats const & start_beats, Temporal::Beats const & end_beats, pframes_t nframes, pframes_t offset, double bpm, pframes_t& quantize_offset);
pframes_t run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, Temporal::Beats const & start, Temporal::Beats const & end, pframes_t nframes, pframes_t dest_offset, double bpm) {
return midi_run<true> (bufs, start_sample, end_sample, start, end, nframes, dest_offset, bpm);
pframes_t run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, Temporal::Beats const & start, Temporal::Beats const & end, pframes_t nframes, pframes_t dest_offset, double bpm, pframes_t& quantize_offset) {
return midi_run<true> (bufs, start_sample, end_sample, start, end, nframes, dest_offset, bpm, quantize_offset);
}
void set_start (timepos_t const &);

View File

@ -1016,7 +1016,7 @@ Trigger::compute_next_transition (samplepos_t start_sample, Temporal::Beats cons
}
void
Trigger::maybe_compute_next_transition (samplepos_t start_sample, Temporal::Beats const & start, Temporal::Beats const & end, pframes_t& nframes, pframes_t& dest_offset)
Trigger::maybe_compute_next_transition (samplepos_t start_sample, Temporal::Beats const & start, Temporal::Beats const & end, pframes_t& nframes, pframes_t& quantize_offset)
{
using namespace Temporal;
@ -1038,7 +1038,6 @@ Trigger::maybe_compute_next_transition (samplepos_t start_sample, Temporal::Beat
return;
}
pframes_t extra_offset = 0;
Temporal::Beats elen_ignored;
/* transition time has arrived! let's figure out what're doing:
@ -1080,12 +1079,9 @@ Trigger::maybe_compute_next_transition (samplepos_t start_sample, Temporal::Beat
* should end up, and the number of samples it should generate.
*/
extra_offset = std::max (samplepos_t (0), transition_samples - start_sample);
quantize_offset = std::max (samplepos_t (0), transition_samples - start_sample);
nframes -= quantize_offset;
nframes -= extra_offset;
dest_offset += extra_offset;
/* XXX need to silence start of buffers up to dest_offset */
break;
case WaitingForRetrigger:
@ -1162,7 +1158,7 @@ void
Trigger::start_and_roll_to (samplepos_t start_pos, samplepos_t end_position, TriggerType& trigger,
pframes_t (TriggerType::*run_method) (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample,
Temporal::Beats const & start_beats, Temporal::Beats const & end_beats,
pframes_t nframes, pframes_t dest_offset, double bpm))
pframes_t nframes, pframes_t dest_offset, double bpm, pframes_t&))
{
const pframes_t block_size = AudioEngine::instance()->samples_per_cycle ();
BufferSet bufs;
@ -1180,6 +1176,7 @@ Trigger::start_and_roll_to (samplepos_t start_pos, samplepos_t end_position, Tri
samplepos_t pos = start_pos;
Temporal::TempoMap::SharedPtr tmap (Temporal::TempoMap::use());
pframes_t quantize_offset;
while (pos < end_position) {
pframes_t nframes = std::min (block_size, (pframes_t) (end_position - pos));
@ -1187,7 +1184,7 @@ Trigger::start_and_roll_to (samplepos_t start_pos, samplepos_t end_position, Tri
Temporal::Beats end_beats = tmap->quarters_at (timepos_t (pos+nframes));
const double bpm = tmap->quarters_per_minute_at (timepos_t (start_beats));
pframes_t n = (trigger.*run_method) (bufs, pos, pos+nframes, start_beats, end_beats, nframes, 0, bpm);
pframes_t n = (trigger.*run_method) (bufs, pos, pos+nframes, start_beats, end_beats, nframes, 0, bpm, quantize_offset);
/* We could have reached the end. Check and restart, because
* TriggerBox::fast_forward() already determined that we are
@ -1201,6 +1198,7 @@ Trigger::start_and_roll_to (samplepos_t start_pos, samplepos_t end_position, Tri
}
pos += n;
pos += quantize_offset;
}
}
@ -1801,7 +1799,7 @@ template<bool in_process_context>
pframes_t
AudioTrigger::audio_run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample,
Temporal::Beats const & start, Temporal::Beats const & end,
pframes_t nframes, pframes_t dest_offset, double bpm)
pframes_t nframes, pframes_t dest_offset, double bpm, pframes_t& quantize_offset)
{
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(_region);
/* We do not modify the I/O of our parent route, so we process only min (bufs.n_audio(),region.channels()) */
@ -1812,11 +1810,14 @@ AudioTrigger::audio_run (BufferSet& bufs, samplepos_t start_sample, samplepos_t
std::vector<Sample*> bufp(nchans);
const bool do_stretch = stretching() && _segment_tempo > 1;
/* see if we're going to start or stop or retrigger in this run() call */
maybe_compute_next_transition (start_sample, start, end, nframes, dest_offset);
const pframes_t orig_nframes = nframes;
quantize_offset = 0;
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1/%2 after checking for transition, state = %3, will stretch %4, nf will be %5 of %6\n", index(), name(), enum_2_string (_state), do_stretch, nframes));
/* see if we're going to start or stop or retrigger in this run() call */
maybe_compute_next_transition (start_sample, start, end, nframes, quantize_offset);
const pframes_t orig_nframes = nframes;
dest_offset += quantize_offset;
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1/%2 after checking for transition, state = %3, will stretch %4, nf will be %5 of %6, dest_offset %7\n", index(), name(), enum_2_string (_state), do_stretch, nframes, orig_nframes, dest_offset));
switch (_state) {
case Stopped:
@ -2634,7 +2635,7 @@ template<bool in_process_context>
pframes_t
MIDITrigger::midi_run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample,
Temporal::Beats const & start_beats, Temporal::Beats const & end_beats,
pframes_t nframes, pframes_t dest_offset, double bpm)
pframes_t nframes, pframes_t dest_offset, double bpm, pframes_t& quantize_offset)
{
MidiBuffer* mb (in_process_context? &bufs.get_midi (0) : 0);
typedef Evoral::Event<MidiModel::TimeType> MidiEvent;
@ -2644,8 +2645,8 @@ MIDITrigger::midi_run (BufferSet& bufs, samplepos_t start_sample, samplepos_t en
DEBUG_RESULT (samplepos_t, last_event_samples, max_samplepos);
/* see if we're going to start or stop or retrigger in this run() call */
pframes_t ignore_computed_dest_offset = 0;
maybe_compute_next_transition (start_sample, start_beats, end_beats, nframes, ignore_computed_dest_offset);
quantize_offset = 0;
maybe_compute_next_transition (start_sample, start_beats, end_beats, nframes, quantize_offset);
const pframes_t orig_nframes = nframes;
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 after checking for transition, state = %2\n", name(), enum_2_string (_state)));
@ -4024,8 +4025,23 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
max_chans = std::max (ar->n_channels(), max_chans);
}
frames_covered = _currently_playing->run (bufs, start_sample, end_sample, start_beats, end_beats, nframes, dest_offset, bpm);
/* Quantize offset will generally be zero, but if non-zero, it
* represents an initial "skip" in the output buffers required
* to align the trigger output with its quantization. This
* means that the total portion of the buffer covered by the
* trigger is the sum of the quantize offset and "frames
* covered".
*
* Quantize offset will only be non-zero for a trigger that is
* actually going to output its initial samples somewhere in
* this process cycle (but after the beginning of the cycle).
*/
pframes_t quantize_offset;
frames_covered = _currently_playing->run (bufs, start_sample, end_sample, start_beats, end_beats, nframes, dest_offset, bpm, quantize_offset);
nframes -= quantize_offset;
nframes -= frames_covered;
start_sample += frames_covered;
dest_offset += frames_covered;