full integration of beatbox test app into ardour tree+build system
authorPaul Davis <paul@linuxaudiosystems.com>
Sat, 5 Aug 2017 06:03:43 +0000 (02:03 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Sat, 5 Aug 2017 06:03:59 +0000 (02:03 -0400)
Plus a few attempts at catching note on/off quantization stuff

tools/bb/bb.cc
tools/bb/bb.h
tools/bb/bbdev [new file with mode: 0755]
tools/bb/makefile [deleted file]
tools/bb/misc.cc [new file with mode: 0644]
tools/bb/wscript [new file with mode: 0644]
wscript

index 668630c0f95d52cabfff8dbcea425768d8253a7d..644538b49c8c55ebce8c679fc94295521309e65b 100644 (file)
@@ -11,6 +11,8 @@
 
 #include "evoral/midi_events.h"
 
+#include "ardour/midi_buffer.h"
+
 #include "bb.h"
 #include "gui.h"
 
@@ -18,126 +20,6 @@ using std::cerr;
 using std::endl;
 
 
-static bool
-second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b)
-{
-       bool b_first = false;
-
-       /* two events at identical times. we need to determine
-          the order in which they should occur.
-
-          the rule is:
-
-          Controller messages
-          Program Change
-          Note Off
-          Note On
-          Note Pressure
-          Channel Pressure
-          Pitch Bend
-       */
-
-       if ((a) >= 0xf0 || (b) >= 0xf0 || ((a & 0xf) != (b & 0xf))) {
-
-               /* if either message is not a channel message, or if the channels are
-                * different, we don't care about the type.
-                */
-
-               b_first = true;
-
-       } else {
-
-               switch (b & 0xf0) {
-               case MIDI_CMD_CONTROL:
-                       b_first = true;
-                       break;
-
-               case MIDI_CMD_PGM_CHANGE:
-                       switch (a & 0xf0) {
-                       case MIDI_CMD_CONTROL:
-                               break;
-                       case MIDI_CMD_PGM_CHANGE:
-                       case MIDI_CMD_NOTE_OFF:
-                       case MIDI_CMD_NOTE_ON:
-                       case MIDI_CMD_NOTE_PRESSURE:
-                       case MIDI_CMD_CHANNEL_PRESSURE:
-                       case MIDI_CMD_BENDER:
-                               b_first = true;
-                       }
-                       break;
-
-               case MIDI_CMD_NOTE_OFF:
-                       switch (a & 0xf0) {
-                       case MIDI_CMD_CONTROL:
-                       case MIDI_CMD_PGM_CHANGE:
-                               break;
-                       case MIDI_CMD_NOTE_OFF:
-                       case MIDI_CMD_NOTE_ON:
-                       case MIDI_CMD_NOTE_PRESSURE:
-                       case MIDI_CMD_CHANNEL_PRESSURE:
-                       case MIDI_CMD_BENDER:
-                               b_first = true;
-                       }
-                       break;
-
-               case MIDI_CMD_NOTE_ON:
-                       switch (a & 0xf0) {
-                       case MIDI_CMD_CONTROL:
-                       case MIDI_CMD_PGM_CHANGE:
-                       case MIDI_CMD_NOTE_OFF:
-                               break;
-                       case MIDI_CMD_NOTE_ON:
-                       case MIDI_CMD_NOTE_PRESSURE:
-                       case MIDI_CMD_CHANNEL_PRESSURE:
-                       case MIDI_CMD_BENDER:
-                               b_first = true;
-                       }
-                       break;
-               case MIDI_CMD_NOTE_PRESSURE:
-                       switch (a & 0xf0) {
-                       case MIDI_CMD_CONTROL:
-                       case MIDI_CMD_PGM_CHANGE:
-                       case MIDI_CMD_NOTE_OFF:
-                       case MIDI_CMD_NOTE_ON:
-                               break;
-                       case MIDI_CMD_NOTE_PRESSURE:
-                       case MIDI_CMD_CHANNEL_PRESSURE:
-                       case MIDI_CMD_BENDER:
-                               b_first = true;
-                       }
-                       break;
-
-               case MIDI_CMD_CHANNEL_PRESSURE:
-                       switch (a & 0xf0) {
-                       case MIDI_CMD_CONTROL:
-                       case MIDI_CMD_PGM_CHANGE:
-                       case MIDI_CMD_NOTE_OFF:
-                       case MIDI_CMD_NOTE_ON:
-                       case MIDI_CMD_NOTE_PRESSURE:
-                               break;
-                       case MIDI_CMD_CHANNEL_PRESSURE:
-                       case MIDI_CMD_BENDER:
-                               b_first = true;
-                       }
-                       break;
-               case MIDI_CMD_BENDER:
-                       switch (a & 0xf0) {
-                       case MIDI_CMD_CONTROL:
-                       case MIDI_CMD_PGM_CHANGE:
-                       case MIDI_CMD_NOTE_OFF:
-                       case MIDI_CMD_NOTE_ON:
-                       case MIDI_CMD_NOTE_PRESSURE:
-                       case MIDI_CMD_CHANNEL_PRESSURE:
-                               break;
-                       case MIDI_CMD_BENDER:
-                               b_first = true;
-                       }
-                       break;
-               }
-       }
-
-       return b_first;
-}
 
 BeatBox::BeatBox (int sr)
        : _start_requested (false)
@@ -232,11 +114,6 @@ BeatBox::process (int nsamples)
 
        superclock_t superclocks = samples_to_superclock (nsamples, _sample_rate);
 
-       if (!_running) {
-               superclock_cnt += superclocks;
-               return 0;
-       }
-
        if (_tempo_request) {
                double ratio = _tempo / _tempo_request;
                _tempo = _tempo_request;
@@ -244,11 +121,20 @@ BeatBox::process (int nsamples)
 
                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 0;
+       }
+
        superclock_t process_start = superclock_cnt - last_start;
        superclock_t process_end = process_start + superclocks;
        const superclock_t loop_length = _measures * measure_superclocks;
@@ -273,7 +159,6 @@ BeatBox::process (int nsamples)
        void* in_buf;
        jack_midi_event_t in_event;
        jack_nframes_t event_index;
-       jack_nframes_t event_count;
 
        /* do this on the first pass only */
        out_buf = jack_port_get_buffer (_output, nsamples);
@@ -298,6 +183,7 @@ BeatBox::process (int nsamples)
                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) {
                                memcpy (buffer, e->buf, e->size);
+                               outbound_tracker.track (e->buf);
                        } 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
@@ -323,8 +209,37 @@ BeatBox::process (int nsamples)
                superclock_t quantized_time;
 
                if (_quantize_divisor != 0) {
-                       const superclock_t time_per_beat = whole_note_superclocks / _quantize_divisor;
-                       quantized_time = (in_loop_time / time_per_beat) * time_per_beat;
+                       const superclock_t time_per_grid_unit = whole_note_superclocks / _quantize_divisor;
+
+                       if (in_event.buffer[0] == MIDI_CMD_NOTE_OFF) {
+
+                               /* note off is special - it must be quantized
+                                * to at least 1 quantization "spacing" after
+                                * the corresponding note on.
+                                */
+
+                               /* compute nominal time */
+
+                               quantized_time = (in_loop_time / time_per_grid_unit) * time_per_grid_unit;
+
+                               /* 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;
+                                       }
+
+                                       if (((*ee)->buf[0] == MIDI_CMD_NOTE_ON) && ((*ee)->buf[1] == in_event.buffer[1]) && ((*ee)->buf[0] & 0xf) == (in_event.buffer[0] & 0xf)) {
+                                               quantized_time = (*ee)->time + time_per_grid_unit;
+                                       }
+                               }
+                       } else {
+                               quantized_time = (in_loop_time / time_per_grid_unit) * time_per_grid_unit;
+                       }
+
                } else {
                        quantized_time = elapsed_time;
                }
@@ -347,6 +262,8 @@ BeatBox::process (int nsamples)
                e->size = in_event.size;
                memcpy (e->buf, in_event.buffer, in_event.size);
 
+               inbound_tracker.track (e->buf);
+
                _current_events.insert (e);
        }
 
@@ -383,7 +300,7 @@ BeatBox::EventComparator::operator() (Event const * a, Event const *b) const
                if (a->buf[0] == b->buf[0]) {
                        return a < b;
                }
-               return !second_simultaneous_midi_byte_is_first (a->buf[0], b->buf[0]);
+               return !ARDOUR::MidiBuffer::second_simultaneous_midi_byte_is_first (a->buf[0], b->buf[0]);
        }
        return a->time < b->time;
 }
index 79a24d69291edeccd5e37ed7c0eaf9001b5296c0..4fcf477140bfc1af138766da4e2f0ed53ab53a34 100644 (file)
@@ -10,6 +10,8 @@
 
 #include <jack/jack.h>
 
+#include "ardour/midi_state_tracker.h"
+
 typedef uint64_t superclock_t;
 
 static const superclock_t superclock_ticks_per_second = 508032000; // 2^10 * 3^4 * 5^3 * 7^2
@@ -58,6 +60,8 @@ class BeatBox {
        superclock_t measure_superclocks;
        int _quantize_divisor;
        bool clear_pending;
+       ARDOUR::MidiStateTracker inbound_tracker;
+       ARDOUR::MidiStateTracker outbound_tracker;
 
        struct Event {
                superclock_t time;
diff --git a/tools/bb/bbdev b/tools/bb/bbdev
new file mode 100755 (executable)
index 0000000..e84d5b0
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+TOP=`dirname "$0"`/../..
+. $TOP/build/tools/bb/bbdev_common_waf.sh
+export UBUNTU_MENUPROXY=""
+exec $TOP/$EXECUTABLE "$@"
diff --git a/tools/bb/makefile b/tools/bb/makefile
deleted file mode 100644 (file)
index d2539ab..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-all: bb
-
-CXXFLAGS=-I../../libs/evoral `pkg-config --cflags jack` `pkg-config --cflags gtkmm-2.4`
-LDFLAGS=`pkg-config --libs jack` `pkg-config --libs gtkmm-2.4`
-
-bb: bb.o gui.o
-       $(CXX) -o bb bb.o gui.o $(LDFLAGS) 
-
-
-bb.o: bb.cc bb.h gui.h
-gui.o: gui.cc gui.h bb.h
-
-clean:
-       rm -f bb bb.o gui.o
diff --git a/tools/bb/misc.cc b/tools/bb/misc.cc
new file mode 100644 (file)
index 0000000..1b7ba68
--- /dev/null
@@ -0,0 +1,7 @@
+/* temporarily required due to some code design confusion (Feb 2014) */
+
+#include "ardour/vst_types.h"
+
+int vstfx_init (void*) { return 0; }
+void vstfx_exit () {}
+void vstfx_destroy_editor (VSTState*) {}
diff --git a/tools/bb/wscript b/tools/bb/wscript
new file mode 100644 (file)
index 0000000..e419fa2
--- /dev/null
@@ -0,0 +1,43 @@
+import waflib.Logs as Logs, waflib.Utils as Utils
+import os
+
+# Mandatory variables
+top = '.'
+out = 'build'
+
+def options(ctx):
+        pass
+
+def configure(ctx):
+        pass
+
+def build(bld):
+       obj = bld (features = 'cxx c cxxprogram')
+       obj.install_path = None
+       obj.source    = [ 'bb.cc', 'gui.cc', 'misc.cc' ]
+       obj.target    = 'bb'
+       obj.includes  = ['.', '../libs']
+       obj.ldflags   = ['-no-undefined']
+       obj.use       = [ 'libardour', 'libevoral', ]
+       obj.uselib    = ' JACK GTKMM '
+
+        wrapper_subst_dict = {
+            'INSTALL_PREFIX' : bld.env['PREFIX'],
+            'LIBDIR'         : os.path.normpath(bld.env['DLLDIR']),
+            'DATADIR'        : os.path.normpath(bld.env['DATADIR']),
+            'CONFDIR'        : os.path.normpath(bld.env['CONFDIR']),
+            'LIBS'           : 'build/libs',
+            'VERSION'        : str (bld.env['VERSION']),
+            'EXECUTABLE'     : 'build/tools/bb/bb'
+        }
+
+        def set_subst_dict(obj, dict):
+                for i in dict:
+                        setattr(obj, i, dict[i])
+
+        obj              = bld (features = 'subst')
+        obj.source       = '../../gtk2_ardour/ardev_common.sh.in'
+        obj.target       = 'bbdev_common_waf.sh'
+        obj.chmod        = Utils.O755
+        obj.dict         = wrapper_subst_dict
+        set_subst_dict(obj, wrapper_subst_dict)
diff --git a/wscript b/wscript
index 0a8a7460ae7454570ae106f3d43ae2f1083113fb..c8ee117c8037883cff44ba092d4c53c196366b3f 100644 (file)
--- a/wscript
+++ b/wscript
@@ -730,6 +730,8 @@ def options(opt):
                     help='Compile Tool to dump LuaBindings (needs C++11)')
     opt.add_option('--canvasui', action='store_true', default=False, dest='canvasui',
                     help='Compile libcanvas test GUI')
+    opt.add_option('--beatbox', action='store_true', default=False, dest='beatbox',
+                    help='Compile beatbox test app')
     opt.add_option('--lv2', action='store_true', default=True, dest='lv2',
                     help='Compile with support for LV2 (if Lilv+Suil is available)')
     opt.add_option('--no-lv2', action='store_false', dest='lv2',
@@ -959,6 +961,10 @@ def configure(conf):
         conf.env['CANVASTESTUI'] = True
         conf.define ('CANVASTESTUI', 1)
 
+    if Options.options.beatbox:
+        conf.env['BEATBOX'] = True
+        conf.define ('BEATBOX', 1)
+
     if Options.options.luadoc:
         conf.env['LUABINDINGDOC'] = True
         conf.define ('LUABINDINGDOC', 1)
@@ -1239,6 +1245,7 @@ const char* const ardour_config_info = "\\n\\
     write_config_text('AudioUnits',            conf.is_defined('AUDIOUNIT_SUPPORT'))
     write_config_text('Build target',          conf.env['build_target'])
     write_config_text('Canvas Test UI',        conf.is_defined('CANVASTESTUI'))
+    write_config_text('Beatbox test app',      conf.is_defined('BEATBOX'))
     write_config_text('CoreAudio',             conf.is_defined('HAVE_COREAUDIO'))
     write_config_text('CoreAudio 10.5 compat', conf.is_defined('COREAUDIO105'))
     write_config_text('Debug RT allocations',  conf.is_defined('DEBUG_RT_ALLOC'))
@@ -1339,6 +1346,9 @@ def build(bld):
     for i in children:
         bld.recurse(i)
 
+    if bld.is_defined ('BEATBOX'):
+        bld.recurse('tools/bb')
+            
     bld.install_files (bld.env['CONFDIR'], 'system_config')
 
     if bld.env['RUN_TESTS']: