mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 14:54:56 +01:00
full integration of beatbox test app into ardour tree+build system
Plus a few attempts at catching note on/off quantization stuff
This commit is contained in:
parent
f21a66797a
commit
f9aff37623
7 changed files with 115 additions and 143 deletions
175
tools/bb/bb.cc
175
tools/bb/bb.cc
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include "evoral/midi_events.h"
|
#include "evoral/midi_events.h"
|
||||||
|
|
||||||
|
#include "ardour/midi_buffer.h"
|
||||||
|
|
||||||
#include "bb.h"
|
#include "bb.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
|
||||||
|
|
@ -18,126 +20,6 @@ using std::cerr;
|
||||||
using std::endl;
|
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)
|
BeatBox::BeatBox (int sr)
|
||||||
: _start_requested (false)
|
: _start_requested (false)
|
||||||
|
|
@ -232,11 +114,6 @@ BeatBox::process (int nsamples)
|
||||||
|
|
||||||
superclock_t superclocks = samples_to_superclock (nsamples, _sample_rate);
|
superclock_t superclocks = samples_to_superclock (nsamples, _sample_rate);
|
||||||
|
|
||||||
if (!_running) {
|
|
||||||
superclock_cnt += superclocks;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_tempo_request) {
|
if (_tempo_request) {
|
||||||
double ratio = _tempo / _tempo_request;
|
double ratio = _tempo / _tempo_request;
|
||||||
_tempo = _tempo_request;
|
_tempo = _tempo_request;
|
||||||
|
|
@ -244,11 +121,20 @@ BeatBox::process (int nsamples)
|
||||||
|
|
||||||
compute_tempo_clocks ();
|
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) {
|
for (Events::iterator ee = _current_events.begin(); ee != _current_events.end(); ++ee) {
|
||||||
(*ee)->time = llrintf ((*ee)->time * ratio);
|
(*ee)->time = llrintf ((*ee)->time * ratio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_running) {
|
||||||
|
superclock_cnt += superclocks;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
superclock_t process_start = superclock_cnt - last_start;
|
superclock_t process_start = superclock_cnt - last_start;
|
||||||
superclock_t process_end = process_start + superclocks;
|
superclock_t process_end = process_start + superclocks;
|
||||||
const superclock_t loop_length = _measures * measure_superclocks;
|
const superclock_t loop_length = _measures * measure_superclocks;
|
||||||
|
|
@ -273,7 +159,6 @@ BeatBox::process (int nsamples)
|
||||||
void* in_buf;
|
void* in_buf;
|
||||||
jack_midi_event_t in_event;
|
jack_midi_event_t in_event;
|
||||||
jack_nframes_t event_index;
|
jack_nframes_t event_index;
|
||||||
jack_nframes_t event_count;
|
|
||||||
|
|
||||||
/* do this on the first pass only */
|
/* do this on the first pass only */
|
||||||
out_buf = jack_port_get_buffer (_output, nsamples);
|
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 (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) {
|
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);
|
memcpy (buffer, e->buf, e->size);
|
||||||
|
outbound_tracker.track (e->buf);
|
||||||
} else {
|
} else {
|
||||||
cerr << "Could not reserve space for output event @ " << e << " of size " << e->size << " @ " << offset + e->time - process_start
|
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
|
<< " (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;
|
superclock_t quantized_time;
|
||||||
|
|
||||||
if (_quantize_divisor != 0) {
|
if (_quantize_divisor != 0) {
|
||||||
const superclock_t time_per_beat = whole_note_superclocks / _quantize_divisor;
|
const superclock_t time_per_grid_unit = whole_note_superclocks / _quantize_divisor;
|
||||||
quantized_time = (in_loop_time / time_per_beat) * time_per_beat;
|
|
||||||
|
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 {
|
} else {
|
||||||
quantized_time = elapsed_time;
|
quantized_time = elapsed_time;
|
||||||
}
|
}
|
||||||
|
|
@ -347,6 +262,8 @@ BeatBox::process (int nsamples)
|
||||||
e->size = in_event.size;
|
e->size = in_event.size;
|
||||||
memcpy (e->buf, in_event.buffer, in_event.size);
|
memcpy (e->buf, in_event.buffer, in_event.size);
|
||||||
|
|
||||||
|
inbound_tracker.track (e->buf);
|
||||||
|
|
||||||
_current_events.insert (e);
|
_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]) {
|
if (a->buf[0] == b->buf[0]) {
|
||||||
return a < b;
|
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;
|
return a->time < b->time;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#include <jack/jack.h>
|
#include <jack/jack.h>
|
||||||
|
|
||||||
|
#include "ardour/midi_state_tracker.h"
|
||||||
|
|
||||||
typedef uint64_t superclock_t;
|
typedef uint64_t superclock_t;
|
||||||
|
|
||||||
static const superclock_t superclock_ticks_per_second = 508032000; // 2^10 * 3^4 * 5^3 * 7^2
|
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;
|
superclock_t measure_superclocks;
|
||||||
int _quantize_divisor;
|
int _quantize_divisor;
|
||||||
bool clear_pending;
|
bool clear_pending;
|
||||||
|
ARDOUR::MidiStateTracker inbound_tracker;
|
||||||
|
ARDOUR::MidiStateTracker outbound_tracker;
|
||||||
|
|
||||||
struct Event {
|
struct Event {
|
||||||
superclock_t time;
|
superclock_t time;
|
||||||
|
|
|
||||||
5
tools/bb/bbdev
Executable file
5
tools/bb/bbdev
Executable file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
TOP=`dirname "$0"`/../..
|
||||||
|
. $TOP/build/tools/bb/bbdev_common_waf.sh
|
||||||
|
export UBUNTU_MENUPROXY=""
|
||||||
|
exec $TOP/$EXECUTABLE "$@"
|
||||||
|
|
@ -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
|
|
||||||
7
tools/bb/misc.cc
Normal file
7
tools/bb/misc.cc
Normal file
|
|
@ -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*) {}
|
||||||
43
tools/bb/wscript
Normal file
43
tools/bb/wscript
Normal file
|
|
@ -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)
|
||||||
10
wscript
10
wscript
|
|
@ -730,6 +730,8 @@ def options(opt):
|
||||||
help='Compile Tool to dump LuaBindings (needs C++11)')
|
help='Compile Tool to dump LuaBindings (needs C++11)')
|
||||||
opt.add_option('--canvasui', action='store_true', default=False, dest='canvasui',
|
opt.add_option('--canvasui', action='store_true', default=False, dest='canvasui',
|
||||||
help='Compile libcanvas test GUI')
|
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',
|
opt.add_option('--lv2', action='store_true', default=True, dest='lv2',
|
||||||
help='Compile with support for LV2 (if Lilv+Suil is available)')
|
help='Compile with support for LV2 (if Lilv+Suil is available)')
|
||||||
opt.add_option('--no-lv2', action='store_false', dest='lv2',
|
opt.add_option('--no-lv2', action='store_false', dest='lv2',
|
||||||
|
|
@ -959,6 +961,10 @@ def configure(conf):
|
||||||
conf.env['CANVASTESTUI'] = True
|
conf.env['CANVASTESTUI'] = True
|
||||||
conf.define ('CANVASTESTUI', 1)
|
conf.define ('CANVASTESTUI', 1)
|
||||||
|
|
||||||
|
if Options.options.beatbox:
|
||||||
|
conf.env['BEATBOX'] = True
|
||||||
|
conf.define ('BEATBOX', 1)
|
||||||
|
|
||||||
if Options.options.luadoc:
|
if Options.options.luadoc:
|
||||||
conf.env['LUABINDINGDOC'] = True
|
conf.env['LUABINDINGDOC'] = True
|
||||||
conf.define ('LUABINDINGDOC', 1)
|
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('AudioUnits', conf.is_defined('AUDIOUNIT_SUPPORT'))
|
||||||
write_config_text('Build target', conf.env['build_target'])
|
write_config_text('Build target', conf.env['build_target'])
|
||||||
write_config_text('Canvas Test UI', conf.is_defined('CANVASTESTUI'))
|
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', conf.is_defined('HAVE_COREAUDIO'))
|
||||||
write_config_text('CoreAudio 10.5 compat', conf.is_defined('COREAUDIO105'))
|
write_config_text('CoreAudio 10.5 compat', conf.is_defined('COREAUDIO105'))
|
||||||
write_config_text('Debug RT allocations', conf.is_defined('DEBUG_RT_ALLOC'))
|
write_config_text('Debug RT allocations', conf.is_defined('DEBUG_RT_ALLOC'))
|
||||||
|
|
@ -1339,6 +1346,9 @@ def build(bld):
|
||||||
for i in children:
|
for i in children:
|
||||||
bld.recurse(i)
|
bld.recurse(i)
|
||||||
|
|
||||||
|
if bld.is_defined ('BEATBOX'):
|
||||||
|
bld.recurse('tools/bb')
|
||||||
|
|
||||||
bld.install_files (bld.env['CONFDIR'], 'system_config')
|
bld.install_files (bld.env['CONFDIR'], 'system_config')
|
||||||
|
|
||||||
if bld.env['RUN_TESTS']:
|
if bld.env['RUN_TESTS']:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue