Merge pull request #249 from mawe42/more-ladspa-cleanup

More LADSPA cleanup and refactor
This commit is contained in:
Marcus Weseloh 2017-10-24 15:50:05 +02:00 committed by GitHub
commit e485129705
4 changed files with 268 additions and 152 deletions

View file

@ -41,7 +41,7 @@
static void clear_ladspa(fluid_ladspa_fx_t *fx); static void clear_ladspa(fluid_ladspa_fx_t *fx);
static fluid_ladspa_node_t *new_fluid_ladspa_node(fluid_ladspa_fx_t *fx, const char *name, static fluid_ladspa_node_t *new_fluid_ladspa_node(fluid_ladspa_fx_t *fx, const char *name,
fluid_ladspa_node_type_t type, int buf_size); fluid_ladspa_node_type_t type);
static void delete_fluid_ladspa_node(fluid_ladspa_node_t *node); static void delete_fluid_ladspa_node(fluid_ladspa_node_t *node);
static int create_input_output_nodes(fluid_ladspa_fx_t *fx); static int create_input_output_nodes(fluid_ladspa_fx_t *fx);
static fluid_ladspa_node_t *get_node(fluid_ladspa_fx_t *fx, const char *name); static fluid_ladspa_node_t *get_node(fluid_ladspa_fx_t *fx, const char *name);
@ -62,8 +62,8 @@ static fluid_ladspa_lib_t *get_ladspa_library(fluid_ladspa_fx_t *fx, const char
static int load_plugin_library(fluid_ladspa_lib_t *lib); static int load_plugin_library(fluid_ladspa_lib_t *lib);
static void unload_plugin_library(fluid_ladspa_lib_t *lib); static void unload_plugin_library(fluid_ladspa_lib_t *lib);
static FLUID_INLINE void node_to_buffer(fluid_ladspa_node_t *node, fluid_real_t *buffer); static FLUID_INLINE void node_to_buffer(fluid_ladspa_node_t *node, fluid_real_t *buffer, int num_samples);
static FLUID_INLINE void buffer_to_node(fluid_real_t *buffer, fluid_ladspa_node_t *node); static FLUID_INLINE void buffer_to_node(fluid_real_t *buffer, fluid_ladspa_node_t *node, int num_samples);
static int set_default_port_value(fluid_ladspa_plugin_t *plugin, unsigned int port_idx, static int set_default_port_value(fluid_ladspa_plugin_t *plugin, unsigned int port_idx,
int sample_rate, LADSPA_Data *data); int sample_rate, LADSPA_Data *data);
@ -71,6 +71,13 @@ static void connect_node_to_port(fluid_ladspa_node_t *node, fluid_ladspa_dir_t d
fluid_ladspa_plugin_t *plugin, int port_idx); fluid_ladspa_plugin_t *plugin, int port_idx);
static int connect_default_control_nodes(fluid_ladspa_fx_t *fx, fluid_ladspa_plugin_t *plugin); static int connect_default_control_nodes(fluid_ladspa_fx_t *fx, fluid_ladspa_plugin_t *plugin);
static int check_all_ports_connected(fluid_ladspa_plugin_t *plugin, const char **name);
static int check_no_inplace_broken(fluid_ladspa_plugin_t *plugin, const char **name1, const char **name2);
static int check_system_input_used(fluid_ladspa_fx_t *fx);
static int check_system_output_used(fluid_ladspa_fx_t *fx);
static int check_all_audio_nodes_connected(fluid_ladspa_fx_t *fx, const char **name);
static int check_all_control_nodes_connected(fluid_ladspa_fx_t *fx, const char **name);
/** /**
* Creates a new LADSPA effects unit. * Creates a new LADSPA effects unit.
* *
@ -78,9 +85,11 @@ static int connect_default_control_nodes(fluid_ladspa_fx_t *fx, fluid_ladspa_plu
* @param audio_groups number of input audio channels (stereo) * @param audio_groups number of input audio channels (stereo)
* @param effects_channels number of input effects channels (stereo) * @param effects_channels number of input effects channels (stereo)
* @param audio_channels number of output audio channels (stereo) * @param audio_channels number of output audio channels (stereo)
* @param buffer_size size of buffers for audio nodes
* @return pointer to the new LADSPA effects unit * @return pointer to the new LADSPA effects unit
*/ */
fluid_ladspa_fx_t *new_fluid_ladspa_fx(fluid_real_t sample_rate, int audio_groups, int effects_channels, int audio_channels) fluid_ladspa_fx_t *new_fluid_ladspa_fx(fluid_real_t sample_rate, int audio_groups, int effects_channels,
int audio_channels, int buffer_size)
{ {
fluid_ladspa_fx_t *fx; fluid_ladspa_fx_t *fx;
@ -102,6 +111,7 @@ fluid_ladspa_fx_t *new_fluid_ladspa_fx(fluid_real_t sample_rate, int audio_group
fx->audio_groups = audio_groups; fx->audio_groups = audio_groups;
fx->effects_channels = effects_channels; fx->effects_channels = effects_channels;
fx->audio_channels = audio_channels; fx->audio_channels = audio_channels;
fx->buffer_size = buffer_size;
/* Setup mutex and cond used to signal that fluid_ladspa_run has finished */ /* Setup mutex and cond used to signal that fluid_ladspa_run has finished */
fx->run_finished_mutex = new_fluid_cond_mutex(); fx->run_finished_mutex = new_fluid_cond_mutex();
@ -333,12 +343,12 @@ int fluid_ladspa_reset(fluid_ladspa_fx_t *fx)
} }
/** /**
* Processes a block of audio data via the LADSPA effects unit. * Processes audio data via the LADSPA effects unit.
* *
* FluidSynth calls this function during main output mixing, just after * FluidSynth calls this function during main output mixing, just after
* the internal reverb and chorus effects have been processed. * the internal reverb and chorus effects have been processed.
* *
* It reads data from the supplied buffers, runs all LADSPA plugins and writes the * It copies audio data from the supplied buffers, runs all LADSPA plugins and copies the
* resulting audio back into the same buffers. * resulting audio back into the same buffers.
* *
* @param fx LADSPA effects instance * @param fx LADSPA effects instance
@ -346,11 +356,15 @@ int fluid_ladspa_reset(fluid_ladspa_fx_t *fx)
* @param right_buf array of pointers into the right audio group buffers * @param right_buf array of pointers into the right audio group buffers
* @param fx_left_buf array of pointers into the left effects buffers * @param fx_left_buf array of pointers into the left effects buffers
* @param fx_right_buf array of pointers into the right effects buffers * @param fx_right_buf array of pointers into the right effects buffers
* @param block_count number of blocks to render
* @param block_size number of samples in a block
*/ */
void fluid_ladspa_run(fluid_ladspa_fx_t *fx, fluid_real_t *left_buf[], fluid_real_t *right_buf[], void fluid_ladspa_run(fluid_ladspa_fx_t *fx, fluid_real_t *left_buf[], fluid_real_t *right_buf[],
fluid_real_t *fx_left_buf[], fluid_real_t *fx_right_buf[]) fluid_real_t *fx_left_buf[], fluid_real_t *fx_right_buf[],
int block_count, int block_size)
{ {
int i, n; int i, n;
int num_samples;
/* Somebody wants to deactivate the engine, so let's give them a chance to do that. /* Somebody wants to deactivate the engine, so let's give them a chance to do that.
* And check that there is at least one plugin loaded, to avoid the overhead of the * And check that there is at least one plugin loaded, to avoid the overhead of the
@ -370,32 +384,33 @@ void fluid_ladspa_run(fluid_ladspa_fx_t *fx, fluid_real_t *left_buf[], fluid_rea
* main inputs, effect inputs, main outputs. * main inputs, effect inputs, main outputs.
* All inputs and outputs use two nodes (stereo), left and right channels interleaved. */ * All inputs and outputs use two nodes (stereo), left and right channels interleaved. */
n = 0; n = 0;
num_samples = block_count * block_size;
/* Incoming main audio data */ /* Incoming main audio data */
for (i = 0; i < fx->audio_groups; i++) for (i = 0; i < fx->audio_groups; i++)
{ {
buffer_to_node(left_buf[i], fx->nodes[n++]); buffer_to_node(left_buf[i], fx->nodes[n++], num_samples);
buffer_to_node(right_buf[i], fx->nodes[n++]); buffer_to_node(right_buf[i], fx->nodes[n++], num_samples);
} }
/* Incoming effects audio data */ /* Incoming effects audio data */
for (i = 0; i < fx->effects_channels; i++) for (i = 0; i < fx->effects_channels; i++)
{ {
buffer_to_node(fx_left_buf[i], fx->nodes[n++]); buffer_to_node(fx_left_buf[i], fx->nodes[n++], num_samples);
buffer_to_node(fx_right_buf[i], fx->nodes[n++]); buffer_to_node(fx_right_buf[i], fx->nodes[n++], num_samples);
} }
/* Run each plugin on a block of data */ /* Run each plugin on a block of data */
for (i = 0; i < fx->num_plugins; i++) for (i = 0; i < fx->num_plugins; i++)
{ {
fx->plugins[i]->desc->run(fx->plugins[i]->handle, FLUID_BUFSIZE); fx->plugins[i]->desc->run(fx->plugins[i]->handle, num_samples);
} }
/* Copy the data from the output nodes back to the output buffers */ /* Copy the data from the output nodes back to the output buffers */
for (i = 0; i < fx->audio_channels; i++) for (i = 0; i < fx->audio_channels; i++)
{ {
node_to_buffer(fx->nodes[n++], left_buf[i]); node_to_buffer(fx->nodes[n++], left_buf[i], num_samples);
node_to_buffer(fx->nodes[n++], right_buf[i]); node_to_buffer(fx->nodes[n++], right_buf[i], num_samples);
} }
if (!fluid_atomic_int_compare_and_exchange(&fx->state, FLUID_LADSPA_RUNNING, FLUID_LADSPA_ACTIVE)) if (!fluid_atomic_int_compare_and_exchange(&fx->state, FLUID_LADSPA_RUNNING, FLUID_LADSPA_ACTIVE))
@ -435,13 +450,13 @@ static int create_input_output_nodes(fluid_ladspa_fx_t *fx)
for (i = 0; i < fx->audio_groups; i++) for (i = 0; i < fx->audio_groups; i++)
{ {
FLUID_SNPRINTF(name, sizeof(name), "in%i_L", (i + 1)); FLUID_SNPRINTF(name, sizeof(name), "in%i_L", (i + 1));
if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO, FLUID_BUFSIZE) == NULL) if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO) == NULL)
{ {
return FLUID_FAILED; return FLUID_FAILED;
} }
FLUID_SNPRINTF(name, sizeof(name), "in%i_R", (i + 1)); FLUID_SNPRINTF(name, sizeof(name), "in%i_R", (i + 1));
if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO, FLUID_BUFSIZE) == NULL) if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO) == NULL)
{ {
return FLUID_FAILED; return FLUID_FAILED;
} }
@ -451,13 +466,13 @@ static int create_input_output_nodes(fluid_ladspa_fx_t *fx)
for (i = 0; i < fx->effects_channels; i++) for (i = 0; i < fx->effects_channels; i++)
{ {
FLUID_SNPRINTF(name, sizeof(name), "send%i_L", (i + 1)); FLUID_SNPRINTF(name, sizeof(name), "send%i_L", (i + 1));
if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO, FLUID_BUFSIZE) == NULL) if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO) == NULL)
{ {
return FLUID_FAILED; return FLUID_FAILED;
} }
FLUID_SNPRINTF(name, sizeof(name), "send%i_R", (i + 1)); FLUID_SNPRINTF(name, sizeof(name), "send%i_R", (i + 1));
if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO, FLUID_BUFSIZE) == NULL) if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO) == NULL)
{ {
return FLUID_FAILED; return FLUID_FAILED;
} }
@ -467,13 +482,13 @@ static int create_input_output_nodes(fluid_ladspa_fx_t *fx)
for (i = 0; i < fx->audio_channels; i++) for (i = 0; i < fx->audio_channels; i++)
{ {
FLUID_SNPRINTF(name, sizeof(name), "out%i_L", (i + 1)); FLUID_SNPRINTF(name, sizeof(name), "out%i_L", (i + 1));
if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO, FLUID_BUFSIZE) == NULL) if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO) == NULL)
{ {
return FLUID_FAILED; return FLUID_FAILED;
} }
FLUID_SNPRINTF(name, sizeof(name), "out%i_R", (i + 1)); FLUID_SNPRINTF(name, sizeof(name), "out%i_R", (i + 1));
if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO, FLUID_BUFSIZE) == NULL) if (new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO) == NULL)
{ {
return FLUID_FAILED; return FLUID_FAILED;
} }
@ -510,6 +525,13 @@ static void clear_ladspa(fluid_ladspa_fx_t *fx)
delete_fluid_ladspa_node(fx->nodes[i]); delete_fluid_ladspa_node(fx->nodes[i]);
} }
fx->num_nodes = num_system_nodes; fx->num_nodes = num_system_nodes;
/* Reset connection counts for system nodes */
for (i = 0; i < num_system_nodes; i++)
{
fx->nodes[i]->num_inputs = 0;
fx->nodes[i]->num_outputs = 0;
}
} }
/** /**
@ -578,7 +600,7 @@ int fluid_ladspa_add_audio_node(fluid_ladspa_fx_t *fx, const char *name)
LADSPA_API_RETURN(fx, FLUID_FAILED); LADSPA_API_RETURN(fx, FLUID_FAILED);
} }
node = new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO, FLUID_BUFSIZE); node = new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_AUDIO);
if (node == NULL) if (node == NULL)
{ {
LADSPA_API_RETURN(fx, FLUID_FAILED); LADSPA_API_RETURN(fx, FLUID_FAILED);
@ -605,7 +627,7 @@ int fluid_ladspa_add_control_node(fluid_ladspa_fx_t *fx, const char *name, fluid
LADSPA_API_RETURN(fx, FLUID_FAILED); LADSPA_API_RETURN(fx, FLUID_FAILED);
} }
node = new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_CONTROL, 1); node = new_fluid_ladspa_node(fx, name, FLUID_LADSPA_NODE_CONTROL);
if (node == NULL) if (node == NULL)
{ {
LADSPA_API_RETURN(fx, FLUID_FAILED); LADSPA_API_RETURN(fx, FLUID_FAILED);
@ -743,7 +765,7 @@ int fluid_ladspa_connect(fluid_ladspa_fx_t *fx, int plugin_id, fluid_ladspa_dir_
* value */ * value */
if (dir == FLUID_LADSPA_FIXED) if (dir == FLUID_LADSPA_FIXED)
{ {
node = new_fluid_ladspa_node(fx, "", FLUID_LADSPA_NODE_CONTROL, 1); node = new_fluid_ladspa_node(fx, "", FLUID_LADSPA_NODE_CONTROL);
if (node == NULL) if (node == NULL)
{ {
LADSPA_API_RETURN(fx, FLUID_FAILED); LADSPA_API_RETURN(fx, FLUID_FAILED);
@ -839,11 +861,9 @@ int fluid_ladspa_control_defaults(fluid_ladspa_fx_t *fx)
int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size) int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size)
{ {
int i; int i;
unsigned int k; const char *str;
int has_connections; const char *str2;
int num_system_nodes;
fluid_ladspa_plugin_t *plugin; fluid_ladspa_plugin_t *plugin;
LADSPA_PortDescriptor port_flags;
LADSPA_API_ENTER(fx); LADSPA_API_ENTER(fx);
@ -854,82 +874,48 @@ int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size)
LADSPA_API_RETURN(fx, FLUID_FAILED); LADSPA_API_RETURN(fx, FLUID_FAILED);
} }
/* Check that all plugin ports are connected */
for (i = 0; i < fx->num_plugins; i++) for (i = 0; i < fx->num_plugins; i++)
{ {
plugin = fx->plugins[i]; plugin = fx->plugins[i];
for (k = 0; k < plugin->desc->PortCount; k++) if (check_all_ports_connected(plugin, &str) == FLUID_FAILED)
{ {
port_flags = plugin->desc->PortDescriptors[k]; FLUID_SNPRINTF(err, err_size, "Port '%s' on plugin '%s' is not connected\n",
str, plugin->desc->Label);
LADSPA_API_RETURN(fx, FLUID_FAILED);
}
if (LADSPA_IS_PORT_INPUT(port_flags) && plugin->ports[k].num_inputs == 0) if (check_no_inplace_broken(plugin, &str, &str2) == FLUID_FAILED)
{ {
FLUID_SNPRINTF(err, err_size, "Input port '%s' on plugin '%s' is not connected\n", FLUID_SNPRINTF(err, err_size,
plugin->desc->PortNames[k], plugin->desc->Label); "Plugin '%s' is in-place broken, '%s' and '%s' are not allowed "
"to connect to the same node\n", plugin->desc->Label, str, str2);
LADSPA_API_RETURN(fx, FLUID_FAILED); LADSPA_API_RETURN(fx, FLUID_FAILED);
}
else if (LADSPA_IS_PORT_OUTPUT(port_flags) && plugin->ports[k].num_outputs == 0)
{
FLUID_SNPRINTF(err, err_size, "Output port '%s' on plugin '%s' is not connected\n",
plugin->desc->PortNames[k], plugin->desc->Label);
LADSPA_API_RETURN(fx, FLUID_FAILED);
}
} }
} }
/* Check that at least one system input is used */ if (check_system_input_used(fx) == FLUID_FAILED)
has_connections = 0;
for (i = 0; i < 2 * (fx->audio_groups + fx->effects_channels); i++)
{
if (fx->nodes[i]->num_outputs)
{
has_connections = 1;
break;
}
}
if (!has_connections)
{ {
FLUID_SNPRINTF(err, err_size, "No system input nodes are connected\n"); FLUID_SNPRINTF(err, err_size, "No system input nodes are connected\n");
LADSPA_API_RETURN(fx, FLUID_FAILED); LADSPA_API_RETURN(fx, FLUID_FAILED);
} }
num_system_nodes = 2 * (fx->audio_groups + fx->effects_channels + fx->audio_channels); if (check_system_output_used(fx) == FLUID_FAILED)
/* Check that at least one system output is used */
has_connections = 0;
for (i = 2 * (fx->audio_groups + fx->effects_channels); i < num_system_nodes; i++)
{
if (fx->nodes[i]->num_inputs)
{
has_connections = 1;
break;
}
}
if (!has_connections)
{ {
FLUID_SNPRINTF(err, err_size, "No system output nodes are connected\n"); FLUID_SNPRINTF(err, err_size, "No system output nodes are connected\n");
LADSPA_API_RETURN(fx, FLUID_FAILED); LADSPA_API_RETURN(fx, FLUID_FAILED);
} }
/* Check that custom audio nodes have both input and output and control nodes have either if (check_all_audio_nodes_connected(fx, &str) == FLUID_FAILED)
* an input or output */
for (i = num_system_nodes; i < fx->num_nodes; i++)
{ {
if (fx->nodes[i]->type == FLUID_LADSPA_NODE_AUDIO && FLUID_SNPRINTF(err, err_size, "Audio node '%s' is not fully connected\n", str);
(fx->nodes[i]->num_inputs == 0 || fx->nodes[i]->num_outputs == 0)) LADSPA_API_RETURN(fx, FLUID_FAILED);
{ }
FLUID_SNPRINTF(err, err_size, "Audio node '%s' is not connected on input and output\n",
fx->nodes[i]->name);
LADSPA_API_RETURN(fx, FLUID_FAILED);
}
if (fx->nodes[i]->type == FLUID_LADSPA_NODE_CONTROL && (fx->nodes[i]->num_outputs == 0) if (check_all_control_nodes_connected(fx, &str) == FLUID_FAILED)
&& (fx->nodes[i]->num_inputs == 0)) {
{ FLUID_SNPRINTF(err, err_size, "Control node '%s' is not connected\n", str);
FLUID_SNPRINTF(err, err_size, "Control node '%s' is not connected\n", fx->nodes[i]->name); LADSPA_API_RETURN(fx, FLUID_FAILED);
LADSPA_API_RETURN(fx, FLUID_FAILED);
}
} }
LADSPA_API_RETURN(fx, FLUID_OK); LADSPA_API_RETURN(fx, FLUID_OK);
@ -937,48 +923,48 @@ int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size)
#ifdef WITH_FLOAT #ifdef WITH_FLOAT
static FLUID_INLINE void buffer_to_node(fluid_real_t *buffer, fluid_ladspa_node_t *node) static FLUID_INLINE void buffer_to_node(fluid_real_t *buffer, fluid_ladspa_node_t *node, int num_samples)
{ {
/* If the node is not used by any plugin, then we don't need to fill it */ /* If the node is not used by any plugin, then we don't need to fill it */
if (node->num_outputs > 0) if (node->num_outputs > 0)
{ {
FLUID_MEMCPY(node->buf, buffer, FLUID_BUFSIZE * sizeof(float)); FLUID_MEMCPY(node->buf, buffer, num_samples * sizeof(float));
} }
} }
static FLUID_INLINE void node_to_buffer(fluid_ladspa_node_t *node, fluid_real_t *buffer) static FLUID_INLINE void node_to_buffer(fluid_ladspa_node_t *node, fluid_real_t *buffer, int num_samples)
{ {
/* If the node has no inputs, then we don't need to copy it to the node */ /* If the node has no inputs, then we don't need to copy it to the node */
if (node->num_inputs > 0) if (node->num_inputs > 0)
{ {
FLUID_MEMCPY(buffer, node->buf, FLUID_BUFSIZE * sizeof(float)); FLUID_MEMCPY(buffer, node->buf, num_samples * sizeof(float));
} }
} }
#else /* WITH_FLOAT */ #else /* WITH_FLOAT */
static FLUID_INLINE void buffer_to_node(fluid_real_t *buffer, fluid_ladspa_node_t *node) static FLUID_INLINE void buffer_to_node(fluid_real_t *buffer, fluid_ladspa_node_t *node, int num_samples)
{ {
int i; int i;
/* If the node is not used by any plugin, then we don't need to fill it */ /* If the node is not used by any plugin, then we don't need to fill it */
if (node->num_outputs > 0) if (node->num_outputs > 0)
{ {
for (i = 0; i < FLUID_BUFSIZE; i++) for (i = 0; i < num_samples; i++)
{ {
node->buf[i] = (LADSPA_Data)buffer[i]; node->buf[i] = (LADSPA_Data)buffer[i];
} }
} }
} }
static FLUID_INLINE void node_to_buffer(fluid_ladspa_node_t *node, fluid_real_t *buffer) static FLUID_INLINE void node_to_buffer(fluid_ladspa_node_t *node, fluid_real_t *buffer, int num_samples)
{ {
int i; int i;
/* If the node has no inputs, then we don't need to copy it to the node */ /* If the node has no inputs, then we don't need to copy it to the node */
if (node->num_inputs > 0) if (node->num_inputs > 0)
{ {
for (i = 0; i < FLUID_BUFSIZE; i++) for (i = 0; i < num_samples; i++)
{ {
buffer[i] = (fluid_real_t)node->buf[i]; buffer[i] = (fluid_real_t)node->buf[i];
} }
@ -1138,14 +1124,14 @@ new_fluid_ladspa_plugin(fluid_ladspa_fx_t *fx, const fluid_ladspa_lib_t *lib, co
return NULL; return NULL;
} }
plugin->ports = FLUID_ARRAY(fluid_ladspa_port_state_t, plugin->desc->PortCount); plugin->port_nodes = FLUID_ARRAY(fluid_ladspa_node_t*, plugin->desc->PortCount);
if (plugin->ports == NULL) if (plugin->port_nodes == NULL)
{ {
delete_fluid_ladspa_plugin(plugin); delete_fluid_ladspa_plugin(plugin);
FLUID_LOG(FLUID_ERR, "Out of memory"); FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL; return NULL;
} }
FLUID_MEMSET(plugin->ports, 0, plugin->desc->PortCount * sizeof(fluid_ladspa_port_state_t)); FLUID_MEMSET(plugin->port_nodes, 0, plugin->desc->PortCount * sizeof(fluid_ladspa_node_t*));
return plugin; return plugin;
} }
@ -1157,9 +1143,9 @@ static void delete_fluid_ladspa_plugin(fluid_ladspa_plugin_t *plugin)
return; return;
} }
if (plugin->ports != NULL) if (plugin->port_nodes != NULL)
{ {
FLUID_FREE(plugin->ports); FLUID_FREE(plugin->port_nodes);
} }
if (plugin->handle != NULL && plugin->desc != NULL && plugin->desc->cleanup != NULL) if (plugin->handle != NULL && plugin->desc != NULL && plugin->desc->cleanup != NULL)
@ -1171,10 +1157,12 @@ static void delete_fluid_ladspa_plugin(fluid_ladspa_plugin_t *plugin)
} }
static fluid_ladspa_node_t *new_fluid_ladspa_node(fluid_ladspa_fx_t *fx, const char *name, static fluid_ladspa_node_t *new_fluid_ladspa_node(fluid_ladspa_fx_t *fx, const char *name,
fluid_ladspa_node_type_t type, int buf_size) fluid_ladspa_node_type_t type)
{ {
int buf_size;
fluid_ladspa_node_t *node; fluid_ladspa_node_t *node;
/* check if node with this name exits already */ /* check if node with this name exits already */
if (FLUID_STRLEN(name) > 0 && get_node(fx, name) != NULL) if (FLUID_STRLEN(name) > 0 && get_node(fx, name) != NULL)
{ {
@ -1205,6 +1193,9 @@ static fluid_ladspa_node_t *new_fluid_ladspa_node(fluid_ladspa_fx_t *fx, const c
return NULL; return NULL;
} }
/* Audio buffers get the full buffer size, control ports use only one float value */
buf_size = (type == FLUID_LADSPA_NODE_AUDIO) ? fx->buffer_size : 1;
node->buf = FLUID_ARRAY(LADSPA_Data, buf_size); node->buf = FLUID_ARRAY(LADSPA_Data, buf_size);
if (node->buf == NULL) if (node->buf == NULL)
{ {
@ -1516,14 +1507,14 @@ static int connect_default_control_nodes(fluid_ladspa_fx_t *fx, fluid_ladspa_plu
{ {
port_flags = plugin->desc->PortDescriptors[i]; port_flags = plugin->desc->PortDescriptors[i];
if (plugin->ports[i].num_inputs > 0 || !LADSPA_IS_PORT_CONTROL(port_flags)) if ((plugin->port_nodes[i] != NULL) || !LADSPA_IS_PORT_CONTROL(port_flags))
{ {
continue; continue;
} }
if (set_default_port_value(plugin, i, fx->sample_rate, &value) == FLUID_OK) if (set_default_port_value(plugin, i, fx->sample_rate, &value) == FLUID_OK)
{ {
node = new_fluid_ladspa_node(fx, "", FLUID_LADSPA_NODE_CONTROL, 1); node = new_fluid_ladspa_node(fx, "", FLUID_LADSPA_NODE_CONTROL);
if (node == NULL) if (node == NULL)
{ {
return FLUID_FAILED; return FLUID_FAILED;
@ -1543,17 +1534,168 @@ static void connect_node_to_port(fluid_ladspa_node_t *node, fluid_ladspa_dir_t d
fluid_ladspa_plugin_t *plugin, int port_idx) fluid_ladspa_plugin_t *plugin, int port_idx)
{ {
plugin->desc->connect_port(plugin->handle, port_idx, node->buf); plugin->desc->connect_port(plugin->handle, port_idx, node->buf);
plugin->port_nodes[port_idx] = node;
/* Mark port and node as connected in the respective direction */ /* Mark node as connected in the respective direction */
if (dir == FLUID_LADSPA_INPUT || dir == FLUID_LADSPA_FIXED) if (dir == FLUID_LADSPA_INPUT || dir == FLUID_LADSPA_FIXED)
{ {
plugin->ports[port_idx].num_inputs++;
node->num_outputs++; node->num_outputs++;
} }
else else
{ {
plugin->ports[port_idx].num_outputs++;
node->num_inputs++; node->num_inputs++;
} }
} }
/**
* Check that all ports on the plugin are connected to a node.
*
* @param plugin LADSPA plugin instance
* @param name if check fails, points to the name of first failed port
* @return FLUID_OK on successful check, otherwise FLUID_FAILED
*/
static int check_all_ports_connected(fluid_ladspa_plugin_t *plugin, const char **name)
{
unsigned int i;
for (i = 0; i < plugin->desc->PortCount; i++)
{
if (plugin->port_nodes[i] == NULL)
{
*name = plugin->desc->PortNames[i];
return FLUID_FAILED;
}
}
return FLUID_OK;
}
/**
* In-place broken plugins can't cope with input and output audio ports connected
* to the same buffer. Check for this condition in the plugin.
*
* @param plugin LADSPA plugin instance
* @param name1 if check fails, points to the first port name
* @param name2 if check fails, points to the second port name
* @return FLUID_OK on successful check, otherwise FLUID_FAILED
*/
static int check_no_inplace_broken(fluid_ladspa_plugin_t *plugin, const char **name1, const char **name2)
{
unsigned int i, k;
LADSPA_PortDescriptor flags1, flags2;
if (!LADSPA_IS_INPLACE_BROKEN(plugin->desc->Properties))
{
return FLUID_OK;
}
for (i = 0; i < plugin->desc->PortCount; i++)
{
flags1 = plugin->desc->PortDescriptors[i];
for (k = 0; k < plugin->desc->PortCount; k++)
{
flags2 = plugin->desc->PortDescriptors[k];
if (i != k
&& plugin->port_nodes[i]->buf == plugin->port_nodes[k]->buf
&& (flags1 & 0x3) != (flags2 & 0x3) /* first two bits encode direction */
&& LADSPA_IS_PORT_AUDIO(flags1) && LADSPA_IS_PORT_AUDIO(flags2))
{
*name1 = plugin->desc->PortNames[i];
*name2 = plugin->desc->PortNames[k];
return FLUID_FAILED;
}
}
}
return FLUID_OK;
}
/**
* Check that at least one system input is used
*
* @param fx LADSPA fx instance
* @return FLUID_OK on successful check, otherwise FLUID_FAILED
*/
static int check_system_input_used(fluid_ladspa_fx_t *fx)
{
int i;
for (i = 0; i < 2 * (fx->audio_groups + fx->effects_channels); i++)
{
if (fx->nodes[i]->num_outputs)
{
return FLUID_OK;
}
}
return FLUID_FAILED;
}
/**
* Check that at least one system output is used
*
* @param fx LADSPA fx instance
* @return FLUID_OK on successful check, otherwise FLUID_FAILED
*/
static int check_system_output_used(fluid_ladspa_fx_t *fx)
{
int i;
int num_system_nodes = 2 * (fx->audio_groups + fx->effects_channels + fx->audio_channels);
for (i = 2 * (fx->audio_groups + fx->effects_channels); i < num_system_nodes; i++)
{
if (fx->nodes[i]->num_inputs)
{
return FLUID_OK;
}
}
return FLUID_FAILED;
}
/**
* Check that all user audio nodes have an input and an output
*
* @param fx LADSPA fx instance
* @param name if check fails, points to the name of first failed node
* @return FLUID_OK on successful check, otherwise FLUID_FAILED
*/
static int check_all_audio_nodes_connected(fluid_ladspa_fx_t *fx, const char **name)
{
int i;
int num_system_nodes = 2 * (fx->audio_groups + fx->effects_channels + fx->audio_channels);
for (i = num_system_nodes; i < fx->num_nodes; i++)
{
if (fx->nodes[i]->type == FLUID_LADSPA_NODE_AUDIO &&
(fx->nodes[i]->num_inputs == 0 || fx->nodes[i]->num_outputs == 0))
{
*name = fx->nodes[i]->name;
return FLUID_FAILED;
}
}
return FLUID_OK;
}
/**
* Check that all user control nodes have an input or an output
*
* @param fx LADSPA fx instance
* @param name if check fails, points to the name of first failed node
* @return FLUID_OK on successful check, otherwise FLUID_FAILED
*/
static int check_all_control_nodes_connected(fluid_ladspa_fx_t *fx, const char **name)
{
int i;
int num_system_nodes = 2 * (fx->audio_groups + fx->effects_channels + fx->audio_channels);
for (i = num_system_nodes; i < fx->num_nodes; i++)
{
if (fx->nodes[i]->type == FLUID_LADSPA_NODE_CONTROL &&
(fx->nodes[i]->num_outputs == 0) && (fx->nodes[i]->num_inputs == 0))
{
*name = fx->nodes[i]->name;
return FLUID_FAILED;
}
}
return FLUID_OK;
}

View file

@ -63,28 +63,6 @@ typedef struct _fluid_ladspa_lib_t
} fluid_ladspa_lib_t; } fluid_ladspa_lib_t;
typedef struct _fluid_ladspa_port_state_t
{
int num_inputs;
int num_outputs;
} fluid_ladspa_port_state_t;
typedef struct _fluid_ladspa_plugin_t
{
/* plugin instance id unique to the effects unit */
int id;
const LADSPA_Descriptor *desc;
LADSPA_Handle *handle;
int active;
/* Used to keep track of the port connection states */
fluid_ladspa_port_state_t *ports;
} fluid_ladspa_plugin_t;
typedef struct _fluid_ladspa_node_t typedef struct _fluid_ladspa_node_t
{ {
char *name; char *name;
@ -96,6 +74,21 @@ typedef struct _fluid_ladspa_node_t
} fluid_ladspa_node_t; } fluid_ladspa_node_t;
typedef struct _fluid_ladspa_plugin_t
{
/* plugin instance id unique to the effects unit */
int id;
const LADSPA_Descriptor *desc;
LADSPA_Handle *handle;
int active;
/* Used to keep track of the port connection state */
fluid_ladspa_node_t **port_nodes;
} fluid_ladspa_plugin_t;
typedef struct _fluid_ladspa_fx_t typedef struct _fluid_ladspa_fx_t
{ {
unsigned long sample_rate; unsigned long sample_rate;
@ -103,6 +96,7 @@ typedef struct _fluid_ladspa_fx_t
int audio_groups; int audio_groups;
int effects_channels; int effects_channels;
int audio_channels; int audio_channels;
int buffer_size;
fluid_ladspa_lib_t *libs[FLUID_LADSPA_MAX_LIBS]; fluid_ladspa_lib_t *libs[FLUID_LADSPA_MAX_LIBS];
int num_libs; int num_libs;
@ -128,7 +122,7 @@ typedef struct _fluid_ladspa_fx_t
} fluid_ladspa_fx_t; } fluid_ladspa_fx_t;
fluid_ladspa_fx_t *new_fluid_ladspa_fx(fluid_real_t sample_rate, int audio_groups, int effects_channels, int audio_channels); fluid_ladspa_fx_t *new_fluid_ladspa_fx(fluid_real_t sample_rate, int audio_groups, int effects_channels, int audio_channels, int buffer_size);
void delete_fluid_ladspa_fx(fluid_ladspa_fx_t *fx); void delete_fluid_ladspa_fx(fluid_ladspa_fx_t *fx);
int fluid_ladspa_set_sample_rate(fluid_ladspa_fx_t *fx, fluid_real_t sample_rate); int fluid_ladspa_set_sample_rate(fluid_ladspa_fx_t *fx, fluid_real_t sample_rate);
@ -138,7 +132,7 @@ int fluid_ladspa_deactivate(fluid_ladspa_fx_t *fx);
int fluid_ladspa_reset(fluid_ladspa_fx_t *fx); int fluid_ladspa_reset(fluid_ladspa_fx_t *fx);
void fluid_ladspa_run(fluid_ladspa_fx_t *fx, fluid_real_t *left_buf[], fluid_real_t *right_buf[], void fluid_ladspa_run(fluid_ladspa_fx_t *fx, fluid_real_t *left_buf[], fluid_real_t *right_buf[],
fluid_real_t *fx_left_buf[], fluid_real_t *fx_right_buf[]); fluid_real_t *fx_left_buf[], fluid_real_t *fx_right_buf[], int block_count, int block_size);
int fluid_ladspa_add_plugin(fluid_ladspa_fx_t *fx, const char *lib_name, const char *plugin_name); int fluid_ladspa_add_plugin(fluid_ladspa_fx_t *fx, const char *lib_name, const char *plugin_name);
int fluid_ladspa_port_exists(fluid_ladspa_fx_t *fx, int plugin_id, const char *name); int fluid_ladspa_port_exists(fluid_ladspa_fx_t *fx, int plugin_id, const char *name);

View file

@ -142,33 +142,12 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
#ifdef LADSPA #ifdef LADSPA
/* Run the signal through the LADSPA Fx unit */ /* Run the signal through the LADSPA Fx unit */
if (mixer->ladspa_fx && mixer->ladspa_fx->state == FLUID_LADSPA_ACTIVE) { if (mixer->ladspa_fx) {
int j; fluid_ladspa_run(mixer->ladspa_fx,
FLUID_DECLARE_VLA(fluid_real_t*, left_buf, mixer->buffers.buf_count); mixer->buffers.left_buf, mixer->buffers.right_buf,
FLUID_DECLARE_VLA(fluid_real_t*, right_buf, mixer->buffers.buf_count); mixer->buffers.fx_left_buf, mixer->buffers.fx_right_buf,
FLUID_DECLARE_VLA(fluid_real_t*, fx_left_buf, mixer->buffers.fx_buf_count); mixer->current_blockcount, FLUID_BUFSIZE);
FLUID_DECLARE_VLA(fluid_real_t*, fx_right_buf, mixer->buffers.fx_buf_count); fluid_check_fpe("LADSPA");
for (j=0; j < mixer->buffers.buf_count; j++) {
left_buf[j] = mixer->buffers.left_buf[j];
right_buf[j] = mixer->buffers.right_buf[j];
}
for (j=0; j < mixer->buffers.fx_buf_count; j++) {
fx_left_buf[j] = mixer->buffers.fx_left_buf[j];
fx_right_buf[j] = mixer->buffers.fx_right_buf[j];
}
for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE) {
fluid_ladspa_run(mixer->ladspa_fx, left_buf, right_buf, fx_left_buf,
fx_right_buf);
for (j=0; j < mixer->buffers.buf_count; j++) {
left_buf[j] += FLUID_BUFSIZE;
right_buf[j] += FLUID_BUFSIZE;
}
for (j=0; j < mixer->buffers.fx_buf_count; j++) {
fx_left_buf[j] += FLUID_BUFSIZE;
fx_right_buf[j] += FLUID_BUFSIZE;
}
}
fluid_check_fpe("LADSPA");
} }
#endif #endif
} }

View file

@ -711,7 +711,8 @@ new_fluid_synth(fluid_settings_t *settings)
if (with_ladspa) { if (with_ladspa) {
#ifdef LADSPA #ifdef LADSPA
synth->ladspa_fx = new_fluid_ladspa_fx(synth->sample_rate, synth->audio_groups, synth->ladspa_fx = new_fluid_ladspa_fx(synth->sample_rate, synth->audio_groups,
synth->effects_channels, synth->audio_channels); synth->effects_channels, synth->audio_channels,
FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE);
if(synth->ladspa_fx == NULL) { if(synth->ladspa_fx == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory"); FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery; goto error_recovery;