288 lines
9.0 KiB
C
288 lines
9.0 KiB
C
#include "carla.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
// Simple internal gain plugin
|
|
typedef struct {
|
|
float gain;
|
|
} GainPlugin;
|
|
|
|
// Initialize Carla host
|
|
int carla_init(CarlaHost *host, jack_client_t *client) {
|
|
if (!host) return -1;
|
|
|
|
memset(host, 0, sizeof(CarlaHost));
|
|
host->client = client;
|
|
|
|
// Initialize all channel racks
|
|
for (int ch = 0; ch < 8; ch++) {
|
|
host->channel_racks[ch].num_plugins = 0;
|
|
host->channel_racks[ch].volume = 1.0f;
|
|
host->channel_racks[ch].bypassed = false;
|
|
}
|
|
|
|
// Initialize available plugins list with some defaults
|
|
host->num_available_plugins = 0;
|
|
host->available_plugins = NULL;
|
|
|
|
// Try to initialize Carla native host
|
|
// In a real implementation, this would call carla_standalone_init()
|
|
// For now, we'll use our internal plugins
|
|
|
|
host->initialized = true;
|
|
printf("Carla host initialized\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
void carla_cleanup(CarlaHost *host) {
|
|
if (!host) return;
|
|
|
|
// Clean up available plugins list
|
|
if (host->available_plugins) {
|
|
for (int i = 0; i < host->num_available_plugins; i++) {
|
|
free(host->available_plugins[i]);
|
|
}
|
|
free(host->available_plugins);
|
|
}
|
|
|
|
// Clean up channel racks
|
|
for (int ch = 0; ch < 8; ch++) {
|
|
ChannelRack *rack = &host->channel_racks[ch];
|
|
for (int p = 0; p < rack->num_plugins; p++) {
|
|
PluginInfo *plugin = &rack->plugins[p];
|
|
if (plugin->parameters) {
|
|
free(plugin->parameters);
|
|
}
|
|
if (plugin->parameter_names) {
|
|
for (int i = 0; i < plugin->num_parameters; i++) {
|
|
free(plugin->parameter_names[i]);
|
|
}
|
|
free(plugin->parameter_names);
|
|
}
|
|
}
|
|
}
|
|
|
|
host->initialized = false;
|
|
}
|
|
|
|
// Add a built-in gain plugin
|
|
static int add_gain_plugin(CarlaHost *host, int channel) {
|
|
if (channel < 0 || channel >= 8) return -1;
|
|
ChannelRack *rack = &host->channel_racks[channel];
|
|
if (rack->num_plugins >= 16) return -1;
|
|
|
|
PluginInfo *plugin = &rack->plugins[rack->num_plugins];
|
|
strcpy(plugin->name, "Gain");
|
|
strcpy(plugin->uri, "internal://gain");
|
|
plugin->type = PLUGIN_TYPE_INTERNAL;
|
|
plugin->carla_plugin_id = -1;
|
|
plugin->num_parameters = 1;
|
|
|
|
plugin->parameters = malloc(sizeof(float));
|
|
plugin->parameters[0] = 1.0f; // Default gain = 1.0
|
|
|
|
plugin->parameter_names = malloc(sizeof(char*));
|
|
plugin->parameter_names[0] = strdup("Gain");
|
|
|
|
rack->num_plugins++;
|
|
return rack->num_plugins - 1;
|
|
}
|
|
|
|
int carla_add_plugin(CarlaHost *host, int channel, const char *uri, PluginType type) {
|
|
if (!host || !host->initialized) return -1;
|
|
if (channel < 0 || channel >= 8) return -1;
|
|
|
|
// For now, only support internal gain plugin
|
|
if (type == PLUGIN_TYPE_INTERNAL && strcmp(uri, "internal://gain") == 0) {
|
|
return add_gain_plugin(host, channel);
|
|
}
|
|
|
|
// In a real implementation, this would call carla_add_plugin() from Carla API
|
|
// For now, fall back to gain plugin
|
|
return add_gain_plugin(host, channel);
|
|
}
|
|
|
|
int carla_remove_plugin(CarlaHost *host, int channel, int plugin_index) {
|
|
if (!host || !host->initialized) return -1;
|
|
if (channel < 0 || channel >= 8) return -1;
|
|
|
|
ChannelRack *rack = &host->channel_racks[channel];
|
|
if (plugin_index < 0 || plugin_index >= rack->num_plugins) return -1;
|
|
|
|
// Free plugin resources
|
|
PluginInfo *plugin = &rack->plugins[plugin_index];
|
|
if (plugin->parameters) {
|
|
free(plugin->parameters);
|
|
}
|
|
if (plugin->parameter_names) {
|
|
for (int i = 0; i < plugin->num_parameters; i++) {
|
|
free(plugin->parameter_names[i]);
|
|
}
|
|
free(plugin->parameter_names);
|
|
}
|
|
|
|
// Shift remaining plugins
|
|
for (int i = plugin_index; i < rack->num_plugins - 1; i++) {
|
|
rack->plugins[i] = rack->plugins[i + 1];
|
|
}
|
|
|
|
rack->num_plugins--;
|
|
return 0;
|
|
}
|
|
|
|
int carla_set_parameter(CarlaHost *host, int channel, int plugin_index, int param_index, float value) {
|
|
if (!host || !host->initialized) return -1;
|
|
if (channel < 0 || channel >= 8) return -1;
|
|
|
|
ChannelRack *rack = &host->channel_racks[channel];
|
|
if (plugin_index < 0 || plugin_index >= rack->num_plugins) return -1;
|
|
|
|
PluginInfo *plugin = &rack->plugins[plugin_index];
|
|
if (param_index < 0 || param_index >= plugin->num_parameters) return -1;
|
|
|
|
plugin->parameters[param_index] = value;
|
|
return 0;
|
|
}
|
|
|
|
float carla_get_parameter(CarlaHost *host, int channel, int plugin_index, int param_index) {
|
|
if (!host || !host->initialized) return 0.0f;
|
|
if (channel < 0 || channel >= 8) return 0.0f;
|
|
|
|
ChannelRack *rack = &host->channel_racks[channel];
|
|
if (plugin_index < 0 || plugin_index >= rack->num_plugins) return 0.0f;
|
|
|
|
PluginInfo *plugin = &rack->plugins[plugin_index];
|
|
if (param_index < 0 || param_index >= plugin->num_parameters) return 0.0f;
|
|
|
|
return plugin->parameters[param_index];
|
|
}
|
|
|
|
void carla_set_channel_volume(CarlaHost *host, int channel, float volume) {
|
|
if (!host || !host->initialized) return;
|
|
if (channel < 0 || channel >= 8) return;
|
|
|
|
host->channel_racks[channel].volume = fmaxf(0.0f, fminf(2.0f, volume));
|
|
}
|
|
|
|
float carla_get_channel_volume(CarlaHost *host, int channel) {
|
|
if (!host || !host->initialized) return 1.0f;
|
|
if (channel < 0 || channel >= 8) return 1.0f;
|
|
|
|
return host->channel_racks[channel].volume;
|
|
}
|
|
|
|
void carla_process(CarlaHost *host, int channel, float *in_buffer, float *out_buffer, jack_nframes_t nframes) {
|
|
if (!host || !host->initialized) return;
|
|
if (channel < 0 || channel >= 8) return;
|
|
|
|
ChannelRack *rack = &host->channel_racks[channel];
|
|
|
|
if (rack->bypassed || rack->num_plugins == 0) {
|
|
// Just apply volume
|
|
for (jack_nframes_t i = 0; i < nframes; i++) {
|
|
out_buffer[i] = in_buffer[i] * rack->volume;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Process through plugin chain
|
|
float *current_in = in_buffer;
|
|
float *current_out = out_buffer;
|
|
|
|
// Allocate temporary buffer for chaining
|
|
float *temp_buffer = malloc(nframes * sizeof(float));
|
|
if (!temp_buffer) {
|
|
// Fallback to direct passthrough
|
|
for (jack_nframes_t i = 0; i < nframes; i++) {
|
|
out_buffer[i] = in_buffer[i] * rack->volume;
|
|
}
|
|
return;
|
|
}
|
|
|
|
for (int p = 0; p < rack->num_plugins; p++) {
|
|
PluginInfo *plugin = &rack->plugins[p];
|
|
|
|
if (plugin->type == PLUGIN_TYPE_INTERNAL && strcmp(plugin->uri, "internal://gain") == 0) {
|
|
float gain = plugin->parameters[0];
|
|
for (jack_nframes_t i = 0; i < nframes; i++) {
|
|
current_out[i] = current_in[i] * gain;
|
|
}
|
|
}
|
|
// In a real implementation, this would call Carla's process function
|
|
|
|
// Chain: output of this plugin becomes input for next
|
|
if (p < rack->num_plugins - 1) {
|
|
float *swap = current_in;
|
|
current_in = current_out;
|
|
current_out = swap;
|
|
}
|
|
}
|
|
|
|
// Apply channel volume
|
|
for (jack_nframes_t i = 0; i < nframes; i++) {
|
|
current_out[i] *= rack->volume;
|
|
}
|
|
|
|
// If we ended up in temp_buffer, copy to out_buffer
|
|
if (current_out == temp_buffer) {
|
|
memcpy(out_buffer, temp_buffer, nframes * sizeof(float));
|
|
}
|
|
|
|
free(temp_buffer);
|
|
}
|
|
|
|
int carla_scan_plugins(CarlaHost *host) {
|
|
if (!host || !host->initialized) return -1;
|
|
|
|
// In a real implementation, this would scan for available LV2/VST plugins
|
|
// For now, add some built-in options
|
|
|
|
// Clean up previous scan
|
|
if (host->available_plugins) {
|
|
for (int i = 0; i < host->num_available_plugins; i++) {
|
|
free(host->available_plugins[i]);
|
|
}
|
|
free(host->available_plugins);
|
|
}
|
|
|
|
// Add built-in plugins
|
|
const char *builtins[] = {
|
|
"internal://gain - Gain (Built-in)",
|
|
"internal://reverb - Reverb (Built-in)",
|
|
"internal://delay - Delay (Built-in)",
|
|
"internal://filter - Filter (Built-in)"
|
|
};
|
|
|
|
host->num_available_plugins = 4;
|
|
host->available_plugins = malloc(host->num_available_plugins * sizeof(char*));
|
|
|
|
for (int i = 0; i < host->num_available_plugins; i++) {
|
|
host->available_plugins[i] = strdup(builtins[i]);
|
|
}
|
|
|
|
return host->num_available_plugins;
|
|
}
|
|
|
|
const char** carla_get_available_plugins(CarlaHost *host, int *count) {
|
|
if (!host || !host->initialized) {
|
|
if (count) *count = 0;
|
|
return NULL;
|
|
}
|
|
|
|
if (count) *count = host->num_available_plugins;
|
|
return (const char**)host->available_plugins;
|
|
}
|
|
|
|
const char* carla_get_plugin_name(CarlaHost *host, int channel, int plugin_index) {
|
|
if (!host || !host->initialized) return NULL;
|
|
if (channel < 0 || channel >= 8) return NULL;
|
|
|
|
ChannelRack *rack = &host->channel_racks[channel];
|
|
if (plugin_index < 0 || plugin_index >= rack->num_plugins) return NULL;
|
|
|
|
return rack->plugins[plugin_index].name;
|
|
}
|