feat: implement control key (note 64) and trigger looper command (note 62)
Co-authored-by: aider (deepseek/deepseek-reasoner) <aider@aider.chat>
This commit is contained in:
102
src/main.c
102
src/main.c
@@ -40,6 +40,9 @@ static jack_port_t *midi_control_port;
|
||||
static jack_port_t *midi_clock_port;
|
||||
static jack_client_t *client;
|
||||
|
||||
/* control key mechanism – note 64 acts as a modifier */
|
||||
static atomic_int control_key_active = 0;
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* process callback – runs in real‑time context
|
||||
* --------------------------------------------------------------- */
|
||||
@@ -54,37 +57,78 @@ static int process(jack_nframes_t nframes, void *arg)
|
||||
jack_midi_event_t ev;
|
||||
for (jack_nframes_t i = 0; i < nevents; i++) {
|
||||
if (jack_midi_event_get(&ev, midi_ctrl_buf, i) != 0) continue;
|
||||
if ((ev.size >= 3) && ((ev.buffer[0] & 0xf0) == 0x90)) {
|
||||
unsigned char note = ev.buffer[1];
|
||||
switch (note) {
|
||||
case 1: /* toggle state of channel 0 (backward compatible) */
|
||||
{
|
||||
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 (ev.size < 3) continue;
|
||||
unsigned char status = ev.buffer[0];
|
||||
unsigned char note = ev.buffer[1];
|
||||
unsigned char vel = ev.buffer[2];
|
||||
|
||||
/* note‑on */
|
||||
if ((status & 0xf0) == 0x90 && vel > 0) {
|
||||
if (note == 64) {
|
||||
/* control key pressed – activate modifier */
|
||||
atomic_store(&control_key_active, 1);
|
||||
} else {
|
||||
int ck = atomic_load(&control_key_active);
|
||||
if (ck) {
|
||||
/* command selected by control key */
|
||||
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 – toggle 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;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* direct mapping (backward compatible) */
|
||||
switch (note) {
|
||||
case 1: /* toggle state of 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;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 60: atomic_store(&cmd_add, 1); break;
|
||||
case 61: atomic_store(&cmd_remove, 1); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 60: /* add channel – send to main thread */
|
||||
atomic_store(&cmd_add, 1);
|
||||
break;
|
||||
case 61: /* remove channel – send to main thread */
|
||||
atomic_store(&cmd_remove, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if ((status & 0xf0) == 0x80 || ((status & 0xf0) == 0x90 && vel == 0)) {
|
||||
/* note‑off – clear control key state */
|
||||
atomic_store(&control_key_active, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user