midi state tracker: extend, fix, improve API for flushing state

This commit is contained in:
Paul Davis 2022-02-10 19:59:08 -07:00
parent 9b3d0ddd11
commit 395b759f42
2 changed files with 73 additions and 49 deletions

View File

@ -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];

View File

@ -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;
}
}
}
}