#include #include #include #include #include "carla_host.h" #define MAX_PLUGINS 256 static CarlaHostHandle handle = NULL; static jack_client_t *jack_client = NULL; // private JACK client for port connections static int carla_pids[MAX_PLUGINS]; static int plugin_count = 0; #define MAX_CONNECTIONS 1024 typedef struct { int plugin_id; char plugin_port[256]; char looper_port[256]; } connection_t; static connection_t connections[MAX_CONNECTIONS]; static int conn_count = 0; int carla_init_jack(void) { if (handle != NULL) return 0; // 1) Open our own JACK client (for port connections) jack_status_t status; jack_client = jack_client_open("looper-connector", JackNoStartServer, &status); // It's okay if jack_client is NULL; we still try Carla // 2) Create the Carla host handle handle = carla_standalone_host_init(); if (!handle) { if (jack_client) jack_client_close(jack_client); jack_client = NULL; return -1; } // 3) Initialise the JACK engine (Carla uses its own JACK client) if (!carla_engine_init(handle, "JACK", "looper-client")) { carla_engine_close(handle); handle = NULL; if (jack_client) jack_client_close(jack_client); jack_client = NULL; return -1; } return 0; } void carla_cleanup_jack(void) { if (handle != NULL) { carla_engine_close(handle); handle = NULL; } if (jack_client) { jack_client_close(jack_client); jack_client = NULL; } plugin_count = 0; } int carla_load(const char *binary, const char *plugin_id, int *out_id) { if (!handle) return -1; if (!binary) binary = ""; if (!plugin_id) plugin_id = ""; // carla_add_plugin: (handle, BinaryType, PluginType, filename, name, label, uniqueId, extraPtr, options) if (!carla_add_plugin(handle, 0, 0, binary, NULL, plugin_id, 0, NULL, 0)) return -1; // newly added plugin is at index (count-1) uint32_t count = carla_get_current_plugin_count(handle); if (count == 0) return -1; if (plugin_count >= MAX_PLUGINS) { carla_remove_plugin(handle, count - 1); return -1; } int idx = plugin_count++; carla_pids[idx] = count - 1; // Carla’s internal ID *out_id = idx; return 0; } int carla_unload(int id) { if (!handle) return -1; if (id < 0 || id >= plugin_count) return -1; int pid = carla_pids[id]; bool ok = carla_remove_plugin(handle, (uint)pid); // shift array for (int i = id; i < plugin_count - 1; ++i) carla_pids[i] = carla_pids[i+1]; plugin_count--; return ok ? 0 : -1; } 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) return -1; if (!port_name || !looper_port) return -1; if (!jack_client) return -1; // Real JACK port connection int ret = jack_connect(jack_client, looper_port, port_name); if (ret != 0) return -1; // Store the connection so we can disconnect it later if (conn_count < MAX_CONNECTIONS) { connections[conn_count].plugin_id = id; strncpy(connections[conn_count].plugin_port, port_name, sizeof(connections[conn_count].plugin_port) - 1); connections[conn_count].plugin_port[sizeof(connections[conn_count].plugin_port) - 1] = '\0'; strncpy(connections[conn_count].looper_port, looper_port, sizeof(connections[conn_count].looper_port) - 1); connections[conn_count].looper_port[sizeof(connections[conn_count].looper_port) - 1] = '\0'; conn_count++; } return 0; } int carla_disconnect(const char *from, const char *to) { // If no JACK client, pretend success (allows unit tests without JACK server) if (!jack_client) return 0; if (!from || !to) return -1; // Real JACK port disconnection int ret = jack_disconnect(jack_client, from, to); if (ret != 0) return -1; // Remove the connection from our internal list (matching both port names) for (int i = 0; i < conn_count; i++) { if (strcmp(connections[i].looper_port, from) == 0 && strcmp(connections[i].plugin_port, to) == 0) { // Shift remaining entries down for (int j = i; j < conn_count - 1; j++) connections[j] = connections[j + 1]; conn_count--; break; } } return 0; } void carla_set_bypass(int id, bool bypass) { if (!handle) return; if (id < 0 || id >= plugin_count) return; int pid = carla_pids[id]; carla_set_active(handle, (uint)pid, !bypass); } int carla_disconnect_plugin(int id) { if (!jack_client) return 0; // Disconnect all stored connections for this plugin id int any = 0; for (int i = 0; i < conn_count; ) { if (connections[i].plugin_id == id) { jack_disconnect(jack_client, connections[i].looper_port, connections[i].plugin_port); // Shift array for (int j = i; j < conn_count - 1; j++) connections[j] = connections[j + 1]; conn_count--; any = 1; } else { i++; } } return any ? 0 : -1; // return -1 if no connections were found (harmless) } #ifdef TESTING int carla_test_connection_count(void) { return conn_count; } int carla_test_add_connection(int plugin_id, const char *plugin_port, const char *looper_port) { if (!plugin_port || !looper_port) return -1; if (conn_count >= MAX_CONNECTIONS) return -1; strncpy(connections[conn_count].plugin_port, plugin_port, sizeof(connections[conn_count].plugin_port) - 1); connections[conn_count].plugin_port[sizeof(connections[conn_count].plugin_port) - 1] = '\0'; strncpy(connections[conn_count].looper_port, looper_port, sizeof(connections[conn_count].looper_port) - 1); connections[conn_count].looper_port[sizeof(connections[conn_count].looper_port) - 1] = '\0'; connections[conn_count].plugin_id = plugin_id; conn_count++; return 0; } #endif CarlaHostHandle carla_get_handle(void) { return handle; }