mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 23:35:03 +01:00
triggerbox: more substantial changes to the new (justifiable) design; audio triggers seem ok, MIDI triggers untested
This commit is contained in:
parent
59b012ddb0
commit
2b6b7226b0
3 changed files with 188 additions and 199 deletions
|
|
@ -63,13 +63,12 @@ class SideChain;
|
||||||
class LIBARDOUR_API Trigger : public PBD::Stateful {
|
class LIBARDOUR_API Trigger : public PBD::Stateful {
|
||||||
public:
|
public:
|
||||||
enum State {
|
enum State {
|
||||||
None = 0, /* mostly for _requested_state */
|
Stopped,
|
||||||
Stopped = 1,
|
WaitingToStart,
|
||||||
WaitingToStart = 2,
|
Running,
|
||||||
Running = 3,
|
WaitingForRetrigger,
|
||||||
WaitingForRetrigger = 4,
|
WaitingToStop,
|
||||||
WaitingToStop = 5,
|
Stopping
|
||||||
Stopping = 6
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Trigger (uint64_t index, TriggerBox&);
|
Trigger (uint64_t index, TriggerBox&);
|
||||||
|
|
@ -86,6 +85,9 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
||||||
/* explicitly call for the trigger to stop */
|
/* explicitly call for the trigger to stop */
|
||||||
void request_stop ();
|
void request_stop ();
|
||||||
|
|
||||||
|
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, bool first, double bpm) = 0;
|
||||||
virtual void set_start (timepos_t const &) = 0;
|
virtual void set_start (timepos_t const &) = 0;
|
||||||
virtual void set_end (timepos_t const &) = 0;
|
virtual void set_end (timepos_t const &) = 0;
|
||||||
virtual void set_length (timecnt_t const &) = 0;
|
virtual void set_length (timecnt_t const &) = 0;
|
||||||
|
|
@ -116,6 +118,7 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
||||||
void set_launch_style (LaunchStyle);
|
void set_launch_style (LaunchStyle);
|
||||||
|
|
||||||
enum FollowAction {
|
enum FollowAction {
|
||||||
|
None,
|
||||||
Stop,
|
Stop,
|
||||||
Again,
|
Again,
|
||||||
QueuedTrigger, /* DP-style */
|
QueuedTrigger, /* DP-style */
|
||||||
|
|
@ -150,22 +153,7 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
||||||
XMLNode& get_state (void);
|
XMLNode& get_state (void);
|
||||||
int set_state (const XMLNode&, int version);
|
int set_state (const XMLNode&, int version);
|
||||||
|
|
||||||
enum RunResult {
|
pframes_t maybe_compute_next_transition (samplepos_t start_sample, Temporal::Beats const & start, Temporal::Beats const & end, pframes_t dest_offset, bool passthru);
|
||||||
Relax = 0,
|
|
||||||
RemoveTrigger = 0x1,
|
|
||||||
ReadMore = 0x2,
|
|
||||||
FillSilence = 0x4,
|
|
||||||
ChangeTriggers = 0x8
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RunType {
|
|
||||||
RunEnd,
|
|
||||||
RunStart,
|
|
||||||
RunAll,
|
|
||||||
RunNone,
|
|
||||||
};
|
|
||||||
|
|
||||||
RunType maybe_compute_next_transition (Temporal::Beats const & start, Temporal::Beats const & end);
|
|
||||||
|
|
||||||
void set_next_trigger (int n);
|
void set_next_trigger (int n);
|
||||||
int next_trigger() const { return _next_trigger; }
|
int next_trigger() const { return _next_trigger; }
|
||||||
|
|
@ -242,7 +230,7 @@ class LIBARDOUR_API AudioTrigger : public Trigger {
|
||||||
AudioTrigger (uint64_t index, TriggerBox&);
|
AudioTrigger (uint64_t index, TriggerBox&);
|
||||||
~AudioTrigger ();
|
~AudioTrigger ();
|
||||||
|
|
||||||
pframes_t run (BufferSet&, pframes_t nframes, pframes_t offset, bool first, double bpm);
|
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, bool first, double bpm);
|
||||||
|
|
||||||
void set_start (timepos_t const &);
|
void set_start (timepos_t const &);
|
||||||
void set_end (timepos_t const &);
|
void set_end (timepos_t const &);
|
||||||
|
|
@ -288,7 +276,6 @@ class LIBARDOUR_API AudioTrigger : public Trigger {
|
||||||
|
|
||||||
void drop_data ();
|
void drop_data ();
|
||||||
int load_data (boost::shared_ptr<AudioRegion>);
|
int load_data (boost::shared_ptr<AudioRegion>);
|
||||||
RunResult at_end ();
|
|
||||||
void determine_tempo ();
|
void determine_tempo ();
|
||||||
void setup_stretcher ();
|
void setup_stretcher ();
|
||||||
};
|
};
|
||||||
|
|
@ -299,7 +286,7 @@ class LIBARDOUR_API MIDITrigger : public Trigger {
|
||||||
MIDITrigger (uint64_t index, TriggerBox&);
|
MIDITrigger (uint64_t index, TriggerBox&);
|
||||||
~MIDITrigger ();
|
~MIDITrigger ();
|
||||||
|
|
||||||
pframes_t run (BufferSet&, samplepos_t start_sample, samplepos_t end_sample, pframes_t nframes, pframes_t offset, bool first, double bpm);
|
pframes_t 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, bool passthru, double bpm);
|
||||||
|
|
||||||
void set_start (timepos_t const &);
|
void set_start (timepos_t const &);
|
||||||
void set_end (timepos_t const &);
|
void set_end (timepos_t const &);
|
||||||
|
|
@ -342,7 +329,6 @@ class LIBARDOUR_API MIDITrigger : public Trigger {
|
||||||
boost::shared_ptr<MidiModel> model;
|
boost::shared_ptr<MidiModel> model;
|
||||||
|
|
||||||
int load_data (boost::shared_ptr<MidiRegion>);
|
int load_data (boost::shared_ptr<MidiRegion>);
|
||||||
RunResult at_end ();
|
|
||||||
void compute_and_set_length ();
|
void compute_and_set_length ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -845,7 +845,6 @@ setup_enum_writer ()
|
||||||
REGISTER_ENUM (RollIfAppropriate);
|
REGISTER_ENUM (RollIfAppropriate);
|
||||||
REGISTER (_LocateTransportDisposition);
|
REGISTER (_LocateTransportDisposition);
|
||||||
|
|
||||||
REGISTER_CLASS_ENUM (Trigger, None);
|
|
||||||
REGISTER_CLASS_ENUM (Trigger, Stopped);
|
REGISTER_CLASS_ENUM (Trigger, Stopped);
|
||||||
REGISTER_CLASS_ENUM (Trigger, WaitingToStart);
|
REGISTER_CLASS_ENUM (Trigger, WaitingToStart);
|
||||||
REGISTER_CLASS_ENUM (Trigger, Running);
|
REGISTER_CLASS_ENUM (Trigger, Running);
|
||||||
|
|
|
||||||
|
|
@ -336,10 +336,6 @@ Trigger::process_state_requests ()
|
||||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 handling bang with state = %2\n", index(), enum_2_string (_state)));
|
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 handling bang with state = %2\n", index(), enum_2_string (_state)));
|
||||||
|
|
||||||
switch (_state) {
|
switch (_state) {
|
||||||
case None:
|
|
||||||
abort ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Running:
|
case Running:
|
||||||
switch (launch_style()) {
|
switch (launch_style()) {
|
||||||
case OneShot:
|
case OneShot:
|
||||||
|
|
@ -388,22 +384,20 @@ Trigger::process_state_requests ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger::RunType
|
pframes_t
|
||||||
Trigger::maybe_compute_next_transition (Temporal::Beats const & start, Temporal::Beats const & end)
|
Trigger::maybe_compute_next_transition (samplepos_t start_sample, Temporal::Beats const & start, Temporal::Beats const & end, pframes_t dest_offset, bool passthru)
|
||||||
{
|
{
|
||||||
using namespace Temporal;
|
using namespace Temporal;
|
||||||
|
|
||||||
|
/* This should never be called by a stopped trigger */
|
||||||
|
|
||||||
|
assert (_state != Stopped);
|
||||||
|
|
||||||
/* In these states, we are not waiting for a transition */
|
/* In these states, we are not waiting for a transition */
|
||||||
|
|
||||||
switch (_state) {
|
if (_state == Running || _state == Stopping) {
|
||||||
case Stopped:
|
/* will cover everything */
|
||||||
return RunNone;
|
return dest_offset;
|
||||||
case Running:
|
|
||||||
return RunAll;
|
|
||||||
case Stopping:
|
|
||||||
return RunAll;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
timepos_t transition_time (BeatTime);
|
timepos_t transition_time (BeatTime);
|
||||||
|
|
@ -412,6 +406,10 @@ Trigger::maybe_compute_next_transition (Temporal::Beats const & start, Temporal:
|
||||||
|
|
||||||
/* XXX need to use global grid here is quantization == zero */
|
/* XXX need to use global grid here is quantization == zero */
|
||||||
|
|
||||||
|
/* Given the value of @param start, determine, based on the
|
||||||
|
* quantization, the next time for a transition.
|
||||||
|
*/
|
||||||
|
|
||||||
if (_quantization.bars == 0) {
|
if (_quantization.bars == 0) {
|
||||||
Temporal::Beats transition_beats = start.round_up_to_multiple (Temporal::Beats (_quantization.beats, _quantization.ticks));
|
Temporal::Beats transition_beats = start.round_up_to_multiple (Temporal::Beats (_quantization.beats, _quantization.ticks));
|
||||||
transition_bbt = tmap->bbt_at (transition_beats);
|
transition_bbt = tmap->bbt_at (transition_beats);
|
||||||
|
|
@ -425,42 +423,84 @@ Trigger::maybe_compute_next_transition (Temporal::Beats const & start, Temporal:
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 quantized with %5 transition at %2, sb %3 eb %4\n", index(), transition_time.beats(), start, end, _quantization));
|
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 quantized with %5 transition at %2, sb %3 eb %4\n", index(), transition_time.beats(), start, end, _quantization));
|
||||||
|
|
||||||
|
/* See if this time falls within the range of time given to us */
|
||||||
|
|
||||||
if (transition_time.beats() >= start && transition_time < end) {
|
if (transition_time.beats() >= start && transition_time < end) {
|
||||||
|
|
||||||
|
/* transition time has arrived! let's figure out what're doing:
|
||||||
|
* stopping, starting, retriggering
|
||||||
|
*/
|
||||||
|
|
||||||
transition_samples = transition_time.samples();
|
transition_samples = transition_time.samples();
|
||||||
transition_beats = transition_time.beats ();
|
transition_beats = transition_time.beats ();
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 in range, should start/stop at %2 aka %3\n", index(), transition_samples, transition_beats));
|
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 in range, should start/stop at %2 aka %3\n", index(), transition_samples, transition_beats));
|
||||||
|
|
||||||
if (_state == WaitingToStop) {
|
switch (_state) {
|
||||||
|
|
||||||
|
case WaitingToStop:
|
||||||
_state = Stopping;
|
_state = Stopping;
|
||||||
PropertyChanged (ARDOUR::Properties::running);
|
PropertyChanged (ARDOUR::Properties::running);
|
||||||
return RunEnd;
|
|
||||||
} else if (_state == WaitingToStart) {
|
/* trigger will reach it's end somewhere within this
|
||||||
retrigger ();
|
* process cycle, so compute the number of samples it
|
||||||
_state = Running;
|
* should generate.
|
||||||
expected_end_sample = tmap->sample_at (tmap->bbt_walk(transition_bbt, BBT_Offset (round (_barcnt), 0, 0)));
|
*/
|
||||||
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);
|
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 will stop somewhere in the middle of run()\n", name()));
|
||||||
return RunStart;
|
|
||||||
} else if (_state == WaitingForRetrigger) {
|
/* offset within the buffer(s) for output remains
|
||||||
retrigger ();
|
unchanged, since we will write from the first
|
||||||
_state = Running;
|
location corresponding to start
|
||||||
expected_end_sample = tmap->sample_at (tmap->bbt_walk(transition_bbt, BBT_Offset (round (_barcnt), 0, 0)));
|
|
||||||
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);
|
|
||||||
return RunAll;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (_state == WaitingForRetrigger || _state == WaitingToStop) {
|
|
||||||
/* retrigger time has not been reached, just continue
|
|
||||||
to play normally until then.
|
|
||||||
*/
|
*/
|
||||||
return RunAll;
|
break;
|
||||||
|
|
||||||
|
case WaitingToStart:
|
||||||
|
retrigger ();
|
||||||
|
_state = Running;
|
||||||
|
expected_end_sample = tmap->sample_at (tmap->bbt_walk(transition_bbt, BBT_Offset (round (_barcnt), 0, 0)));
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* trigger will start somewhere within this process
|
||||||
|
* cycle. Compute the sample offset where any audio
|
||||||
|
* should end up, and the number of samples it should generate.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dest_offset += std::max (samplepos_t (0), transition_samples - start_sample);
|
||||||
|
|
||||||
|
if (!passthru) {
|
||||||
|
/* XXX need to silence start of buffers up to dest_offset */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WaitingForRetrigger:
|
||||||
|
retrigger ();
|
||||||
|
_state = Running;
|
||||||
|
expected_end_sample = tmap->sample_at (tmap->bbt_walk(transition_bbt, BBT_Offset (round (_barcnt), 0, 0)));
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* trigger is just running normally, and will fill
|
||||||
|
* buffers entirely.
|
||||||
|
*/
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fatal << string_compose (_("programming error: %1"), "impossible trigger state in ::maybe_compute_next_transition()") << endmsg;
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* retrigger time has not been reached, just continue
|
||||||
|
to play normally until then.
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return RunNone;
|
return dest_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------*/
|
/*--------------------*/
|
||||||
|
|
@ -778,7 +818,7 @@ AudioTrigger::retrigger ()
|
||||||
}
|
}
|
||||||
|
|
||||||
pframes_t
|
pframes_t
|
||||||
AudioTrigger::run (BufferSet& bufs, pframes_t nframes, pframes_t dest_offset, bool passthru, double bpm)
|
AudioTrigger::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, bool passthru, double bpm)
|
||||||
{
|
{
|
||||||
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(_region);
|
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(_region);
|
||||||
const uint32_t nchans = ar->n_channels();
|
const uint32_t nchans = ar->n_channels();
|
||||||
|
|
@ -788,8 +828,23 @@ AudioTrigger::run (BufferSet& bufs, pframes_t nframes, pframes_t dest_offset, bo
|
||||||
Sample* bufp[nchans];
|
Sample* bufp[nchans];
|
||||||
const bool stretching = (_apparent_tempo != 0.);
|
const bool stretching = (_apparent_tempo != 0.);
|
||||||
|
|
||||||
assert (ar);
|
/* see if we're going to start or stop or retrigger in this run() call */
|
||||||
assert (active());
|
dest_offset = maybe_compute_next_transition (start_sample, start, end, dest_offset, passthru);
|
||||||
|
|
||||||
|
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 after checking for transition, state = %2\n", name(), enum_2_string (_state)));
|
||||||
|
|
||||||
|
switch (_state) {
|
||||||
|
case Stopped:
|
||||||
|
case WaitingForRetrigger:
|
||||||
|
case WaitingToStart:
|
||||||
|
/* did everything we could do */
|
||||||
|
return nframes;
|
||||||
|
case Running:
|
||||||
|
case WaitingToStop:
|
||||||
|
case Stopping:
|
||||||
|
/* stuff to do */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* We use session scratch buffers for both padding the start of the
|
/* We use session scratch buffers for both padding the start of the
|
||||||
* input to RubberBand, and to hold the output. Because of this dual
|
* input to RubberBand, and to hold the output. Because of this dual
|
||||||
|
|
@ -1209,7 +1264,9 @@ MIDITrigger::reload (BufferSet&, void*)
|
||||||
}
|
}
|
||||||
|
|
||||||
pframes_t
|
pframes_t
|
||||||
MIDITrigger::run (BufferSet& bufs, samplepos_t start, samplepos_t end, pframes_t nframes, pframes_t dest_offset, bool passthru, double bpm)
|
MIDITrigger::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, bool passthru, double bpm)
|
||||||
{
|
{
|
||||||
MidiBuffer& mb (bufs.get_midi (0));
|
MidiBuffer& mb (bufs.get_midi (0));
|
||||||
typedef Evoral::Event<MidiModel::TimeType> MidiEvent;
|
typedef Evoral::Event<MidiModel::TimeType> MidiEvent;
|
||||||
|
|
@ -1218,11 +1275,25 @@ MIDITrigger::run (BufferSet& bufs, samplepos_t start, samplepos_t end, pframes_t
|
||||||
Temporal::TempoMap::SharedPtr tmap (Temporal::TempoMap::use());
|
Temporal::TempoMap::SharedPtr tmap (Temporal::TempoMap::use());
|
||||||
samplepos_t last_event_samples = 0;
|
samplepos_t last_event_samples = 0;
|
||||||
|
|
||||||
|
/* see if we're going to start or stop or retrigger in this run() call */
|
||||||
|
dest_offset = maybe_compute_next_transition (start_sample, start_beats, end_beats, dest_offset, passthru);
|
||||||
|
|
||||||
|
switch (_state) {
|
||||||
|
case Stopped:
|
||||||
|
case WaitingForRetrigger:
|
||||||
|
case WaitingToStart:
|
||||||
|
return nframes;
|
||||||
|
case Running:
|
||||||
|
case WaitingToStop:
|
||||||
|
case Stopping:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!passthru) {
|
if (!passthru) {
|
||||||
mb.clear ();
|
mb.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (iter != model->end()) {
|
||||||
|
|
||||||
MidiEvent const & next_event (*iter);
|
MidiEvent const & next_event (*iter);
|
||||||
|
|
||||||
|
|
@ -1238,15 +1309,27 @@ MIDITrigger::run (BufferSet& bufs, samplepos_t start, samplepos_t end, pframes_t
|
||||||
|
|
||||||
const samplepos_t timeline_samples = tmap->sample_at (effective_time);
|
const samplepos_t timeline_samples = tmap->sample_at (effective_time);
|
||||||
|
|
||||||
if (timeline_samples > end) {
|
if (timeline_samples >= end_sample) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now we have to convert to a position within the buffer we
|
/* Now we have to convert to a position within the buffer we
|
||||||
* are writing to.
|
* are writing to.
|
||||||
|
*
|
||||||
|
* There's a slight complication here, because both
|
||||||
|
* start_sample and dest_offset reflect an offset from the
|
||||||
|
* start of the buffer that our parent (TriggerBox) processor
|
||||||
|
* is handling in its own run() method. start_sample may have
|
||||||
|
* been adjusted to reflect a previous Trigger's processing
|
||||||
|
* during this run cycle, and so has dest_offset.
|
||||||
|
*
|
||||||
|
* Therefore, when computing the buffer sample for this MIDI
|
||||||
|
* event, we only consider one of the two values, not both. If
|
||||||
|
* we use both, we will double the "offset" that occurs if
|
||||||
|
* another Trigger ran during this process cycle.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
samplepos_t buffer_samples = timeline_samples - start + dest_offset;
|
samplepos_t buffer_samples = timeline_samples - start_sample + dest_offset;
|
||||||
last_event_samples = buffer_samples;
|
last_event_samples = buffer_samples;
|
||||||
|
|
||||||
const Evoral::Event<MidiBuffer::TimeType> ev (Evoral::MIDI_EVENT, buffer_samples, next_event.size(), const_cast<uint8_t*>(next_event.buffer()), false);
|
const Evoral::Event<MidiBuffer::TimeType> ev (Evoral::MIDI_EVENT, buffer_samples, next_event.size(), const_cast<uint8_t*>(next_event.buffer()), false);
|
||||||
|
|
@ -1256,49 +1339,54 @@ MIDITrigger::run (BufferSet& bufs, samplepos_t start, samplepos_t end, pframes_t
|
||||||
last_event_beats = next_event.time();
|
last_event_beats = next_event.time();
|
||||||
|
|
||||||
++iter;
|
++iter;
|
||||||
|
|
||||||
if (iter == model->end()) {
|
|
||||||
|
|
||||||
/* We reached the end */
|
|
||||||
|
|
||||||
_loop_cnt++;
|
|
||||||
_state = Stopped;
|
|
||||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 reached end, now stopped\n", index()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last_event_samples) {
|
|
||||||
nframes -= (last_event_samples - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_state == Stopping) {
|
if (_state == Stopping) {
|
||||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 was stopping, now stopped\n", index()));
|
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 was stopping, now stopped\n", index()));
|
||||||
tracker.resolve_notes (mb, nframes);
|
tracker.resolve_notes (mb, nframes);
|
||||||
shutdown ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_state == Stopped) {
|
if (iter == model->end()) {
|
||||||
if (_loop_cnt == _follow_count) {
|
|
||||||
/* have played the specified number of times, we're done */
|
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 loop cnt %2 satisfied, now stopped\n", index(), _follow_count));
|
/* We reached the end */
|
||||||
shutdown ();
|
|
||||||
|
|
||||||
} else {
|
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 reached end\n", index()));
|
||||||
|
|
||||||
/* reached the end, but we haven't done that enough
|
if (!(_state == Stopping)) {
|
||||||
* times yet for a follow action/stop to take
|
_loop_cnt++;
|
||||||
* effect. Time to get played again.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 was stopping, now waiting to retrigger, loop cnt %2 fc %3\n", index(), _loop_cnt, _follow_count));
|
if (_loop_cnt == _follow_count) {
|
||||||
/* we will "restart" at the beginning of the
|
/* have played the specified number of times, we're done */
|
||||||
next iteration of the trigger.
|
|
||||||
*/
|
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 loop cnt %2 satisfied, now stopped\n", index(), _follow_count));
|
||||||
transition_beats = transition_beats + data_length;
|
shutdown ();
|
||||||
retrigger ();
|
|
||||||
_state = WaitingToStart;
|
} else {
|
||||||
|
|
||||||
|
/* reached the end, but we haven't done that enough
|
||||||
|
* times yet for a follow action/stop to take
|
||||||
|
* effect. Time to get played again.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 was stopping, now waiting to retrigger, loop cnt %2 fc %3\n", index(), _loop_cnt, _follow_count));
|
||||||
|
/* we will "restart" at the beginning of the
|
||||||
|
next iteration of the trigger.
|
||||||
|
*/
|
||||||
|
transition_beats = transition_beats + data_length;
|
||||||
|
retrigger ();
|
||||||
|
_state = WaitingToStart;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* the time we processed spans from start to the last event */
|
||||||
|
|
||||||
|
nframes -= (last_event_samples - start_sample);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* we didn't reach the end of the MIDI data, ergo we covered
|
||||||
|
the entire timespan passed into us.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return nframes;
|
return nframes;
|
||||||
|
|
@ -1724,7 +1812,7 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
|
||||||
|
|
||||||
if (!check_active()) {
|
if (!check_active()) {
|
||||||
return;
|
return;
|
||||||
}
|
| ||||||