mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-05 05:05:43 +01:00
triggerbox: more behavioral improvements
This commit is contained in:
parent
ceabc49232
commit
7932c9bde1
2 changed files with 113 additions and 15 deletions
|
|
@ -43,6 +43,7 @@ class XMLNode;
|
|||
namespace ARDOUR {
|
||||
namespace Properties {
|
||||
LIBARDOUR_API extern PBD::PropertyDescriptor<bool> running;
|
||||
LIBARDOUR_API extern PBD::PropertyDescriptor<bool> legato;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,6 +164,8 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
|||
bool legato () const { return _legato; }
|
||||
|
||||
virtual void startup ();
|
||||
virtual void jump_start ();
|
||||
virtual void jump_stop ();
|
||||
|
||||
protected:
|
||||
TriggerBox& _box;
|
||||
|
|
@ -184,7 +187,6 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
|||
void request_state (State s);
|
||||
virtual void retrigger() = 0;
|
||||
virtual void set_usable_length () = 0;
|
||||
void maybe_startup ();
|
||||
};
|
||||
|
||||
class LIBARDOUR_API AudioTrigger : public Trigger {
|
||||
|
|
@ -207,6 +209,8 @@ class LIBARDOUR_API AudioTrigger : public Trigger {
|
|||
|
||||
int set_region (boost::shared_ptr<Region>);
|
||||
void startup ();
|
||||
void jump_start ();
|
||||
void jump_stop ();
|
||||
|
||||
XMLNode& get_state (void);
|
||||
int set_state (const XMLNode&, int version);
|
||||
|
|
@ -263,8 +267,9 @@ class LIBARDOUR_API TriggerBox : public Processor
|
|||
|
||||
void queue_explict (Trigger*);
|
||||
void queue_implicit (Trigger*);
|
||||
void clear_implicit ();
|
||||
Trigger* get_next_trigger ();
|
||||
Trigger* peak_next_trigger ();
|
||||
Trigger* peek_next_trigger ();
|
||||
void prepare_next (size_t current);
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ using std::endl;
|
|||
namespace ARDOUR {
|
||||
namespace Properties {
|
||||
PBD::PropertyDescriptor<bool> running;
|
||||
PBD::PropertyDescriptor<bool> legato;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -129,6 +130,13 @@ Trigger::set_state (const XMLNode& node, int version)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Trigger::set_legato (bool yn)
|
||||
{
|
||||
_legato = yn;
|
||||
PropertyChanged (Properties::legato);
|
||||
}
|
||||
|
||||
void
|
||||
Trigger::set_follow_action_probability (int n)
|
||||
{
|
||||
|
|
@ -176,6 +184,26 @@ Trigger::startup()
|
|||
PropertyChanged (ARDOUR::Properties::running);
|
||||
}
|
||||
|
||||
void
|
||||
Trigger::jump_start()
|
||||
{
|
||||
/* this is used when we start a new trigger in legato mode. We do not
|
||||
wait for quantization.
|
||||
*/
|
||||
_state = Running;
|
||||
PropertyChanged (ARDOUR::Properties::running);
|
||||
}
|
||||
|
||||
void
|
||||
Trigger::jump_stop()
|
||||
{
|
||||
/* this is used when we start a new trigger in legato mode. We do not
|
||||
wait for quantization.
|
||||
*/
|
||||
_state = Stopped;
|
||||
PropertyChanged (ARDOUR::Properties::running);
|
||||
}
|
||||
|
||||
void
|
||||
Trigger::process_state_requests ()
|
||||
{
|
||||
|
|
@ -188,7 +216,7 @@ Trigger::process_state_requests ()
|
|||
switch (new_state) {
|
||||
case Stopped:
|
||||
if (_state != WaitingToStop) {
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 %2 -> %3\n", index(), enum_2_string (_state), enum_2_string (WaitingToStop)));
|
||||
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);
|
||||
}
|
||||
|
|
@ -219,21 +247,22 @@ Trigger::process_state_requests ()
|
|||
case Running:
|
||||
switch (launch_style()) {
|
||||
case OneShot:
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 %2 -> %3\n", index(), enum_2_string (Running), enum_2_string (WaitingForRetrigger)));
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 oneshot %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)));
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 %2 gate/toggle/repeat => %3\n", index(), enum_2_string (Running), enum_2_string (WaitingToStop)));
|
||||
_state = WaitingToStop;
|
||||
_box.clear_implicit ();
|
||||
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)));
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 %2 stopped => %3\n", index(), enum_2_string (Stopped), enum_2_string (WaitingToStart)));
|
||||
_box.queue_explict (this);
|
||||
break;
|
||||
|
||||
|
|
@ -353,6 +382,20 @@ AudioTrigger::startup ()
|
|||
retrigger ();
|
||||
}
|
||||
|
||||
void
|
||||
AudioTrigger::jump_start ()
|
||||
{
|
||||
Trigger::jump_start ();
|
||||
retrigger ();
|
||||
}
|
||||
|
||||
void
|
||||
AudioTrigger::jump_stop ()
|
||||
{
|
||||
Trigger::jump_stop ();
|
||||
retrigger ();
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
AudioTrigger::get_state (void)
|
||||
{
|
||||
|
|
@ -655,6 +698,7 @@ void
|
|||
AudioTrigger::retrigger ()
|
||||
{
|
||||
read_index = _start_offset + _legato_offset;
|
||||
_legato_offset = 0; /* used one time only */
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 retriggered to %2\n", _index, read_index));
|
||||
}
|
||||
|
||||
|
|
@ -691,7 +735,7 @@ AudioTrigger::run (BufferSet& bufs, pframes_t nframes, pframes_t dest_offset, bo
|
|||
|
||||
/* We reached the end */
|
||||
|
||||
if ((_launch_style == Repeat) || (_box.peak_next_trigger() == this)) { /* self repeat */
|
||||
if ((_launch_style == Repeat) || (_box.peek_next_trigger() == this)) { /* self repeat */
|
||||
nframes -= this_read;
|
||||
dest_offset += this_read;
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 reached end, but set to loop, so retrigger\n", index()));
|
||||
|
|
@ -771,6 +815,12 @@ TriggerBox::TriggerBox (Session& s, DataType dt)
|
|||
midi_trigger_map.insert (midi_trigger_map.end(), std::make_pair (uint8_t (69), 9));
|
||||
}
|
||||
|
||||
void
|
||||
TriggerBox::clear_implicit ()
|
||||
{
|
||||
implicit_queue.reset ();
|
||||
}
|
||||
|
||||
void
|
||||
TriggerBox::queue_explict (Trigger* t)
|
||||
{
|
||||
|
|
@ -796,8 +846,12 @@ TriggerBox::queue_implicit (Trigger* t)
|
|||
}
|
||||
|
||||
Trigger*
|
||||
TriggerBox::peak_next_trigger ()
|
||||
TriggerBox::peek_next_trigger ()
|
||||
{
|
||||
/* allows us to check if there's a next trigger queued, without
|
||||
* actually reading it from either of the queues.
|
||||
*/
|
||||
|
||||
RingBuffer<Trigger*>::rw_vector rwv;
|
||||
|
||||
explicit_queue.get_read_vector (&rwv);
|
||||
|
|
@ -1015,6 +1069,8 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
|
|||
all_triggers[n]->process_state_requests ();
|
||||
}
|
||||
|
||||
Trigger* nxt = 0;
|
||||
|
||||
if (!currently_playing) {
|
||||
if ((currently_playing = get_next_trigger ()) != 0) {
|
||||
currently_playing->startup ();
|
||||
|
|
@ -1031,11 +1087,6 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
|
|||
_session.start_transport_from_processor ();
|
||||
}
|
||||
|
||||
if (_stop_all) {
|
||||
stop_all ();
|
||||
_stop_all = false;
|
||||
}
|
||||
|
||||
timepos_t start (start_sample);
|
||||
timepos_t end (end_sample);
|
||||
Temporal::Beats start_beats (start.beats());
|
||||
|
|
@ -1044,6 +1095,47 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
|
|||
size_t max_chans = 0;
|
||||
bool first = false;
|
||||
|
||||
/* see if there's another trigger explicitly queued that has legato set. */
|
||||
|
||||
RingBuffer<Trigger*>::rw_vector rwv;
|
||||
explicit_queue.get_read_vector (&rwv);
|
||||
|
||||
if (rwv.len[0] > 0) {
|
||||
|
||||
/* actually fetch it (guaranteed to pull from the explicit queue */
|
||||
|
||||
nxt = get_next_trigger ();
|
||||
|
||||
/* if user triggered same clip, with legato set, then there is
|
||||
* nothing to do
|
||||
*/
|
||||
|
||||
if (nxt != currently_playing) {
|
||||
|
||||
if (nxt->legato()) {
|
||||
/* We want to start this trigger immediately, without
|
||||
* waiting for quantization points, and it should start
|
||||
* playing at the same internal offset as the current
|
||||
* trigger.
|
||||
*/
|
||||
|
||||
nxt->set_legato_offset (currently_playing->current_pos());
|
||||
nxt->jump_start ();
|
||||
currently_playing->jump_stop ();
|
||||
prepare_next (nxt->index());
|
||||
/* and switch */
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 => %2 switched to in legato mode\n", currently_playing->index(), nxt->index()));
|
||||
currently_playing = nxt;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_stop_all) {
|
||||
stop_all ();
|
||||
_stop_all = false;
|
||||
}
|
||||
|
||||
while (currently_playing) {
|
||||
|
||||
assert (currently_playing->state() >= Trigger::WaitingToStart);
|
||||
|
|
@ -1164,6 +1256,8 @@ TriggerBox::prepare_next (size_t current)
|
|||
{
|
||||
int nxt = determine_next_trigger (current);
|
||||
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("nxt for %1 = %2\n", current, nxt));
|
||||
|
||||
if (nxt >= 0) {
|
||||
queue_implicit (all_triggers[nxt]);
|
||||
}
|
||||
|
|
@ -1234,6 +1328,7 @@ TriggerBox::determine_next_trigger (size_t current)
|
|||
}
|
||||
|
||||
if (n == current) {
|
||||
cerr << "outa here\n";
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1370,5 +1465,3 @@ TriggerBox::set_state (const XMLNode& node, int version)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*--------------------*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue