mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 15:01:40 +00:00
Merge pull request #240 from mawe42/ladspa-port-defaults
Add support for LADSPA control port defaults
This commit is contained in:
commit
de617dd1f3
4 changed files with 223 additions and 12 deletions
|
@ -189,6 +189,8 @@ static const fluid_cmd_int_t fluid_commands[] = {
|
|||
"ladspa_node Create a LADSPA audio or control node"},
|
||||
{ "ladspa_control", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_control,
|
||||
"ladspa_control Set the value of a LADSPA control node"},
|
||||
{ "ladspa_control_defaults", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_control_defaults,
|
||||
"ladspa_control_defaults Assign all unconnected controls on all plugins their default value"},
|
||||
{ "ladspa_check", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_check,
|
||||
"ladspa_check Check LADSPA configuration"},
|
||||
{ "ladspa_start", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_start,
|
||||
|
@ -1908,6 +1910,23 @@ int fluid_handle_ladspa_reset(fluid_cmd_handler_t *handler, int ac, char **av, f
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
int fluid_handle_ladspa_control_defaults(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
|
||||
{
|
||||
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
|
||||
|
||||
CHECK_LADSPA_ENABLED(fx, out);
|
||||
|
||||
if (fluid_ladspa_control_defaults(fx) != FLUID_OK)
|
||||
{
|
||||
fluid_ostream_printf(out, "Error while setting default values for control ports\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
fluid_ostream_printf(out, "Control port defaults set\n");
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
int fluid_handle_ladspa_check(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
|
||||
{
|
||||
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
|
||||
|
|
|
@ -91,6 +91,7 @@ int fluid_handle_ladspa_plugin(fluid_cmd_handler_t *handler, int ac, char **av,
|
|||
int fluid_handle_ladspa_port(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_node(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_control(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_control_defaults(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_check(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_start(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
int fluid_handle_ladspa_stop(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "fluid_ladspa.h"
|
||||
#include "fluid_sys.h"
|
||||
#include <dlfcn.h>
|
||||
#include <math.h>
|
||||
|
||||
#define LADSPA_API_ENTER(_fx) (fluid_rec_mutex_lock((_fx)->api_mutex))
|
||||
|
||||
|
@ -66,6 +67,12 @@ 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 buffer_to_node(fluid_real_t *buffer, fluid_ladspa_node_t *node);
|
||||
|
||||
static int set_default_port_value(fluid_ladspa_plugin_t *plugin, unsigned int port_idx,
|
||||
int sample_rate, LADSPA_Data *data);
|
||||
static void connect_node_to_port(fluid_ladspa_node_t *node, fluid_ladspa_dir_t dir,
|
||||
fluid_ladspa_plugin_t *plugin, int port_idx);
|
||||
static int connect_default_control_nodes(fluid_ladspa_fx_t *fx, fluid_ladspa_plugin_t *plugin);
|
||||
|
||||
/**
|
||||
* Creates a new LADSPA effects unit.
|
||||
*
|
||||
|
@ -238,6 +245,12 @@ int fluid_ladspa_activate(fluid_ladspa_fx_t *fx)
|
|||
LADSPA_API_RETURN(fx, FLUID_FAILED);
|
||||
}
|
||||
|
||||
if (fluid_ladspa_check(fx, NULL, 0) != FLUID_OK)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "LADSPA check failed, unable to activate effects");
|
||||
LADSPA_API_RETURN(fx, FLUID_FAILED);
|
||||
}
|
||||
|
||||
for (i = 0; i < fx->num_plugins; i++)
|
||||
{
|
||||
activate_plugin(fx->plugins[i]);
|
||||
|
@ -781,18 +794,30 @@ int fluid_ladspa_connect(fluid_ladspa_fx_t *fx, int plugin_id, fluid_ladspa_dir_
|
|||
FLUID_LOG(FLUID_DBG, "Connecting LADSPA plugin '%s': port '%s' %s node '%s'", plugin->desc->Label,
|
||||
full_port_name, (dir == FLUID_LADSPA_INPUT) ? "<" : ">", node_name);
|
||||
|
||||
plugin->desc->connect_port(plugin->handle, port_idx, node->buf);
|
||||
connect_node_to_port(node, dir, plugin, port_idx);
|
||||
|
||||
/* Mark port and node as connected in the respective direction */
|
||||
if (dir == FLUID_LADSPA_INPUT || dir == FLUID_LADSPA_FIXED)
|
||||
LADSPA_API_RETURN(fx, FLUID_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all unconnected control ports on all configured plugins and fill any unconnected ports with
|
||||
* their default value, if available.
|
||||
*
|
||||
* @param fx LADSPA fx instance
|
||||
* @return FLUID_OK on success, otherwise FLUID_FAILED
|
||||
*/
|
||||
int fluid_ladspa_control_defaults(fluid_ladspa_fx_t *fx)
|
||||
{
|
||||
int i;
|
||||
|
||||
LADSPA_API_ENTER(fx);
|
||||
|
||||
for (i = 0; i < fx->num_plugins; i++)
|
||||
{
|
||||
plugin->ports[port_idx].num_inputs++;
|
||||
node->num_outputs++;
|
||||
}
|
||||
else
|
||||
{
|
||||
plugin->ports[port_idx].num_outputs++;
|
||||
node->num_inputs++;
|
||||
if (connect_default_control_nodes(fx, fx->plugins[i]) != FLUID_OK)
|
||||
{
|
||||
LADSPA_API_RETURN(fx, FLUID_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
LADSPA_API_RETURN(fx, FLUID_OK);
|
||||
|
@ -882,7 +907,8 @@ int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size)
|
|||
LADSPA_API_RETURN(fx, FLUID_FAILED);
|
||||
}
|
||||
|
||||
/* Check that custom audio nodes have both input and output and control nodes have an output */
|
||||
/* Check that custom audio nodes have both input and output and control nodes have either
|
||||
* an input or output */
|
||||
for (i = num_system_nodes; i < fx->num_nodes; i++)
|
||||
{
|
||||
if (fx->nodes[i]->type == FLUID_LADSPA_NODE_AUDIO &&
|
||||
|
@ -893,7 +919,8 @@ int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size)
|
|||
LADSPA_API_RETURN(fx, FLUID_FAILED);
|
||||
}
|
||||
|
||||
if (fx->nodes[i]->type == FLUID_LADSPA_NODE_CONTROL && (fx->nodes[i]->num_outputs == 0))
|
||||
if (fx->nodes[i]->type == FLUID_LADSPA_NODE_CONTROL && (fx->nodes[i]->num_outputs == 0)
|
||||
&& (fx->nodes[i]->num_inputs == 0))
|
||||
{
|
||||
FLUID_SNPRINTF(err, err_size, "Control node '%s' is not connected\n", fx->nodes[i]->name);
|
||||
LADSPA_API_RETURN(fx, FLUID_FAILED);
|
||||
|
@ -1356,4 +1383,167 @@ static fluid_ladspa_plugin_t *get_plugin_by_id(fluid_ladspa_fx_t *fx, int id)
|
|||
LADSPA_API_RETURN(fx, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default value of a plugin port, as specified by the port hints.
|
||||
*
|
||||
* @param plugin pointer to plugin instance
|
||||
* @param port_idx index of the port in the plugin
|
||||
* @param sample_rate the current sample rate of the LADSPA fx
|
||||
* @param pointer to LADSPA_Data value to set
|
||||
* @return FLUID_OK on success, otherwise FLUID_FAILED
|
||||
*/
|
||||
static int set_default_port_value(fluid_ladspa_plugin_t *plugin, unsigned int port_idx, int sample_rate,
|
||||
LADSPA_Data *data)
|
||||
{
|
||||
const LADSPA_PortRangeHint *hint;
|
||||
LADSPA_PortRangeHintDescriptor flags;
|
||||
LADSPA_Data value;
|
||||
float low_factor = 0.0;
|
||||
float high_factor = 0.0;
|
||||
|
||||
if (port_idx >= plugin->desc->PortCount)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
hint = &plugin->desc->PortRangeHints[port_idx];
|
||||
flags = hint->HintDescriptor;
|
||||
|
||||
if (!LADSPA_IS_HINT_HAS_DEFAULT(flags))
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
if (LADSPA_IS_HINT_DEFAULT_0(flags))
|
||||
{
|
||||
value = 0.0;
|
||||
}
|
||||
else if (LADSPA_IS_HINT_DEFAULT_1(flags))
|
||||
{
|
||||
value = 1.0;
|
||||
}
|
||||
else if (LADSPA_IS_HINT_DEFAULT_100(flags))
|
||||
{
|
||||
value = 100.0;
|
||||
}
|
||||
else if (LADSPA_IS_HINT_DEFAULT_440(flags))
|
||||
{
|
||||
value = 440.0;
|
||||
}
|
||||
/* defaults based on lower or upper bounds must consider HINT_SAMPLE_RATE */
|
||||
else {
|
||||
if (LADSPA_IS_HINT_DEFAULT_MINIMUM(flags))
|
||||
{
|
||||
low_factor = 1.0;
|
||||
high_factor = 0.0;
|
||||
}
|
||||
else if (LADSPA_IS_HINT_DEFAULT_LOW(flags))
|
||||
{
|
||||
low_factor = 0.75;
|
||||
high_factor = 0.25;
|
||||
}
|
||||
else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(flags))
|
||||
{
|
||||
low_factor = 0.5;
|
||||
high_factor = 0.5;
|
||||
}
|
||||
else if (LADSPA_IS_HINT_DEFAULT_HIGH(flags))
|
||||
{
|
||||
low_factor = 0.25;
|
||||
high_factor = 0.75;
|
||||
}
|
||||
else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(flags))
|
||||
{
|
||||
low_factor = 0.0;
|
||||
high_factor = 1.0;
|
||||
}
|
||||
|
||||
if (LADSPA_IS_HINT_LOGARITHMIC(flags) && low_factor > 0 && high_factor > 0)
|
||||
{
|
||||
value = exp(log(hint->LowerBound) * low_factor + log(hint->UpperBound) * high_factor);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (hint->LowerBound * low_factor + hint->UpperBound * high_factor);
|
||||
}
|
||||
|
||||
if (LADSPA_IS_HINT_SAMPLE_RATE(flags))
|
||||
{
|
||||
value *= sample_rate;
|
||||
}
|
||||
}
|
||||
|
||||
if (LADSPA_IS_HINT_INTEGER(flags))
|
||||
{
|
||||
/* LADSPA doesn't specify which rounding method to use, so lets keep it simple... */
|
||||
value = floor(value + 0.5);
|
||||
}
|
||||
|
||||
*data = value;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* For each control port that hasn't got an input yet, create a node based on the port hints
|
||||
* specified in the plugin (if available).
|
||||
*
|
||||
* @param fx LADSPA fx instance
|
||||
* @param plugin plugin instance
|
||||
* @return FLUID_OK on success, otherwise FLUID_FAILED
|
||||
*/
|
||||
static int connect_default_control_nodes(fluid_ladspa_fx_t *fx, fluid_ladspa_plugin_t *plugin)
|
||||
{
|
||||
unsigned int i;
|
||||
LADSPA_Data value;
|
||||
fluid_ladspa_node_t *node;
|
||||
fluid_ladspa_dir_t dir;
|
||||
int port_flags;
|
||||
|
||||
for (i = 0; i < plugin->desc->PortCount; i++)
|
||||
{
|
||||
port_flags = plugin->desc->PortDescriptors[i];
|
||||
|
||||
if (plugin->ports[i].num_inputs > 0 || !LADSPA_IS_PORT_CONTROL(port_flags))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (set_default_port_value(plugin, i, fx->sample_rate, &value) == FLUID_OK)
|
||||
{
|
||||
node = new_fluid_ladspa_node(fx, "", FLUID_LADSPA_NODE_CONTROL, 1);
|
||||
if (node == NULL)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
node->buf[0] = value;
|
||||
|
||||
dir = LADSPA_IS_PORT_INPUT(port_flags) ? FLUID_LADSPA_INPUT : FLUID_LADSPA_OUTPUT;
|
||||
|
||||
connect_node_to_port(node, dir, plugin, i);
|
||||
}
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
static void connect_node_to_port(fluid_ladspa_node_t *node, fluid_ladspa_dir_t dir,
|
||||
fluid_ladspa_plugin_t *plugin, int port_idx)
|
||||
{
|
||||
plugin->desc->connect_port(plugin->handle, port_idx, node->buf);
|
||||
|
||||
/* Mark port and node as connected in the respective direction */
|
||||
if (dir == FLUID_LADSPA_INPUT || dir == FLUID_LADSPA_FIXED)
|
||||
{
|
||||
plugin->ports[port_idx].num_inputs++;
|
||||
node->num_outputs++;
|
||||
}
|
||||
else
|
||||
{
|
||||
plugin->ports[port_idx].num_outputs++;
|
||||
node->num_inputs++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /*LADSPA*/
|
||||
|
|
|
@ -151,6 +151,7 @@ int fluid_ladspa_node_exists(fluid_ladspa_fx_t *fx, const char *name);
|
|||
int fluid_ladspa_connect(fluid_ladspa_fx_t *fx, int plugin_id, fluid_ladspa_dir_t dir,
|
||||
const char *port_name, const char *node_name);
|
||||
int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size);
|
||||
int fluid_ladspa_control_defaults(fluid_ladspa_fx_t *fx);
|
||||
|
||||
#endif /* LADSPA */
|
||||
#endif /* _FLUID_LADSPA_H */
|
||||
|
|
Loading…
Reference in a new issue