tweaks to the beatbox toy to properly track and connect note on/off
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 18 Aug 2017 16:17:46 +0000 (12:17 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 18 Sep 2017 15:40:53 +0000 (11:40 -0400)
tools/bb/bb.cc
tools/bb/bb.h

index 644538b49c8c55ebce8c679fc94295521309e65b..eb31fc0868e0bd88a155a544e3877c1a5c504831 100644 (file)
@@ -19,7 +19,7 @@
 using std::cerr;
 using std::endl;
 
-
+using namespace ARDOUR;
 
 BeatBox::BeatBox (int sr)
        : _start_requested (false)
@@ -174,16 +174,21 @@ BeatBox::process (int nsamples)
                        event_pool.push_back (*ee);
                }
                _current_events.clear ();
+               _incomplete_notes.clear ();
                clear_pending = false;
        }
 
+       framepos_t last_output_time = 0;
+
        for (Events::iterator ee = _current_events.begin(); ee != _current_events.end(); ++ee) {
                Event* e = (*ee);
 
                if (e->size && (e->time >= process_start && e->time < process_end)) {
-                       if ((buffer = jack_midi_event_reserve (out_buf, superclock_to_samples (offset + e->time - process_start, _sample_rate), e->size)) != 0) {
+                       framepos_t sample_offset_in_buffer = superclock_to_samples (offset + e->time - process_start, _sample_rate);
+                       if ((buffer = jack_midi_event_reserve (out_buf, sample_offset_in_buffer, e->size)) != 0) {
                                memcpy (buffer, e->buf, e->size);
                                outbound_tracker.track (e->buf);
+                               last_output_time = sample_offset_in_buffer;
                        } else {
                                cerr << "Could not reserve space for output event @ " << e << " of size " << e->size << " @ " << offset + e->time - process_start
                                     << " (samples: " << superclock_to_samples (offset + e->time - process_start, _sample_rate) << ") offset is " << offset
@@ -201,6 +206,8 @@ BeatBox::process (int nsamples)
        in_buf = jack_port_get_buffer (_input, nsamples);
        event_index = 0;
 
+       Events::iterator loop_iterator;
+
        while (jack_midi_event_get (&in_event, in_buf, event_index++) == 0) {
 
                superclock_t event_time = superclock_cnt + samples_to_superclock (in_event.time, _sample_rate);
@@ -211,7 +218,7 @@ BeatBox::process (int nsamples)
                if (_quantize_divisor != 0) {
                        const superclock_t time_per_grid_unit = whole_note_superclocks / _quantize_divisor;
 
-                       if (in_event.buffer[0] == MIDI_CMD_NOTE_OFF) {
+                       if ((in_event.buffer[0] & 0xf) == MIDI_CMD_NOTE_OFF) {
 
                                /* note off is special - it must be quantized
                                 * to at least 1 quantization "spacing" after
@@ -224,18 +231,22 @@ BeatBox::process (int nsamples)
 
                                /* look for the note on */
 
-                               for (Events::iterator ee = _current_events.begin(); ee != _current_events.end(); ++ee) {
-                                       /* is it a note-on? same note? same  channel? */
-                                       if ((*ee)->time > quantized_time) {
-                                               cerr << "Note off seen without corresponding note on!\n";
-                                               /* leave quantized_time alone ... should probably dump the whole event */
-                                               break;
-                                       }
+                               IncompleteNotes::iterator ee;
 
-                                       if (((*ee)->buf[0] == MIDI_CMD_NOTE_ON) && ((*ee)->buf[1] == in_event.buffer[1]) && ((*ee)->buf[0] & 0xf) == (in_event.buffer[0] & 0xf)) {
+                               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);
+                                               break;
                                        }
                                }
+
+                               if (ee == _incomplete_notes.end()) {
+                                       cerr << "Note off for " << (int) (*ee)->buf[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;
                        }
@@ -265,6 +276,17 @@ BeatBox::process (int nsamples)
                inbound_tracker.track (e->buf);
 
                _current_events.insert (e);
+
+               if ((e->buf[0] & 0xf) == MIDI_CMD_NOTE_ON) {
+                       _incomplete_notes.push_back (e);
+               }
+
+               /* play it to out outputs so that we can hear it immediately */
+               /* XXX this smooshes together all inbound notes ... tricky */
+               if ((buffer = jack_midi_event_reserve (out_buf, last_output_time++, e->size)) != 0) {
+                       memcpy (buffer, e->buf, e->size);
+                       outbound_tracker.track (e->buf);
+               }
        }
 
        superclock_cnt += superclocks;
index 4fcf477140bfc1af138766da4e2f0ed53ab53a34..07175b6664745713e7dce57f86a1ee3857bf9f67 100644 (file)
@@ -18,6 +18,10 @@ static const superclock_t superclock_ticks_per_second = 508032000; // 2^10 * 3^4
 inline superclock_t superclock_to_samples (superclock_t s, int sr) { return (s * sr) / superclock_ticks_per_second; }
 inline superclock_t samples_to_superclock (int samples, int sr) { return (samples * superclock_ticks_per_second) / sr; }
 
+namespace ARDOUR {
+class Session;
+}
+
 class BeatBox {
   public:
        BeatBox (int sample_rate);
@@ -78,6 +82,9 @@ class BeatBox {
                bool operator () (Event const * a, Event const * b) const;
        };
 
+       typedef std::vector<Event*> IncompleteNotes;
+       IncompleteNotes _incomplete_notes;
+
        typedef std::set<Event*,EventComparator> Events;
        Events _current_events;