From 71f7f7a09b43331649957ba4a1d7ce8393c40e22 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 15 Dec 2021 10:21:28 -0700 Subject: [PATCH] triggerbox: add stretching property, virtualize computation of expected end sample, maybe fix position_as_fraction() --- libs/ardour/ardour/triggerbox.h | 16 ++++++++--- libs/ardour/triggerbox.cc | 47 +++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/libs/ardour/ardour/triggerbox.h b/libs/ardour/ardour/triggerbox.h index d35a9ea2cb..b2ae51ab38 100644 --- a/libs/ardour/ardour/triggerbox.h +++ b/libs/ardour/ardour/triggerbox.h @@ -129,6 +129,7 @@ class LIBARDOUR_API Trigger : public PBD::Stateful { virtual void reload (BufferSet&, void*) = 0; virtual double position_as_fraction() const = 0; + virtual void set_expected_end_sample (Temporal::TempoMap::SharedPtr const &, Temporal::BBT_Time const &) = 0; void set_use_follow (bool yn); bool use_follow() const { return _use_follow; } @@ -256,6 +257,7 @@ class LIBARDOUR_API Trigger : public PBD::Stateful { PBD::Property _midi_velocity_effect; void* _ui; samplepos_t expected_end_sample; + PBD::Property _stretching; void set_region_internal (boost::shared_ptr); virtual void retrigger() = 0; @@ -292,13 +294,17 @@ class LIBARDOUR_API AudioTrigger : public Trigger { RubberBand::RubberBandStretcher* stretcher() { return (_stretcher); } SegmentDescriptor get_segment_descriptor () const; + void set_expected_end_sample (Temporal::TempoMap::SharedPtr const &, Temporal::BBT_Time const &); + + void set_stretching (bool yn); + bool stretching () const; protected: void retrigger (); void set_usable_length (); private: - PBD::ID data_source; + PBD::ID data_source; std::vector data; samplecnt_t read_index; samplecnt_t process_index; @@ -309,9 +315,9 @@ class LIBARDOUR_API AudioTrigger : public Trigger { samplepos_t last_sample; samplecnt_t retrieved; RubberBand::RubberBandStretcher* _stretcher; - samplecnt_t got_stretcher_padding; - samplecnt_t to_pad; - samplecnt_t to_drop; + samplecnt_t got_stretcher_padding; + samplecnt_t to_pad; + samplecnt_t to_drop; void drop_data (); int load_data (boost::shared_ptr); @@ -349,6 +355,7 @@ class LIBARDOUR_API MIDITrigger : public Trigger { int set_state (const XMLNode&, int version); SegmentDescriptor get_segment_descriptor () const; + void set_expected_end_sample (Temporal::TempoMap::SharedPtr const &, Temporal::BBT_Time const &); protected: void retrigger (); @@ -603,6 +610,7 @@ namespace Properties { LIBARDOUR_API extern PBD::PropertyDescriptor velocity_effect; LIBARDOUR_API extern PBD::PropertyDescriptor gain; LIBARDOUR_API extern PBD::PropertyDescriptor currently_playing; + LIBARDOUR_API extern PBD::PropertyDescriptor stretching; } diff --git a/libs/ardour/triggerbox.cc b/libs/ardour/triggerbox.cc index f66578a4dd..535418fa09 100644 --- a/libs/ardour/triggerbox.cc +++ b/libs/ardour/triggerbox.cc @@ -56,6 +56,7 @@ namespace ARDOUR { PBD::PropertyDescriptor follow_action_probability; PBD::PropertyDescriptor velocity_effect; PBD::PropertyDescriptor gain; + PBD::PropertyDescriptor stretching; } } @@ -80,12 +81,14 @@ Trigger::Trigger (uint64_t n, TriggerBox& b) , _midi_velocity_effect (Properties::velocity_effect, 0.) , _ui (0) , expected_end_sample (0) + , _stretching (Properties::stretching, true) { add_property (_legato); add_property (_use_follow); add_property (_follow_count); add_property (_midi_velocity_effect); add_property (_follow_action_probability); + add_property (_stretching); } void @@ -368,8 +371,7 @@ Trigger::process_state_requests () case Toggle: case Repeat: DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 %2 gate/toggle/repeat => %3\n", index(), enum_2_string (Running), enum_2_string (WaitingToStop))); - _state = WaitingToStop; - PropertyChanged (ARDOUR::Properties::running); + begin_stop (); } break; @@ -480,7 +482,7 @@ Trigger::maybe_compute_next_transition (samplepos_t start_sample, Temporal::Beat case WaitingToStart: retrigger (); _state = Running; - expected_end_sample = tmap->sample_at (tmap->bbt_walk(transition_bbt, BBT_Offset (round (_barcnt), 0, 0))); + set_expected_end_sample (tmap, transition_bbt); cerr << "starting at " << transition_bbt << " bars " << round(_barcnt) << " end at " << tmap->bbt_walk (transition_bbt, BBT_Offset (round (_barcnt), 0, 0)) << " sample = " << expected_end_sample << endl; PropertyChanged (ARDOUR::Properties::running); @@ -499,7 +501,7 @@ Trigger::maybe_compute_next_transition (samplepos_t start_sample, Temporal::Beat case WaitingForRetrigger: retrigger (); _state = Running; - expected_end_sample = tmap->sample_at (tmap->bbt_walk(transition_bbt, BBT_Offset (round (_barcnt), 0, 0))); + set_expected_end_sample (tmap, transition_bbt); cerr << "starting at " << transition_bbt << " bars " << round(_barcnt) << " end at " << tmap->bbt_walk (transition_bbt, BBT_Offset (round (_barcnt), 0, 0)) << " sample = " << expected_end_sample << endl; PropertyChanged (ARDOUR::Properties::running); @@ -553,6 +555,22 @@ AudioTrigger::~AudioTrigger () delete _stretcher; } +bool +AudioTrigger::stretching() const +{ + return (_apparent_tempo != .0) && _stretching; +} + +void +AudioTrigger::set_expected_end_sample (Temporal::TempoMap::SharedPtr const & tmap, Temporal::BBT_Time const & transition_bbt) +{ + if (stretching()) { + expected_end_sample = tmap->sample_at (tmap->bbt_walk(transition_bbt, Temporal::BBT_Offset (round (_barcnt), 0, 0))); + } else { + expected_end_sample = transition_samples = usable_length; + } +} + SegmentDescriptor AudioTrigger::get_segment_descriptor () const { @@ -592,7 +610,7 @@ AudioTrigger::position_as_fraction () const return 0.0; } - return process_index / (double) usable_length; + return process_index / (double) (expected_end_sample - transition_samples); } XMLNode& @@ -904,7 +922,7 @@ AudioTrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa int avail = 0; BufferSet& scratch (_box.session().get_scratch_buffers (ChanCount (DataType::AUDIO, nchans))); std::vector bufp(nchans); - const bool stretching = (_apparent_tempo != 0.); + const bool do_stretch = stretching(); /* see if we're going to start or stop or retrigger in this run() call */ pframes_t extra_offset = maybe_compute_next_transition (start_sample, start, end, dest_offset, passthru); @@ -919,7 +937,6 @@ AudioTrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa case WaitingForRetrigger: case WaitingToStart: /* did everything we could do */ - std::cerr << name() << " when i run, stretching will be: " << stretching << std::endl; return nframes; case Running: case WaitingToStop: @@ -939,7 +956,7 @@ AudioTrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa /* tell the stretcher what we are doing for this ::run() call */ - if (stretching) { + if (do_stretch) { const double stretch = _apparent_tempo / bpm; _stretcher->setTimeRatio (stretch); @@ -992,7 +1009,7 @@ AudioTrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa pframes_t to_stretcher; pframes_t from_stretcher; - if (stretching) { + if (do_stretch) { if (read_index < last_sample) { @@ -1068,7 +1085,7 @@ AudioTrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa uint64_t channel = chn % data.size(); AudioBuffer& buf (bufs.get_audio (channel)); - Sample* src = stretching ? bufp[channel] : (data[channel] + read_index); + Sample* src = do_stretch ? bufp[channel] : (data[channel] + read_index); if (!passthru) { buf.read_from (src, from_stretcher, dest_offset); @@ -1090,7 +1107,7 @@ AudioTrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa * stretcher */ - if (!stretching) { + if (!do_stretch) { read_index += from_stretcher; } @@ -1163,6 +1180,12 @@ MIDITrigger::~MIDITrigger () { } +void +MIDITrigger::set_expected_end_sample (Temporal::TempoMap::SharedPtr const & tmap, Temporal::BBT_Time const & transition_bbt) +{ + expected_end_sample = tmap->sample_at (tmap->bbt_walk(transition_bbt, Temporal::BBT_Offset (round (_barcnt), 0, 0))); +} + SegmentDescriptor MIDITrigger::get_segment_descriptor () const { @@ -1525,6 +1548,8 @@ Trigger::make_property_quarks () DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for follow-action-0 = %1\n", Properties::follow_action0.property_id)); Properties::follow_action1.property_id = g_quark_from_static_string (X_("follow-action-1")); DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for follow-action-1 = %1\n", Properties::follow_action1.property_id)); + Properties::stretching.property_id = g_quark_from_static_string (X_("stretching")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretching = %1\n", Properties::stretching.property_id)); } const int32_t TriggerBox::default_triggers_per_box = 8;