feat: add port connection display and audio pass-through test

This commit is contained in:
Loic Coenen
2026-05-24 22:35:51 +00:00
committed by Loic Coenen (aider)
parent c9c8afc602
commit 1e62ec9310
4 changed files with 205 additions and 24 deletions

View File

@@ -135,8 +135,10 @@ int carla_unload(int id) {
int carla_connect(int id, const char *port_name, const char *looper_port) {
// Check that the plugin id is valid
if (id < 0 || id >= plugin_count)
if (id < 0 || id >= plugin_count) {
fprintf(stderr, "CARLA_CONNECT: invalid plugin id %d (plugin_count=%d)\n", id, plugin_count);
return -1;
}
if (!port_name || !looper_port) return -1;
if (!jack_client) return -1;
@@ -144,7 +146,10 @@ int carla_connect(int id, const char *port_name, const char *looper_port) {
id, conn_count, port_name, looper_port);
// Real JACK port connection
int ret = jack_connect(jack_client, looper_port, port_name);
if (ret != 0) return -1;
if (ret != 0) {
fprintf(stderr, "CARLA_CONNECT: jack_connect(%s, %s) failed with %d\n", looper_port, port_name, ret);
return -1;
}
// Store the connection so we can disconnect it later
if (conn_count >= MAX_CONNECTIONS) {
@@ -279,3 +284,17 @@ int carla_test_add_connection(int plugin_id, const char *plugin_port, const char
CarlaHostHandle carla_get_handle(void) {
return handle;
}
bool carla_get_connected_port(int channel, bool is_input, char *buf, size_t bufsize) {
char needle[64];
snprintf(needle, sizeof(needle), "ch%d%s", channel, is_input ? "in" : "out");
for (int i = 0; i < conn_count; i++) {
if (strstr(connections[i].looper_port, needle)) {
strncpy(buf, connections[i].plugin_port, bufsize - 1);
buf[bufsize - 1] = '\0';
return true;
}
}
buf[0] = '\0';
return false;
}

View File

@@ -6,6 +6,8 @@
/* All functions return -1 on error, 0 on success (except carla_load which returns 0 on success and sets *out_id) */
bool carla_get_connected_port(int channel, bool is_input, char *buf, size_t bufsize);
int carla_init_jack(void);
void carla_cleanup_jack(void);

View File

@@ -20,6 +20,12 @@
#include <CarlaHost.h>
#include "log.h"
extern char g_selected_port[256];
/* Stored connected port names for channel 0 display fallback */
static char g_from_port[256] = "";
static char g_to_port[256] = "";
/* ---------- engine alive indicator ---------- */
static bool engine_running = false;
static bool debug_mode = false;
@@ -67,7 +73,7 @@ static const char *clip_state_string(ClipState s) {
#define GRID_ROWS 8
#define GRID_COLS 8
#define NUM_GRIDS 8
#define CELL_WIDTH 6
#define CELL_WIDTH 20
#define CELL_HEIGHT 3
/* status FIFO path */
@@ -150,19 +156,13 @@ static void draw_cell(int grid, int row, int col, bool selected) {
for (int dy=0; dy<CELL_HEIGHT; dy++)
for (int dx=0; dx<CELL_WIDTH; dx++)
mvaddch(y+dy, x+dx, ' ');
mvprintw(y+1, x+1, "%2d", grid*GRID_ROWS*GRID_COLS + row*GRID_COLS + col);
attroff(COLOR_PAIR(color));
/* Draw state indicator character below the number, centered */
int ch = grid * GRID_ROWS * GRID_COLS + row * GRID_COLS + col;
const char state_char = (s == STATE_RECORD) ? 'R' :
(s == STATE_LOOPING) ? 'L' :
(s == STATE_PAUSED) ? 'P' : '.';
int state_color = (s == STATE_RECORD) ? COLOR_RECORDING :
(s == STATE_LOOPING) ? COLOR_LOOPING :
(s == STATE_PAUSED) ? COLOR_STOPPED : COLOR_EMPTY;
attron(COLOR_PAIR(state_color));
mvaddch(y+2, x + CELL_WIDTH / 2, state_char);
attroff(COLOR_PAIR(state_color));
mvprintw(y, x, "ch %2d", ch);
mvaddch(y, x+5, state_char);
attroff(COLOR_PAIR(color));
}
static void draw_rack(void) {
@@ -207,11 +207,38 @@ static void draw_grid(void) {
for (int r=0; r<GRID_ROWS; r++)
for (int c=0; c<GRID_COLS; c++)
draw_cell(selected_grid, r, c, r==selected_row && c==selected_col);
mvprintw(GRID_ROWS*CELL_HEIGHT+3, 0, "Selected: Grid %d, Row %d, Col %d",
/* ---------- Footer: percolumn input / output ---------- */
int footer_y = GRID_ROWS * CELL_HEIGHT + 3;
for (int c=0; c<GRID_COLS; c++) {
int x = c * CELL_WIDTH + 1;
int global_ch = selected_grid * GRID_ROWS * GRID_COLS + c;
char input_buf[80], output_buf[80];
bool has_input = carla_get_connected_port(global_ch, true, input_buf, sizeof(input_buf));
bool has_output = carla_get_connected_port(global_ch, false, output_buf, sizeof(output_buf));
if (global_ch == 0) {
if (!has_input && g_from_port[0]) {
strncpy(input_buf, g_from_port, sizeof(input_buf)-1);
input_buf[sizeof(input_buf)-1] = '\0';
has_input = true;
}
if (!has_output && g_to_port[0]) {
strncpy(output_buf, g_to_port, sizeof(output_buf)-1);
output_buf[sizeof(output_buf)-1] = '\0';
has_output = true;
}
}
char fallback[16];
snprintf(fallback, sizeof(fallback), "ch%d", global_ch);
mvprintw(footer_y, x, "i:%-8.8s", has_input ? input_buf : fallback);
mvprintw(footer_y+1, x, "o:%-8.8s", has_output ? output_buf : fallback);
}
mvprintw(footer_y+2, 0, "Selected: Grid %d, Row %d, Col %d",
selected_grid, selected_row, selected_col);
if (show_help) {
attron(COLOR_PAIR(COLOR_HELP));
mvprintw(GRID_ROWS*CELL_HEIGHT+4, 0, "Help: h/j/k/l navigate, t record, d/D stop, s/S scene, a add, A add_midi, r remove, b bind, u unbind, R rack, ? help, Esc/Q quit");
mvprintw(footer_y+3, 0, "Help: h/j/k/l navigate, t record, d/D stop, s/S scene, a add, A add_midi, r remove, b bind, u unbind, R rack, ? help, Esc/Q quit");
attroff(COLOR_PAIR(COLOR_HELP));
}
refresh();
@@ -335,12 +362,41 @@ void tui_run(void) {
rack_mode = false;
} else if ((strcmp(first, "from") == 0 || strcmp(first, "to") == 0)) {
char *potential_arg = strtok(NULL, " ");
if (potential_arg == NULL) {
// no argument: launch fzf
const char *port_name = NULL;
if (potential_arg != NULL) {
port_name = potential_arg;
const char *colon = strchr(port_name, ':');
if (colon) port_name = colon + 1;
} else {
script_handle_fzf_command(first);
draw_grid();
continue;
if (g_selected_port[0] != '\0') {
port_name = g_selected_port;
}
}
/* Store the full port name (before stripping colon) for footer fallback */
if (potential_arg) {
if (strcmp(first, "from") == 0)
strncpy(g_from_port, potential_arg, sizeof(g_from_port)-1);
else
strncpy(g_to_port, potential_arg, sizeof(g_to_port)-1);
} else if (g_selected_port[0]) {
if (strcmp(first, "from") == 0)
strncpy(g_from_port, g_selected_port, sizeof(g_from_port)-1);
else
strncpy(g_to_port, g_selected_port, sizeof(g_to_port)-1);
}
if (port_name) {
const char *looper_port = (strcmp(first, "from") == 0) ? "looper:input" : "looper:output";
int ret = carla_connect(0, port_name, looper_port);
if (ret == 0) {
log_msg("Connected %s -> %s", port_name, looper_port);
} else {
log_msg("Failed to connect %s -> %s (ret=%d)", port_name, looper_port, ret);
}
}
if (!potential_arg) g_selected_port[0] = '\0';
draw_grid();
continue;
}
}
int dummy_id;