200 lines
6.2 KiB
C
200 lines
6.2 KiB
C
#include <CarlaHost.h>
|
||
#include <CarlaBackend.h>
|
||
#include <jack/jack.h>
|
||
#include <string.h>
|
||
#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;
|
||
}
|