midi state tracker: extend, fix, improve API for flushing state
This commit is contained in:
parent
9b3d0ddd11
commit
395b759f42
@ -50,11 +50,11 @@ public:
|
||||
void track (const MidiBuffer::const_iterator& from, const MidiBuffer::const_iterator& to);
|
||||
void add (uint8_t note, uint8_t chn);
|
||||
void remove (uint8_t note, uint8_t chn);
|
||||
void resolve_notes (MidiBuffer& buffer, samplepos_t time);
|
||||
void resolve_notes (MidiBuffer& buffer, samplepos_t time, bool reset = true);
|
||||
void resolve_notes (Evoral::EventSink<samplepos_t>& buffer, samplepos_t time);
|
||||
void resolve_notes (MidiSource& src, const Glib::Threads::Mutex::Lock& lock, Temporal::Beats time);
|
||||
|
||||
void flush_notes (MidiBuffer&, samplepos_t);
|
||||
void flush_notes (MidiBuffer& buffer, samplepos_t time, bool reset = true);
|
||||
|
||||
bool empty() const { return _on == 0; }
|
||||
uint16_t on() const { return _on; }
|
||||
@ -70,6 +70,9 @@ public:
|
||||
private:
|
||||
uint8_t _active_notes[128*16];
|
||||
uint16_t _on;
|
||||
|
||||
void push_notes (MidiBuffer &dst, samplepos_t time, bool reset, int cmd, int velocity);
|
||||
|
||||
};
|
||||
|
||||
class LIBARDOUR_API MidiStateTracker : public MidiNoteTracker
|
||||
@ -82,7 +85,7 @@ class LIBARDOUR_API MidiStateTracker : public MidiNoteTracker
|
||||
void dump (std::ostream&);
|
||||
void reset ();
|
||||
|
||||
void flush (MidiBuffer&, samplepos_t);
|
||||
void flush (MidiBuffer&, samplepos_t, bool reset);
|
||||
|
||||
private:
|
||||
uint8_t program[16];
|
||||
|
@ -110,7 +110,19 @@ MidiNoteTracker::track (const uint8_t* evbuf)
|
||||
}
|
||||
|
||||
void
|
||||
MidiNoteTracker::resolve_notes (MidiBuffer &dst, samplepos_t time)
|
||||
MidiNoteTracker::resolve_notes (MidiBuffer &dst, samplepos_t time, bool reset)
|
||||
{
|
||||
push_notes (dst, time, reset, MIDI_CMD_NOTE_OFF, 64);
|
||||
}
|
||||
|
||||
void
|
||||
MidiNoteTracker::flush_notes (MidiBuffer &dst, samplepos_t time, bool reset)
|
||||
{
|
||||
push_notes (dst, time, reset, MIDI_CMD_NOTE_ON, 64);
|
||||
}
|
||||
|
||||
void
|
||||
MidiNoteTracker::push_notes (MidiBuffer &dst, samplepos_t time, bool reset, int cmd, int velocity)
|
||||
{
|
||||
DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 MB-resolve notes @ %2 on = %3\n", this, time, _on));
|
||||
|
||||
@ -121,20 +133,20 @@ MidiNoteTracker::resolve_notes (MidiBuffer &dst, samplepos_t time)
|
||||
for (int channel = 0; channel < 16; ++channel) {
|
||||
for (int note = 0; note < 128; ++note) {
|
||||
while (_active_notes[note + 128 * channel]) {
|
||||
uint8_t buffer[3] = { ((uint8_t) (MIDI_CMD_NOTE_OFF | channel)), uint8_t (note), 0 };
|
||||
Evoral::Event<MidiBuffer::TimeType> noteoff
|
||||
(Evoral::MIDI_EVENT, time, 3, buffer, false);
|
||||
uint8_t buffer[3] = { ((uint8_t) (cmd | channel)), uint8_t (note), (uint8_t) velocity };
|
||||
Evoral::Event<MidiBuffer::TimeType> ev (Evoral::MIDI_EVENT, time, 3, buffer, false);
|
||||
/* note that we do not care about failure from
|
||||
push_back() ... should we warn someone ?
|
||||
*/
|
||||
dst.push_back (noteoff);
|
||||
dst.push_back (ev);
|
||||
_active_notes[note + 128 * channel]--;
|
||||
DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1: MB-resolved note %2/%3 at %4\n",
|
||||
this, (int) note, (int) channel, time));
|
||||
DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1: MB-push note %2/%3 at %4\n", this, (int) note, (int) channel, time));
|
||||
}
|
||||
}
|
||||
}
|
||||
_on = 0;
|
||||
if (reset) {
|
||||
_on = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -164,6 +176,7 @@ MidiNoteTracker::resolve_notes (Evoral::EventSink<samplepos_t> &dst, samplepos_t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_on = 0;
|
||||
}
|
||||
|
||||
@ -195,40 +208,14 @@ MidiNoteTracker::resolve_notes (MidiSource& src, const MidiSource::Lock& lock, T
|
||||
}
|
||||
}
|
||||
}
|
||||
_on = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MidiNoteTracker::flush_notes (MidiBuffer &dst, samplepos_t time)
|
||||
{
|
||||
DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 MB-flushing notes @ %2 on = %3\n", this, time, _on));
|
||||
|
||||
if (!_on) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int channel = 0; channel < 16; ++channel) {
|
||||
for (int note = 0; note < 128; ++note) {
|
||||
while (_active_notes[note + 128 * channel]) {
|
||||
uint8_t buffer[3] = { ((uint8_t) (MIDI_CMD_NOTE_ON | channel)), uint8_t (note), 0 };
|
||||
Evoral::Event<MidiBuffer::TimeType> noteoff (Evoral::MIDI_EVENT, time, 3, buffer, false);
|
||||
/* note that we do not care about failure from
|
||||
push_back() ... should we warn someone ?
|
||||
*/
|
||||
dst.push_back (noteoff);
|
||||
_active_notes[note + 128 * channel]--;
|
||||
DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1: MB-flushed note %2/%3 at %4\n",
|
||||
this, (int) note, (int) channel, time));
|
||||
}
|
||||
}
|
||||
}
|
||||
_on = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MidiNoteTracker::dump (ostream& o)
|
||||
{
|
||||
o << "******\n";
|
||||
o << "****** NOTES\n";
|
||||
for (int c = 0; c < 16; ++c) {
|
||||
for (int x = 0; x < 128; ++x) {
|
||||
if (_active_notes[c * 128 + x]) {
|
||||
@ -269,8 +256,38 @@ MidiStateTracker::reset ()
|
||||
void
|
||||
MidiStateTracker::dump (ostream& o)
|
||||
{
|
||||
const size_t n_channels = 16;
|
||||
const size_t n_controls = 127;
|
||||
bool need_comma = false;
|
||||
|
||||
o << "DUMP for MidiStateTracker @ " << this << std::endl;
|
||||
MidiNoteTracker::dump (o);
|
||||
o << "implement MidiStateTracker::dump()";
|
||||
|
||||
for (size_t chn = 0; chn < n_channels; ++chn) {
|
||||
if ((program[chn] & 0x80) == 0) {
|
||||
if (need_comma) {
|
||||
o << ", ";
|
||||
}
|
||||
o << "program[" << chn << "] = " << int (program[chn] & 0x7f);
|
||||
need_comma = true;
|
||||
}
|
||||
}
|
||||
o << std::endl;
|
||||
|
||||
need_comma = false;
|
||||
|
||||
for (size_t chn = 0; chn < n_channels; ++chn) {
|
||||
for (size_t ctl = 0; ctl < n_controls; ++ctl) {
|
||||
if ((control[chn][ctl] & 0x80) == 0) {
|
||||
if (need_comma) {
|
||||
o << ", ";
|
||||
}
|
||||
o << "ctrl[" << chn << "][" << ctl << "] = " << int (control[chn][ctl] & 0x7f);
|
||||
need_comma = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
o << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
@ -314,12 +331,12 @@ MidiStateTracker::track (const uint8_t* evbuf)
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MidiStateTracker::flush (MidiBuffer& dst, samplepos_t time)
|
||||
MidiStateTracker::flush (MidiBuffer& dst, samplepos_t time, bool reset)
|
||||
{
|
||||
/* XXX implement me */
|
||||
|
||||
@ -327,25 +344,29 @@ MidiStateTracker::flush (MidiBuffer& dst, samplepos_t time)
|
||||
const size_t n_channels = 16;
|
||||
const size_t n_controls = 127;
|
||||
|
||||
/* XXX need MidiNoteTracker::flush() method that will emit NoteOn for
|
||||
* all currently-on notes.
|
||||
*/
|
||||
flush_notes (dst, time, reset);
|
||||
|
||||
for (int chn = 0; chn < n_channels; ++chn) {
|
||||
if (program[chn] & 0x80 == 0) {
|
||||
for (size_t chn = 0; chn < n_channels; ++chn) {
|
||||
if ((program[chn] & 0x80) == 0) {
|
||||
buf[0] = MIDI_CMD_PGM_CHANGE|chn;
|
||||
buf[1] = program[chn] & 0x7f;
|
||||
dst.write (time, Evoral::MIDI_EVENT, 2, buf);
|
||||
if (reset) {
|
||||
program[chn] = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int chn = 0; chn < n_channels; ++chn) {
|
||||
for (int ctl = 0; ctl < n_controls; ++ctl) {
|
||||
if (control[chn][ctl] & 0x80 == 0) {
|
||||
for (size_t chn = 0; chn < n_channels; ++chn) {
|
||||
for (size_t ctl = 0; ctl < n_controls; ++ctl) {
|
||||
if ((control[chn][ctl] & 0x80) == 0) {
|
||||
buf[0] = MIDI_CMD_CONTROL|chn;
|
||||
buf[1] = ctl;
|
||||
buf[2] = control[chn][ctl] & 0x7f;
|
||||
dst.write (time, Evoral::MIDI_EVENT, 3, buf);
|
||||
if (reset) {
|
||||
control[chn][ctl] = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user