feat: implement bind feature for associating channels with MIDI notes

Co-authored-by: aider (deepseek/deepseek-reasoner) <aider@aider.chat>
This commit is contained in:
Loic Coenen
2026-05-09 10:22:33 +00:00
parent 740ebaa969
commit 4bacab68c6
3 changed files with 151 additions and 23 deletions

View File

@@ -18,6 +18,7 @@ atomic_int cmd_remove = 0;
jack_port_t *midi_control_port = NULL;
jack_port_t *midi_clock_port = NULL;
atomic_int control_key_active = 0;
atomic_int bind_channel = 0;
/* Deferred removal index (1 second grace) */
static int pending_unregister_idx = -1;

View File

@@ -7,6 +7,7 @@
extern atomic_int control_key_active;
extern atomic_int cmd_add;
extern atomic_int cmd_remove;
extern atomic_int bind_channel;
void midi_handle_events(void *port_buffer, jack_nframes_t nframes)
{
@@ -30,30 +31,37 @@ void midi_handle_events(void *port_buffer, jack_nframes_t nframes)
int ck = atomic_load(&control_key_active);
if (ck) {
atomic_store(&control_key_active, 0);
switch (note) {
case 60: atomic_store(&cmd_add, 1); break;
case 61: atomic_store(&cmd_remove, 1); break;
case 62: /* trigger looper channel 0 */
{
int cur0 = atomic_load(&channels[0].state);
switch (cur0) {
case STATE_IDLE:
atomic_store(&channels[0].state, STATE_RECORD);
break;
case STATE_RECORD:
atomic_store(&channels[0].state, STATE_LOOPING);
break;
case STATE_LOOPING:
atomic_store(&channels[0].state, STATE_PAUSED);
break;
case STATE_PAUSED:
atomic_store(&channels[0].state, STATE_LOOPING);
break;
if (note < 16) {
atomic_store(&bind_channel, note);
} else {
switch (note) {
case 60: atomic_store(&cmd_add, 1); break;
case 61: atomic_store(&cmd_remove, 1); break;
case 62: /* trigger looper channel via bind_channel */
{
int bch = atomic_load(&bind_channel);
if (bch >= 0 && bch < MAX_CHANNELS) {
int cur = atomic_load(&channels[bch].state);
switch (cur) {
case STATE_IDLE:
atomic_store(&channels[bch].state, STATE_RECORD);
break;
case STATE_RECORD:
atomic_store(&channels[bch].state, STATE_LOOPING);
break;
case STATE_LOOPING:
atomic_store(&channels[bch].state, STATE_PAUSED);
break;
case STATE_PAUSED:
atomic_store(&channels[bch].state, STATE_LOOPING);
break;
}
}
}
break;
default:
break;
}
break;
default:
break;
}
} else {
/* direct mapping */