feat: integrate real Carla host with JACK support and add plugin abstraction layer

This commit is contained in:
Loic Coenen
2026-05-16 22:23:50 +00:00
parent dafc7fe46b
commit c7df02d37c
20 changed files with 285 additions and 113 deletions

View File

@@ -1,38 +1,116 @@
#include <stddef.h>
#include <CarlaHost.h>
#include <CarlaBackend.h>
#include <jack/jack.h>
#include <string.h>
#include "carla_host.h"
int carla_load(const char *binary, const char *plugin_id, int *out_id)
{
(void)plugin_id;
(void)out_id;
if (binary == NULL) return -1;
// stub: always fails (will be replaced by real Carla later)
return -1;
#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;
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;
}
int carla_unload(int id)
{
(void)id;
return -1; // stub: always fails
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_connect(int id, const char *port_name, const char *looper_port)
{
(void)id;
(void)port_name;
(void)looper_port;
return -1; // stub: always fails
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; // Carlas internal ID
*out_id = idx;
return 0;
}
int carla_disconnect(const char *from, const char *to)
{
(void)from;
(void)to;
return 0; // stub: disconnect always succeeds (does nothing)
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;
}
void carla_set_bypass(int id, bool bypass)
{
(void)id;
(void)bypass;
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);
return (ret == 0) ? 0 : -1;
}
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);
return (ret == 0) ? 0 : -1;
}
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);
}

View File

@@ -5,6 +5,9 @@
/* All functions return -1 on error, 0 on success (except carla_load which returns 0 on success and sets *out_id) */
int carla_init_jack(void);
void carla_cleanup_jack(void);
int carla_load(const char *binary, const char *plugin_id, int *out_id);
int carla_unload(int id);
int carla_connect(int id, const char *port_name, const char *looper_port);

29
client/src/plugins.c Normal file
View File

@@ -0,0 +1,29 @@
#include <stddef.h>
#include "plugins.h"
#include "carla_host.h"
int plugin_load(const char *binary, const char *plugin_id, int *out_id)
{
if (!plugin_id) plugin_id = ""; // allow NULL
return carla_load(binary, plugin_id, out_id);
}
int plugin_unload(int id)
{
return carla_unload(id);
}
int plugin_connect(int id, const char *port_name, const char *looper_port)
{
return carla_connect(id, port_name, looper_port);
}
int plugin_disconnect(const char *from, const char *to)
{
return carla_disconnect(from, to);
}
void plugin_set_bypass(int id, bool bypass)
{
carla_set_bypass(id, bypass);
}

22
client/src/plugins.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef PLUGINS_H
#define PLUGINS_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/* All functions return -1 on error, 0 on success (except plugin_load which returns 0 on success and sets *out_id) */
int plugin_load(const char *binary, const char *plugin_id, int *out_id);
int plugin_unload(int id);
int plugin_connect(int id, const char *port_name, const char *looper_port);
int plugin_disconnect(const char *from, const char *to);
void plugin_set_bypass(int id, bool bypass);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -9,6 +9,7 @@
#include <dirent.h>
#include <sys/stat.h>
#include <math.h>
#include "carla_host.h"
/* ---------- FIFO command helper ---------- */
int send_command(const char *cmd) {
@@ -151,6 +152,8 @@ void tui_init(void) {
/* initialise cell states to idle */
for (int i = 0; i < GRID_ROWS * GRID_COLS; i++)
cell_state[i] = STATE_IDLE;
/* open the JACK client used for Carla plugins */
carla_init_jack();
}
/* ---------- TUI run ---------- */
@@ -234,5 +237,7 @@ void tui_cleanup(void) {
/* delete FIFOs */
unlink(STATUS_FIFO);
unlink(CMD_FIFO);
/* close the Carla JACK client */
carla_cleanup_jack();
curs_set(1); endwin();
}