mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-24 07:27:44 +01:00
step sequencer now follows tempo map precisely; beatbox loses some functionality (for now)
This commit is contained in:
parent
be831c6870
commit
d682e61b99
3 changed files with 94 additions and 328 deletions
|
|
@ -95,6 +95,7 @@ class BeatBox : public ARDOUR::Processor {
|
|||
int _meter_beat_type;
|
||||
superclock_t superclock_cnt;
|
||||
superclock_t last_start;
|
||||
superclock_t last_end;
|
||||
Timecode::BBT_Time last_time;
|
||||
|
||||
int _sample_rate;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#include <glibmm/threads.h>
|
||||
|
||||
#include "temporal/types.h"
|
||||
#include "temporal/bbt_time.h"
|
||||
#include "temporal/beats.h"
|
||||
|
||||
#include "ardour/mode.h"
|
||||
#include "ardour/types.h"
|
||||
|
|
@ -33,9 +33,13 @@
|
|||
namespace ARDOUR {
|
||||
|
||||
class MidiBuffer;
|
||||
|
||||
class MidiStateTracker;
|
||||
class StepSequencer;
|
||||
class StepSequence;
|
||||
class TempoMap;
|
||||
|
||||
typedef std::pair<Temporal::Beats,samplepos_t> BeatPosition;
|
||||
typedef std::vector<BeatPosition> BeatPositions;
|
||||
|
||||
class Step {
|
||||
public:
|
||||
|
|
@ -44,10 +48,10 @@ class Step {
|
|||
RelativePitch
|
||||
};
|
||||
|
||||
Step (StepSequence&, Timecode::BBT_Time const & nominal_on);
|
||||
Step (StepSequence&, Temporal::Beats const & beat);
|
||||
~Step ();
|
||||
|
||||
void set_note (double note, double velocity = 0.5, double duration = 0.9, int n = 0);
|
||||
void set_note (double note, double velocity = 0.5, int32_t duration = 1, int n = 0);
|
||||
void set_chord (size_t note_cnt, double* notes);
|
||||
void set_parameter (int number, double value, int n = 0);
|
||||
|
||||
|
|
@ -56,11 +60,10 @@ class Step {
|
|||
|
||||
double note (size_t n = 0) const { return _notes[n].number; }
|
||||
double velocity (size_t n = 0) const { return _notes[n].velocity; }
|
||||
Timecode::BBT_Time beat_duration (size_t n = 0) const;
|
||||
double duration (size_t n = 0) const { return _notes[n].duration; }
|
||||
int32_t duration (size_t n = 0) const { return _notes[n].duration; }
|
||||
|
||||
void set_offset (Timecode::BBT_Time const &, size_t n = 0);
|
||||
Timecode::BBT_Time offset (size_t n = 0) const { return _notes[n].offset; }
|
||||
void set_offset (Temporal::Beats const &, size_t n = 0);
|
||||
Temporal::Beats offset (size_t n = 0) const { return _notes[n].offset; }
|
||||
|
||||
int parameter (size_t n = 0) const { return _parameters[n].parameter; }
|
||||
int parameter_value (size_t n = 0) const { return _parameters[n].value; }
|
||||
|
|
@ -71,16 +74,22 @@ class Step {
|
|||
void set_repeat (size_t r);
|
||||
size_t repeat() const { return _repeat; }
|
||||
|
||||
void set_nominal_on (Timecode::BBT_Time const &);
|
||||
bool run (MidiBuffer& buf, Timecode::BBT_Time const & start, Timecode::BBT_Time const & end, samplecnt_t beat_samples);
|
||||
void set_beat (Temporal::Beats const & beat);
|
||||
Temporal::Beats beat () const { return _nominal_beat; }
|
||||
|
||||
bool run (MidiBuffer& buf, bool running, samplepos_t, samplepos_t, MidiStateTracker&);
|
||||
|
||||
bool skipped() const { return _skipped; }
|
||||
void set_skipped (bool);
|
||||
|
||||
void set_timeline_offset (Temporal::Beats const &, Temporal::Beats const &);
|
||||
|
||||
private:
|
||||
StepSequence& _sequence;
|
||||
bool _enabled;
|
||||
Timecode::BBT_Time _nominal_on;
|
||||
Temporal::Beats timeline_offset;
|
||||
Temporal::Beats _nominal_beat;
|
||||
Temporal::Beats _scheduled_beat;
|
||||
bool _skipped;
|
||||
Mode _mode;
|
||||
|
||||
|
|
@ -95,14 +104,13 @@ class Step {
|
|||
double interval; /* semitones */
|
||||
};
|
||||
double velocity;
|
||||
double duration;
|
||||
Timecode::BBT_Time offset;
|
||||
int32_t duration;
|
||||
Temporal::Beats offset;
|
||||
bool on;
|
||||
Timecode::BBT_Time off_at;
|
||||
Temporal::Beats off_at;
|
||||
|
||||
Note () : number (-1), on (false) {}
|
||||
Note (double n, double v, double d, Timecode::BBT_Time o)
|
||||
: number (n), velocity (v), duration (d), offset (o), on (false) {}
|
||||
Note () : number (-1), velocity (0.5), duration (1), on (false) {}
|
||||
Note (double n, double v, double d, Temporal::Beats const & o) : number (n), velocity (v), duration (d), offset (o), on (false) {}
|
||||
};
|
||||
|
||||
static const int _notes_per_step = 5;
|
||||
|
|
@ -112,9 +120,11 @@ class Step {
|
|||
ParameterValue _parameters[_parameters_per_step];
|
||||
size_t _repeat;
|
||||
|
||||
void check_note (size_t n, MidiBuffer& buf, Timecode::BBT_Time const & start, Timecode::BBT_Time const & end, ARDOUR::samplecnt_t beat_samples);
|
||||
void check_parameter (size_t n, MidiBuffer& buf, Timecode::BBT_Time const & start, Timecode::BBT_Time const & end, ARDOUR::samplecnt_t beat_samples);
|
||||
void check_note (size_t n, MidiBuffer& buf, bool, samplepos_t, samplepos_t, MidiStateTracker&);
|
||||
void check_parameter (size_t n, MidiBuffer& buf, bool, samplepos_t, samplepos_t);
|
||||
|
||||
|
||||
StepSequencer& sequencer() const;
|
||||
};
|
||||
|
||||
class StepSequence
|
||||
|
|
@ -127,15 +137,21 @@ class StepSequence
|
|||
rd_random = 3
|
||||
};
|
||||
|
||||
StepSequence (size_t numsteps, StepSequencer &myseq);
|
||||
StepSequence (StepSequencer &myseq, size_t nsteps, Temporal::Beats const & step_size, Temporal::Beats const & bar_size);
|
||||
~StepSequence ();
|
||||
|
||||
void startup (Temporal::Beats const & start, Temporal::Beats const & offset);
|
||||
|
||||
Temporal::Beats bar_size() const { return _bar_size; }
|
||||
|
||||
double root() const { return _root; }
|
||||
void set_root (double n);
|
||||
|
||||
int channel() const { return _channel; }
|
||||
void set_channel (int);
|
||||
|
||||
Temporal::Beats wrap (Temporal::Beats const &) const;
|
||||
|
||||
MusicalMode mode() const { return _mode; }
|
||||
void set_mode (MusicalMode m);
|
||||
|
||||
|
|
@ -146,13 +162,14 @@ class StepSequence
|
|||
void set_end_step (size_t);
|
||||
void set_start_and_end_step (size_t, size_t);
|
||||
|
||||
void set_beat_divisor (size_t);
|
||||
size_t beat_divisor () const { return _beat_divisor; }
|
||||
void set_step_size (Temporal::Beats const &);
|
||||
Temporal::Beats step_size () const { return _step_size; }
|
||||
|
||||
void reset ();
|
||||
|
||||
void set_tempo (double quarters_per_minute, int sr);
|
||||
bool run (MidiBuffer& buf, Timecode::BBT_Time const & start, Timecode::BBT_Time const & end);
|
||||
bool run (MidiBuffer& buf, bool running, samplepos_t, samplepos_t, MidiStateTracker&);
|
||||
|
||||
StepSequencer& sequencer() const { return _sequencer; }
|
||||
|
||||
private:
|
||||
StepSequencer& _sequencer;
|
||||
|
|
@ -160,63 +177,52 @@ class StepSequence
|
|||
typedef std::vector<Step*> Steps;
|
||||
|
||||
Steps _steps;
|
||||
size_t _start;
|
||||
size_t _end;
|
||||
size_t _start; /* step count */
|
||||
size_t _end; /* step count */
|
||||
int _channel; /* MIDI channel */
|
||||
|
||||
Temporal::Beats _step_size;
|
||||
Temporal::Beats _bar_size;
|
||||
Temporal::Beats end_beat;
|
||||
|
||||
double _root;
|
||||
MusicalMode _mode;
|
||||
size_t _beat_divisor;
|
||||
int _channel;
|
||||
samplecnt_t _beat_samples;
|
||||
};
|
||||
|
||||
class StepSequencer {
|
||||
public:
|
||||
enum State {
|
||||
Running,
|
||||
Halted,
|
||||
Paused,
|
||||
};
|
||||
|
||||
StepSequencer (size_t nseqs, size_t nsteps);
|
||||
StepSequencer (TempoMap&, size_t nseqs, size_t nsteps, Temporal::Beats const & step_size, Temporal::Beats const & bar_size);
|
||||
~StepSequencer ();
|
||||
|
||||
Temporal::Beats duration() const;
|
||||
|
||||
void startup (Temporal::Beats const & start, Temporal::Beats const & offset);
|
||||
|
||||
Temporal::Beats step_size () const { return _step_size; }
|
||||
void set_step_size (Temporal::Beats const &);
|
||||
|
||||
void set_start_step (size_t);
|
||||
void set_end_step (size_t);
|
||||
void set_start_and_end_step (size_t, size_t);
|
||||
|
||||
bool running() const { return _state == Running; }
|
||||
bool halted() const { return _state == Halted; }
|
||||
bool paused() const { return _state == Paused; }
|
||||
|
||||
void start ();
|
||||
void halt (); /* stop everything, reset */
|
||||
void play ();
|
||||
void pause ();
|
||||
void toggle_pause ();
|
||||
void sync (); /* return all rows to start step */
|
||||
void reset (); /* return entire state to default */
|
||||
|
||||
double tempo() const; /* quarters per minute, not beats per minute */
|
||||
void set_tempo (double, int sr);
|
||||
bool run (MidiBuffer& buf, bool running, samplepos_t, samplepos_t, MidiStateTracker&);
|
||||
|
||||
bool run (MidiBuffer& buf, Timecode::BBT_Time const & start, Timecode::BBT_Time const & end);
|
||||
TempoMap& tempo_map() const { return _tempo_map; }
|
||||
|
||||
private:
|
||||
Glib::Threads::Mutex _sequence_lock;
|
||||
Glib::Threads::Mutex _state_lock;
|
||||
|
||||
typedef std::vector<StepSequence*> StepSequences;
|
||||
|
||||
StepSequences _sequences;
|
||||
State _state;
|
||||
|
||||
Timecode::BBT_Time _target_start;
|
||||
Timecode::BBT_Time _target_end;
|
||||
double _target_tempo;
|
||||
|
||||
Timecode::BBT_Time _start;
|
||||
Timecode::BBT_Time _end;
|
||||
double _tempo;
|
||||
TempoMap& _tempo_map;
|
||||
Temporal::Beats _step_size;
|
||||
int32_t _start;
|
||||
int32_t _end;
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "ardour/session.h"
|
||||
#include "ardour/smf_source.h"
|
||||
#include "ardour/step_sequencer.h"
|
||||
#include "ardour/tempo.h"
|
||||
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
|
@ -49,10 +50,9 @@ BeatBox::BeatBox (Session& s)
|
|||
, _start_requested (false)
|
||||
, _running (false)
|
||||
, _measures (2)
|
||||
, _tempo (120)
|
||||
, _tempo_request (0)
|
||||
, _meter_beats (4)
|
||||
, _meter_beat_type (4)
|
||||
, _tempo (-1.0)
|
||||
, _meter_beats (-1)
|
||||
, _meter_beat_type (-1)
|
||||
, superclock_cnt (0)
|
||||
, last_start (0)
|
||||
, whole_note_superclocks (0)
|
||||
|
|
@ -65,7 +65,7 @@ BeatBox::BeatBox (Session& s)
|
|||
, remove_queue (64)
|
||||
{
|
||||
_display_to_user = true;
|
||||
_sequencer = new StepSequencer (1, 32);
|
||||
_sequencer = new StepSequencer (s.tempo_map(), 1, 8, Temporal::Beats (1, 0), Temporal::Beats (4, 0));
|
||||
}
|
||||
|
||||
BeatBox::~BeatBox ()
|
||||
|
|
@ -73,24 +73,9 @@ BeatBox::~BeatBox ()
|
|||
delete _sequencer;
|
||||
}
|
||||
|
||||
void
|
||||
BeatBox::compute_tempo_clocks ()
|
||||
{
|
||||
whole_note_superclocks = (superclock_ticks_per_second * 60) / (_tempo / _meter_beat_type);
|
||||
beat_superclocks = whole_note_superclocks / _meter_beat_type;
|
||||
tick_superclocks = beat_superclocks / Timecode::BBT_Time::ticks_per_beat;
|
||||
measure_superclocks = beat_superclocks * _meter_beats;
|
||||
|
||||
_sequencer->set_tempo (_tempo, AudioEngine::instance()->sample_rate());
|
||||
}
|
||||
|
||||
void
|
||||
BeatBox::start ()
|
||||
{
|
||||
/* compute tempo, beat steps etc. */
|
||||
|
||||
compute_tempo_clocks ();
|
||||
|
||||
/* we can start */
|
||||
|
||||
_start_requested = true;
|
||||
|
|
@ -102,12 +87,6 @@ BeatBox::stop ()
|
|||
_start_requested = false;
|
||||
}
|
||||
|
||||
void
|
||||
BeatBox::set_tempo (float bpm)
|
||||
{
|
||||
_tempo_request = bpm;
|
||||
}
|
||||
|
||||
void
|
||||
BeatBox::silence (samplecnt_t, samplepos_t)
|
||||
{
|
||||
|
|
@ -115,276 +94,56 @@ BeatBox::silence (samplecnt_t, samplepos_t)
|
|||
}
|
||||
|
||||
void
|
||||
BeatBox::run (BufferSet& bufs, samplepos_t /*start_frame*/, samplepos_t /*end_frame*/, double speed, pframes_t nsamples, bool /*result_required*/)
|
||||
BeatBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nsamples, bool /*result_required*/)
|
||||
{
|
||||
if (bufs.count().n_midi() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_running) {
|
||||
if (_start_requested) {
|
||||
_running = true;
|
||||
last_start = superclock_cnt;
|
||||
}
|
||||
bool resolve = false;
|
||||
|
||||
} else {
|
||||
if (!_start_requested) {
|
||||
if (speed == 0) {
|
||||
if (_running) {
|
||||
resolve = true;
|
||||
_running = false;
|
||||
outbound_tracker.resolve_notes (bufs.get_midi (0), 0);
|
||||
}
|
||||
}
|
||||
|
||||
superclock_t superclocks = samples_to_superclock (nsamples, _session.sample_rate());
|
||||
if (speed != 0) {
|
||||
|
||||
if (_tempo_request) {
|
||||
double ratio = _tempo / _tempo_request;
|
||||
_tempo = _tempo_request;
|
||||
_tempo_request = 0;
|
||||
if (!_running || (last_end != start_sample)) {
|
||||
|
||||
compute_tempo_clocks ();
|
||||
|
||||
/* recompute all the event times based on the ratio between the
|
||||
* new and old tempo.
|
||||
*/
|
||||
|
||||
for (Events::iterator ee = _current_events.begin(); ee != _current_events.end(); ++ee) {
|
||||
(*ee)->time = llrintf ((*ee)->time * ratio);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_running) {
|
||||
superclock_cnt += superclocks;
|
||||
return;
|
||||
}
|
||||
|
||||
superclock_t process_start = superclock_cnt - last_start;
|
||||
superclock_t process_end = process_start + superclocks;
|
||||
const superclock_t loop_length = _measures * measure_superclocks;
|
||||
const superclock_t orig_superclocks = superclocks;
|
||||
|
||||
process_start %= loop_length;
|
||||
process_end %= loop_length;
|
||||
|
||||
Timecode::BBT_Time start = last_time;
|
||||
|
||||
last_time.bars = (process_end / measure_superclocks);
|
||||
last_time.beats = ((process_end - (last_time.bars * measure_superclocks)) / beat_superclocks);
|
||||
last_time.ticks = (process_end - (last_time.bars * measure_superclocks) - (last_time.beats * beat_superclocks)) / tick_superclocks;
|
||||
|
||||
/* change to 1-base */
|
||||
last_time.bars++;
|
||||
last_time.beats++;
|
||||
|
||||
std::cerr << "run " << process_start << " .. " << process_end << " => " << start << " .. " << last_time << endl;
|
||||
|
||||
bool two_pass_required;
|
||||
superclock_t offset = 0;
|
||||
|
||||
if (process_end < process_start) {
|
||||
two_pass_required = true;
|
||||
process_end = loop_length;
|
||||
superclocks = process_end - process_start;
|
||||
} else {
|
||||
two_pass_required = false;
|
||||
}
|
||||
|
||||
Evoral::Event<MidiBuffer::TimeType> in_event;
|
||||
|
||||
/* do this on the first pass only */
|
||||
MidiBuffer& buf = bufs.get_midi (0);
|
||||
|
||||
if (clear_pending) {
|
||||
|
||||
for (Events::iterator ee = _current_events.begin(); ee != _current_events.end(); ++ee) {
|
||||
delete *ee;
|
||||
}
|
||||
_current_events.clear ();
|
||||
_incomplete_notes.clear ();
|
||||
clear_pending = false;
|
||||
}
|
||||
|
||||
second_pass:
|
||||
|
||||
/* input */
|
||||
|
||||
for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ++e) {
|
||||
const Evoral::Event<MidiBuffer::TimeType>& in_event = *e;
|
||||
|
||||
superclock_t event_time = superclock_cnt + samples_to_superclock (in_event.time(), _session.sample_rate());
|
||||
superclock_t elapsed_time = event_time - last_start;
|
||||
superclock_t in_loop_time = elapsed_time % loop_length;
|
||||
superclock_t quantized_time;
|
||||
|
||||
if (_quantize_divisor != 0) {
|
||||
const superclock_t time_per_grid_unit = whole_note_superclocks / _quantize_divisor;
|
||||
|
||||
if ((in_event.buffer()[0] & 0xf0) == MIDI_CMD_NOTE_OFF) {
|
||||
|
||||
/* note off is special - it must be quantized
|
||||
* to at least 1 quantization "spacing" after
|
||||
* the corresponding note on.
|
||||
*/
|
||||
|
||||
/* look for the note on */
|
||||
|
||||
IncompleteNotes::iterator ee;
|
||||
bool found = false;
|
||||
|
||||
for (ee = _incomplete_notes.begin(); ee != _incomplete_notes.end(); ++ee) {
|
||||
/* check for same note and channel */
|
||||
if (((*ee)->buf[1] == in_event.buffer()[1]) && ((*ee)->buf[0] & 0xf) == (in_event.buffer()[0] & 0xf)) {
|
||||
quantized_time = (*ee)->time + time_per_grid_unit;
|
||||
_incomplete_notes.erase (ee);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
cerr << "Note off for " << (int) in_event.buffer()[1] << " seen without corresponding note on among " << _incomplete_notes.size() << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
quantized_time = (in_loop_time / time_per_grid_unit) * time_per_grid_unit;
|
||||
if (last_end != start_sample) {
|
||||
resolve = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
quantized_time = elapsed_time;
|
||||
}
|
||||
/* compute the beat position of this first "while-moving
|
||||
* run() call as an offset into the sequencer's current loop
|
||||
* length.
|
||||
*/
|
||||
|
||||
/* if computed quantized time is past the end of the loop, wrap
|
||||
it back around.
|
||||
*/
|
||||
TempoMap& tmap (_session.tempo_map());
|
||||
|
||||
quantized_time %= loop_length;
|
||||
const Temporal::Beats start_beat (tmap.beat_at_sample (start_sample));
|
||||
const int32_t tick_duration = _sequencer->duration().to_ticks();
|
||||
|
||||
if (in_event.size() > 24) {
|
||||
cerr << "Ignored large MIDI event\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
Event* new_event = new Event; // pool alloc, thread safe
|
||||
|
||||
if (!new_event) {
|
||||
cerr << "No more events, grow pool\n";
|
||||
continue;
|
||||
}
|
||||
Temporal::Beats closest_previous_loop_start = Temporal::Beats::ticks ((start_beat.to_ticks() / tick_duration) * tick_duration);
|
||||
Temporal::Beats offset = Temporal::Beats::ticks ((start_beat.to_ticks() % tick_duration));
|
||||
_sequencer->startup (closest_previous_loop_start, offset);
|
||||
last_start = start_sample;
|
||||
_running = true;
|
||||
|
||||
new_event->time = quantized_time;
|
||||
new_event->whole_note_superclocks = whole_note_superclocks;
|
||||
new_event->size = in_event.size();
|
||||
memcpy (new_event->buf, in_event.buffer(), new_event->size);
|
||||
|
||||
inbound_tracker.track (new_event->buf);
|
||||
|
||||
_current_events.insert (new_event);
|
||||
|
||||
if ((new_event->buf[0] & 0xf0) == MIDI_CMD_NOTE_ON) {
|
||||
_incomplete_notes.push_back (new_event);
|
||||
}
|
||||
}
|
||||
|
||||
/* Notes added from other threads */
|
||||
|
||||
Event* added_event;
|
||||
|
||||
if (offset == 0) {
|
||||
/* during first pass only */
|
||||
|
||||
while (add_queue.read (&added_event, 1)) {
|
||||
_current_events.insert (added_event);
|
||||
|
||||
if (((added_event->buf[0] & 0xf0) == MIDI_CMD_NOTE_ON) &&
|
||||
(added_event->time >= process_end || added_event->time < process_start)) {
|
||||
|
||||
/* won't hear it this time, so do immediate play. Off will follow in time */
|
||||
|
||||
/* e->buf is guaranteed to live through this process cycle, so do not alloc for a copy*/
|
||||
const Evoral::Event<MidiBuffer::TimeType> eev (Evoral::MIDI_EVENT, 0, added_event->size, added_event->buf, false);
|
||||
|
||||
if (buf.insert_event (eev)) {
|
||||
outbound_tracker.track (added_event->buf);
|
||||
}
|
||||
|
||||
/* insert a 1-time only note off to turn off this immediate note on */
|
||||
|
||||
Event* matching_note_off = new Event;
|
||||
matching_note_off->once = 1;
|
||||
matching_note_off->size = 3;
|
||||
|
||||
if (_quantize_divisor) {
|
||||
matching_note_off->time = process_start + (beat_superclocks / _quantize_divisor);
|
||||
} else {
|
||||
matching_note_off->time = process_start + beat_superclocks;
|
||||
}
|
||||
matching_note_off->time %= loop_length;
|
||||
|
||||
matching_note_off->buf[0] = MIDI_CMD_NOTE_OFF | (added_event->buf[0] & 0xf);
|
||||
matching_note_off->buf[1] = added_event->buf[1];
|
||||
matching_note_off->buf[2] = 0;
|
||||
|
||||
_current_events.insert (matching_note_off);
|
||||
}
|
||||
}
|
||||
if (resolve) {
|
||||
outbound_tracker.resolve_notes (bufs.get_midi(0), 0);
|
||||
}
|
||||
|
||||
/* Output */
|
||||
|
||||
#if 0
|
||||
|
||||
for (Events::iterator ee = _current_events.begin(); ee != _current_events.end(); ) {
|
||||
Event* e = (*ee);
|
||||
if ((e->once <= 1) && e->size && (e->time >= process_start && e->time < process_end)) {
|
||||
const samplepos_t sample_offset_in_buffer = superclock_to_samples (offset + e->time - process_start, _session.sample_rate());
|
||||
/* e->buf is guaranteed to live through this process cycle, so do not alloc for a copy*/
|
||||
const Evoral::Event<MidiBuffer::TimeType> eev (Evoral::MIDI_EVENT, sample_offset_in_buffer, e->size, e->buf, false);
|
||||
if (buf.insert_event (eev)) {
|
||||
outbound_tracker.track (e->buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (e->time >= process_end) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (e->once) {
|
||||
case 0:
|
||||
/* normal event, do nothing */
|
||||
++ee;
|
||||
break;
|
||||
case 1:
|
||||
/* delete it next process cycle */
|
||||
e->once++;
|
||||
++ee;
|
||||
break;
|
||||
default:
|
||||
delete e;
|
||||
/* old versions of libstc++ don't return an iterator
|
||||
from set<T>::erase (iterator)
|
||||
*/
|
||||
Events::iterator n = ee;
|
||||
++n;
|
||||
_current_events.erase (ee);
|
||||
ee = n;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
_sequencer->run (buf, start, last_time);
|
||||
|
||||
superclock_cnt += superclocks;
|
||||
|
||||
if (two_pass_required) {
|
||||
offset = superclocks;
|
||||
superclocks = orig_superclocks - superclocks;
|
||||
process_start = 0;
|
||||
process_end = superclocks;
|
||||
two_pass_required = false;
|
||||
goto second_pass;
|
||||
}
|
||||
|
||||
return;
|
||||
_sequencer->run (bufs.get_midi (0), _running, start_sample, end_sample, outbound_tracker);
|
||||
last_end = end_sample;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue