triggerbox: various improvements, including legato support, state tracking

This commit is contained in:
Paul Davis 2021-08-31 11:53:24 -06:00
parent 3734277263
commit 584e5c5b45
2 changed files with 63 additions and 8 deletions

View file

@ -69,6 +69,9 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
static void make_property_quarks ();
void set_name (std::string const &);
std::string name() const { return _name; }
/* semantics of "bang" depend on the trigger */
void bang ();
void unbang ();
@ -77,8 +80,8 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
/* explicitly call for the trigger to start */
virtual void start();
virtual void set_start (timepos_t) = 0;
virtual void set_end (timepos_t) = 0;
virtual void set_start (timepos_t const &) = 0;
virtual void set_end (timepos_t const &) = 0;
/* this accepts timepos_t because the origin is assumed to be the start */
virtual void set_length (timepos_t const &) = 0;
@ -156,6 +159,11 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
void set_follow_action_probability (int zero_to_a_hundred);
int follow_action_probability() const { return _follow_action_probability; }
virtual void set_legato_offset (timepos_t const & offset) = 0;
virtual timepos_t current_pos() const = 0;
void set_legato (bool yn);
bool legato () const { return _legato; }
protected:
TriggerBox& _box;
State _state;
@ -169,6 +177,8 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
int _follow_action_probability;
boost::shared_ptr<Region> _region;
Temporal::BBT_Offset _quantization;
bool _legato;
std::string _name;
void set_region_internal (boost::shared_ptr<Region>);
void request_state (State s);
@ -183,8 +193,10 @@ class LIBARDOUR_API AudioTrigger : public Trigger {
int run (BufferSet&, pframes_t nframes, pframes_t offset, bool first);
void set_start (timepos_t);
void set_end (timepos_t);
void set_start (timepos_t const &);
void set_end (timepos_t const &);
void set_legato_offset (timepos_t const &);
timepos_t current_pos() const;
/* this accepts timepos_t because the origin is assumed to be the start */
void set_length (timepos_t const &);
timepos_t start_offset () const { return timepos_t (_start_offset); } /* offset from start of data */
@ -203,6 +215,7 @@ class LIBARDOUR_API AudioTrigger : public Trigger {
samplecnt_t read_index;
samplecnt_t data_length;
samplepos_t _start_offset;
samplepos_t _legato_offset;
samplecnt_t usable_length;
samplepos_t last_sample;
@ -260,6 +273,8 @@ class LIBARDOUR_API TriggerBox : public Processor
typedef std::map<uint8_t,Triggers::size_type> MidiTriggerMap;
MidiTriggerMap midi_trigger_map;
static const size_t default_triggers_per_box;
};
} // namespace ARDOUR

View file

@ -45,9 +45,16 @@ Trigger::Trigger (size_t n, TriggerBox& b)
, _follow_action { NextTrigger, Stop }
, _follow_action_probability (100)
, _quantization (Temporal::BBT_Offset (0, 1, 0))
, _legato (false)
{
}
void
Trigger::set_name (std::string const & str)
{
_name = str;
}
void
Trigger::bang ()
{
@ -150,10 +157,12 @@ Trigger::process_state_requests ()
case Stopped:
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 %2 -> %3\n", index(), enum_2_string (_state), enum_2_string (WaitingToStop)));
_state = WaitingToStop;
PropertyChanged (ARDOUR::Properties::running);
break;
case Running:
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 %2 -> %3\n", index(), enum_2_string (_state), enum_2_string (WaitingToStart)));
_state = WaitingToStart;
PropertyChanged (ARDOUR::Properties::running);
break;
default:
break;
@ -180,18 +189,21 @@ Trigger::process_state_requests ()
case OneShot:
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 %2 -> %3\n", index(), enum_2_string (Running), enum_2_string (WaitingForRetrigger)));
_state = WaitingForRetrigger;
PropertyChanged (ARDOUR::Properties::running);
break;
case Gate:
case Toggle:
case Repeat:
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 %2 -> %3\n", index(), enum_2_string (Running), enum_2_string (Stopped)));
_state = WaitingToStop;
PropertyChanged (ARDOUR::Properties::running);
}
break;
case Stopped:
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 %2 -> %3\n", index(), enum_2_string (Stopped), enum_2_string (WaitingToStart)));
_state = WaitingToStart;
PropertyChanged (ARDOUR::Properties::running);
break;
case WaitingToStart:
@ -211,11 +223,13 @@ Trigger::process_state_requests ()
switch (_state) {
case Running:
_state = WaitingToStop;
PropertyChanged (ARDOUR::Properties::running);
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 unbanged, now in WaitingToStop\n", index()));
break;
default:
/* didn't even get started */
_state = Stopped;
PropertyChanged (ARDOUR::Properties::running);
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 unbanged, never started, now stopped\n", index()));
}
}
@ -254,14 +268,17 @@ Trigger::maybe_compute_next_transition (Temporal::Beats const & start, Temporal:
if (_state == WaitingToStop) {
_state = Stopping;
PropertyChanged (ARDOUR::Properties::running);
return RunEnd;
} else if (_state == WaitingToStart) {
retrigger ();
_state = Running;
PropertyChanged (ARDOUR::Properties::running);
return RunStart;
} else if (_state == WaitingForRetrigger) {
retrigger ();
_state = Running;
PropertyChanged (ARDOUR::Properties::running);
return RunAll;
}
} else {
@ -292,6 +309,7 @@ AudioTrigger::AudioTrigger (size_t n, TriggerBox& b)
, read_index (0)
, data_length (0)
, _start_offset (0)
, _legato_offset (0)
, usable_length (0)
, last_sample (0)
{
@ -305,17 +323,29 @@ AudioTrigger::~AudioTrigger ()
}
void
AudioTrigger::set_start (timepos_t s)
AudioTrigger::set_start (timepos_t const & s)
{
_start_offset = s.samples ();
}
void
AudioTrigger::set_end (timepos_t e)
AudioTrigger::set_end (timepos_t const & e)
{
set_length (timepos_t (e.samples() - _start_offset));
}
void
AudioTrigger::set_legato_offset (timepos_t const & offset)
{
_legato_offset = offset.samples();
}
timepos_t
AudioTrigger::current_pos() const
{
return timepos_t (read_index);
}
timepos_t
AudioTrigger::end() const
{
@ -549,6 +579,9 @@ AudioTrigger::load_data (boost::shared_ptr<AudioRegion> ar)
data.push_back (new Sample[data_length]);
ar->read (data[n], 0, data_length, n);
}
set_name (ar->name());
} catch (...) {
drop_data ();
return -1;
@ -560,7 +593,7 @@ AudioTrigger::load_data (boost::shared_ptr<AudioRegion> ar)
void
AudioTrigger::retrigger ()
{
read_index = _start_offset;
read_index = _start_offset + _legato_offset;
}
int
@ -618,6 +651,7 @@ AudioTrigger::run (BufferSet& bufs, pframes_t nframes, pframes_t dest_offset, bo
}
}
_state = Stopped;
PropertyChanged (ARDOUR::Properties::running);
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 reached end, now stopped\n", index()));
break;
}
@ -629,6 +663,7 @@ AudioTrigger::run (BufferSet& bufs, pframes_t nframes, pframes_t dest_offset, bo
if (_state == Stopping && long_enough_to_fade) {
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 was stopping, now stopped\n", index()));
_state = Stopped;
PropertyChanged (ARDOUR::Properties::running);
}
return 0;
@ -643,6 +678,8 @@ Trigger::make_property_quarks ()
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for running = %1\n", Properties::running.property_id));
}
const size_t TriggerBox::default_triggers_per_box = 8;
TriggerBox::TriggerBox (Session& s, DataType dt)
: Processor (s, _("TriggerBox"), Temporal::BeatTime)
, _bang_queue (1024)
@ -653,7 +690,7 @@ TriggerBox::TriggerBox (Session& s, DataType dt)
/* default number of possible triggers. call ::add_trigger() to increase */
if (_data_type == DataType::AUDIO) {
for (size_t n = 0; n < 16; ++n) {
for (size_t n = 0; n < default_triggers_per_box; ++n) {
all_triggers.push_back (new AudioTrigger (n, *this));
}
}
@ -964,6 +1001,9 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
if (nxt >= 0 && (size_t) nxt < all_triggers.size() && !all_triggers[nxt]->active()) {
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 switching to %2\n", trigger.index(), nxt));
if (all_triggers[nxt]->legato()) {
all_triggers[nxt]->set_legato_offset (trigger.current_pos());
}
/* start it up */
all_triggers[nxt]->bang ();
all_triggers[nxt]->process_state_requests ();