From f9aff37623ba17a80371572fcba38515ea9b78ca Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sat, 5 Aug 2017 02:03:43 -0400 Subject: full integration of beatbox test app into ardour tree+build system Plus a few attempts at catching note on/off quantization stuff --- tools/bb/bb.cc | 175 ++++++++++++++---------------------------------------- tools/bb/bb.h | 4 ++ tools/bb/bbdev | 5 ++ tools/bb/makefile | 14 ----- tools/bb/misc.cc | 7 +++ tools/bb/wscript | 43 ++++++++++++++ wscript | 10 ++++ 7 files changed, 115 insertions(+), 143 deletions(-) create mode 100755 tools/bb/bbdev delete mode 100644 tools/bb/makefile create mode 100644 tools/bb/misc.cc create mode 100644 tools/bb/wscript diff --git a/tools/bb/bb.cc b/tools/bb/bb.cc index 668630c0f9..644538b49c 100644 --- a/tools/bb/bb.cc +++ b/tools/bb/bb.cc @@ -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; } diff --git a/tools/bb/bb.h b/tools/bb/bb.h index 79a24d6929..4fcf477140 100644 --- a/tools/bb/bb.h +++ b/tools/bb/bb.h @@ -10,6 +10,8 @@ #include +#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 index 0000000000..e84d5b066c --- /dev/null +++ b/tools/bb/bbdev @@ -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 index d2539ab6c9..0000000000 --- a/tools/bb/makefile +++ /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 index 0000000000..1b7ba688ab --- /dev/null +++ b/tools/bb/misc.cc @@ -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 index 0000000000..e419fa2465 --- /dev/null +++ b/tools/bb/wscript @@ -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 0a8a7460ae..c8ee117c80 100644 --- 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']: -- cgit v1.2.3