From 5f1cc081f7183e9a64d1e566fb3c06791bc8ceba Mon Sep 17 00:00:00 2001 From: Loic Coenen Date: Sun, 3 May 2026 18:49:46 +0000 Subject: [PATCH] feat: add MIDI clip recording and grid mode support Co-authored-by: aider (deepseek/deepseek-coder) --- engine.c | 18 ++++++++++++++++++ tui.c | 20 ++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/engine.c b/engine.c index 13978ec..5ac9820 100644 --- a/engine.c +++ b/engine.c @@ -44,6 +44,7 @@ static int process_callback(jack_nframes_t nframes, void *arg) { uint8_t velocity = data[2]; if (status == 0x90 && channel == 0 && velocity > 0) { + // Trigger audio clip Action action = { .type = ACTION_MIDI_NOTE_ON, .data.midi_note_on = { .note = note, .velocity = velocity, @@ -51,6 +52,23 @@ static int process_callback(jack_nframes_t nframes, void *arg) { }; engine->dispatch(action); + // Also trigger MIDI clip + int clip_idx = note % MAX_CLIPS; + Action midi_action = { + .type = ACTION_MIDI_CLIP_TRIGGER, + .data.midi_clip_trigger = { .clip_index = clip_idx } + }; + engine->dispatch(midi_action); + + // Record MIDI event into MIDI clip if recording + MidiClip *mclip = &state.midi_clips[clip_idx]; + if (mclip->state == CLIP_RECORDING && mclip->event_count < MAX_MIDI_EVENTS) { + mclip->events[mclip->event_count].note = note; + mclip->events[mclip->event_count].velocity = velocity; + mclip->events[mclip->event_count].timestamp = midi_event.time; + mclip->event_count++; + } + uint8_t out_velocity = clip_state_to_velocity(state.clips[note % MAX_CLIPS].state); uint8_t out_msg[3] = {0x90 | channel, note, out_velocity}; jack_midi_event_write(midi_out_buf, midi_event.time, out_msg, 3); diff --git a/tui.c b/tui.c index 6f7dcd6..d29a664 100644 --- a/tui.c +++ b/tui.c @@ -1066,14 +1066,26 @@ static void handle_mouse_event(MEVENT *event) { selected_row = grid_row; selected_col = grid_col; int clip_idx = grid_to_clip_index(selected_grid, selected_row, selected_col); - Action action = { .type = ACTION_TRIGGER_CLIP, .data.trigger_clip = { .clip_index = clip_idx } }; - g_dispatch(action); + AppState s = dispatcher_get_state(); + if (s.show_midi_grid) { + Action action = { .type = ACTION_MIDI_CLIP_TRIGGER, .data.midi_clip_trigger = { .clip_index = clip_idx } }; + g_dispatch(action); + } else { + Action action = { .type = ACTION_TRIGGER_CLIP, .data.trigger_clip = { .clip_index = clip_idx } }; + g_dispatch(action); + } } else if (event->bstate & BUTTON3_CLICKED) { selected_row = grid_row; selected_col = grid_col; int clip_idx = grid_to_clip_index(selected_grid, selected_row, selected_col); - Action action = { .type = ACTION_RESET_CLIP, .data.reset_clip = { .clip_index = clip_idx } }; - g_dispatch(action); + AppState s = dispatcher_get_state(); + if (s.show_midi_grid) { + Action action = { .type = ACTION_MIDI_CLIP_RESET, .data.midi_clip_reset = { .clip_index = clip_idx } }; + g_dispatch(action); + } else { + Action action = { .type = ACTION_RESET_CLIP, .data.reset_clip = { .clip_index = clip_idx } }; + g_dispatch(action); + } } else if (event->bstate & BUTTON2_CLICKED) { selected_row = grid_row; selected_col = grid_col;