Skip to content

Commit 4077a55

Browse files
committed
simple implementation of midi tap tempo
1 parent 754070f commit 4077a55

5 files changed

Lines changed: 74 additions & 0 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,14 @@ The commands supported by mod-host are:
229229
* monitor audio levels for a specific jack port (on the feedback port)
230230
e.g.: monitor_audio_levels "system:capture_1" 1
231231

232+
midi_map_tempo_tap <midi_channel> <midi_cc>
233+
* map the MIDI tempo tap
234+
e.g.: midi_map_tempo_tap 0 0
235+
236+
midi_unmap_tempo_tap
237+
* unmap the MIDI tempo tap
238+
e.g.: midi_unmap_tempo_tap
239+
232240
monitor_midi_control <midi_channel> <enable>
233241
* listen to MIDI control change messages (on the feedback port)
234242
e.g.: monitor_midi_control 7 1

src/effects.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,12 @@ typedef struct MIDI_CC_T {
592592
port_t* port;
593593
} midi_cc_t;
594594

595+
typedef struct MIDI_CC_TEMPO_TAP_T {
596+
int8_t channel;
597+
uint8_t controller;
598+
jack_nframes_t last_frame_time;
599+
} midi_cc_tempo_tap_t;
600+
595601
typedef struct ASSIGNMENT_T {
596602
int effect_id;
597603
port_t *port;
@@ -755,6 +761,8 @@ typedef struct CACHED_EFFECT_FLUSH_T {
755761
static effect_t g_effects[MAX_INSTANCES];
756762
static midi_cc_t g_midi_cc_list[MAX_MIDI_CC_ASSIGN], *g_midi_learning;
757763

764+
static midi_cc_tempo_tap_t g_midi_cc_tempo_tap;
765+
758766
#ifdef HAVE_CONTROLCHAIN
759767
/* Control Chain */
760768
static cc_client_t *g_cc_client = NULL;
@@ -2943,6 +2951,26 @@ static int ProcessGlobalClient(jack_nframes_t nframes, void *arg)
29432951
handled = false;
29442952
channel = (event.buffer[0] & 0x0F);
29452953

2954+
const float max_tap_delay = 10.0f;
2955+
const float min_tap_delay = 0.1f;
2956+
if (g_midi_cc_tempo_tap.channel != -1)
2957+
{
2958+
if (channel == g_midi_cc_tempo_tap.channel && controller == g_midi_cc_tempo_tap.controller && mvalue > 63)
2959+
{
2960+
jack_nframes_t current = event.time + g_monotonic_frame_count;
2961+
const float delta_t = (current - g_midi_cc_tempo_tap.last_frame_time) / (float)g_sample_rate;
2962+
if (delta_t < max_tap_delay && delta_t > min_tap_delay)
2963+
{
2964+
const float bpm = 60.0f / delta_t;
2965+
effects_set_beats_per_minute(bpm);
2966+
// printf("bpm: %f delta_t: %f current: %d last: %d\n", bpm, delta_t, current, g_midi_cc_tempo_tap.last_frame_time);
2967+
}
2968+
2969+
g_midi_cc_tempo_tap.last_frame_time = current;
2970+
continue;
2971+
}
2972+
}
2973+
29462974
for (int j = 0; j < MAX_MIDI_CC_ASSIGN; j++)
29472975
{
29482976
if (g_midi_cc_list[j].effect_id == ASSIGNMENT_NULL)
@@ -4313,6 +4341,8 @@ static void ExternalControllerWriteFunction(LV2UI_Controller controller,
43134341

43144342
int effects_init(void* client)
43154343
{
4344+
g_midi_cc_tempo_tap.channel = -1;
4345+
43164346
/* This global client is for connections / disconnections and midi-learn */
43174347
if (client != NULL)
43184348
{
@@ -7898,6 +7928,22 @@ int effects_midi_unmap(int effect_id, const char *control_symbol)
78987928
return ERR_LV2_INVALID_PARAM_SYMBOL;
78997929
}
79007930

7931+
int effects_midi_map_tempo_tap(int channel, int controller)
7932+
{
7933+
g_midi_cc_tempo_tap.channel = channel;
7934+
g_midi_cc_tempo_tap.controller = controller;
7935+
g_midi_cc_tempo_tap.last_frame_time = g_monotonic_frame_count;
7936+
return SUCCESS;
7937+
}
7938+
7939+
int effects_midi_unmap_tempo_tap()
7940+
{
7941+
g_midi_cc_tempo_tap.channel = -1;
7942+
g_midi_cc_tempo_tap.controller = 0;
7943+
return SUCCESS;
7944+
}
7945+
7946+
79017947
int effects_licensee(int effect_id, char **licensee_ptr)
79027948
{
79037949
if (!InstanceExist(effect_id))

src/effects.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ int effects_get_parameter_info(int effect_id, const char *control_symbol, float
172172
int effects_midi_learn(int effect_id, const char *control_symbol, float minimum, float maximum);
173173
int effects_midi_map(int effect_id, const char *control_symbol, int channel, int controller, float minimum, float maximum);
174174
int effects_midi_unmap(int effect_id, const char *control_symbol);
175+
int effects_midi_map_tempo_tap(int channel, int controller);
176+
int effects_midi_unmap_tempo_tap();
175177
int effects_licensee(int effect_id, char **licensee);
176178
int effects_set_beats_per_minute(double bpm);
177179
int effects_set_beats_per_bar(float bpb);

src/mod-host.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,20 @@ static void midi_unmap_cb(proto_t *proto)
430430
protocol_response_int(resp, proto);
431431
}
432432

433+
static void midi_map_tempo_tap_cb(proto_t *proto)
434+
{
435+
int resp;
436+
resp = !effects_midi_map_tempo_tap(atoi(proto->list[1]), atoi(proto->list[2]));
437+
protocol_response_int(resp, proto);
438+
}
439+
440+
static void midi_unmap_tempo_tap_cb(proto_t *proto)
441+
{
442+
int resp;
443+
resp = !effects_midi_unmap_tempo_tap();
444+
protocol_response_int(resp, proto);
445+
}
446+
433447
static void cc_map_cb(proto_t *proto)
434448
{
435449
int resp;
@@ -1063,6 +1077,8 @@ static int mod_host_init(jack_client_t* client, int socket_port, int feedback_po
10631077
protocol_add_command(MIDI_LEARN, midi_learn_cb);
10641078
protocol_add_command(MIDI_MAP, midi_map_cb);
10651079
protocol_add_command(MIDI_UNMAP, midi_unmap_cb);
1080+
protocol_add_command(MIDI_MAP_TEMPO_TAP, midi_map_tempo_tap_cb);
1081+
protocol_add_command(MIDI_UNMAP_TEMPO_TAP, midi_unmap_tempo_tap_cb);
10661082
protocol_add_command(CC_MAP, cc_map_cb);
10671083
protocol_add_command(CC_VALUE_SET, cc_value_set_cb);
10681084
protocol_add_command(CC_UNMAP, cc_unmap_cb);

src/mod-host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@
8383
#define MIDI_LEARN "midi_learn %i %s %f %f"
8484
#define MIDI_MAP "midi_map %i %s %i %i %f %f"
8585
#define MIDI_UNMAP "midi_unmap %i %s"
86+
#define MIDI_MAP_TEMPO_TAP "midi_map_tempo_tap %i %i"
87+
#define MIDI_UNMAP_TEMPO_TAP "midi_map_tempo_tap"
8688
#define CC_MAP "cc_map %i %s %i %i %s %f %f %f %i %i %s %i ..."
8789
#define CC_VALUE_SET "cc_value_set %i %s %f"
8890
#define CC_UNMAP "cc_unmap %i %s"

0 commit comments

Comments
 (0)