Major refactor and rewrite of the LADSPA effects engine.

This commit is contained in:
Marcus Weseloh 2017-10-19 23:24:01 +02:00
parent 09f237fd0c
commit 4120b2320f
9 changed files with 1658 additions and 1239 deletions

View file

@ -48,6 +48,11 @@ struct _fluid_cmd_handler_t {
fluid_midi_router_rule_t *cmd_rule; /* Rule currently being processed by shell command handler */
int cmd_rule_type; /* Type of the rule (#fluid_midi_router_rule_type) */
#ifdef LADSPA
/* Instance id of the LADSPA plugin currently being processed by shell command handler */
int ladspa_plugin_id;
#endif
};
@ -165,16 +170,22 @@ static fluid_cmd_t fluid_commands[] = {
"echo arg Print arg" },
/* LADSPA-related commands */
#ifdef LADSPA
{ "ladspa_clear", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_clear, NULL,
"ladspa_clear Resets LADSPA effect unit to bypass state"},
{ "ladspa_add", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_add, NULL,
"ladspa_add lib plugin n1 <- p1 n2 -> p2 ... Loads and connects LADSPA plugin"},
{ "ladspa_start", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_start, NULL,
"ladspa_start Starts LADSPA effect unit"},
{ "ladspa_declnode", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_declnode, NULL,
"ladspa_declnode node value Declares control node `node' with value `value'"},
{ "ladspa_setnode", "ladspa", (fluid_cmd_func_t) fluid_LADSPA_handle_setnode, NULL,
"ladspa_setnode node value Assigns `value' to `node'"},
{ "ladspa_plugin", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_plugin, NULL,
"ladspa_plugin Instantiate a new LADSPA plugin"},
{ "ladspa_port", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_port, NULL,
"ladspa_port Connect a LADSPA plugin port"},
{ "ladspa_node", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_node, NULL,
"ladspa_node Create a LADSPA audio or control node"},
{ "ladspa_control", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_control, NULL,
"ladspa_control Set the value of a LADSPA control node"},
{ "ladspa_check", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_check, NULL,
"ladspa_check Check LADSPA configuration"},
{ "ladspa_start", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_start, NULL,
"ladspa_start Start LADSPA effects"},
{ "ladspa_stop", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_stop, NULL,
"ladspa_stop Stop LADSPA effect unit"},
{ "ladspa_reset", "ladspa", (fluid_cmd_func_t) fluid_handle_ladspa_reset, NULL,
"ladspa_reset Stop and reset LADSPA effects"},
#endif
{ "router_clear", "router", (fluid_cmd_func_t) fluid_handle_router_clear, NULL,
"router_clear Clears all routing rules from the midi router"},
@ -1817,6 +1828,271 @@ int fluid_handle_router_par2(fluid_cmd_handler_t* handler, int ac, char** av, fl
return FLUID_OK;
}
#ifdef LADSPA
#define CHECK_LADSPA_ENABLED(_fx, _out) \
if (_fx == NULL) \
{ \
fluid_ostream_printf(_out, "LADSPA is not enabled.\n"); \
return FLUID_FAILED; \
}
#define LADSPA_ERR_LEN (1024)
int fluid_handle_ladspa_start(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
{
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
char error[LADSPA_ERR_LEN];
CHECK_LADSPA_ENABLED(fx, out);
if (fluid_ladspa_is_active(fx))
{
fluid_ostream_printf(out, "LADSPA already started.\n");
return FLUID_FAILED;
}
if (fluid_ladspa_check(fx, error, LADSPA_ERR_LEN) != FLUID_OK)
{
fluid_ostream_printf(out, "LADSPA check failed: %s", error);
fluid_ostream_printf(out, "LADSPA not started.\n");
return FLUID_FAILED;
}
if (fluid_ladspa_activate(fx, handler->synth) != FLUID_OK)
{
fluid_ostream_printf(out, "Unable to start LADSPA.\n");
return FLUID_FAILED;
}
return FLUID_OK;
}
int fluid_handle_ladspa_stop(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_is_active(fx))
{
fluid_ostream_printf(out, "LADSPA has not been started.\n");
}
if (fluid_ladspa_deactivate(fx, handler->synth) != FLUID_OK)
{
fluid_ostream_printf(out, "Unable to stop LADSPA.\n");
return FLUID_FAILED;
}
return FLUID_OK;
}
int fluid_handle_ladspa_reset(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_is_active(fx))
{
fluid_ladspa_deactivate(fx, handler->synth);
}
fluid_ladspa_reset(fx);
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;
char error[LADSPA_ERR_LEN];
CHECK_LADSPA_ENABLED(fx, out);
if (fluid_ladspa_check(fx, error, LADSPA_ERR_LEN) != FLUID_OK)
{
fluid_ostream_printf(out, "LADSPA check failed: %s", error);
return FLUID_FAILED;
}
fluid_ostream_printf(out, "LADSPA check ok\n");
return FLUID_OK;
}
int fluid_handle_ladspa_control(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 (ac != 2)
{
fluid_ostream_printf(out, "ladspa_control needs two arguments: node name and value.\n");
return FLUID_FAILED;
};
/* Redundant check, just here to give a more detailed error message */
if (!fluid_ladspa_node_exists(fx, av[0]))
{
fluid_ostream_printf(out, "Node '%s' not found.\n", av[0]);
return FLUID_FAILED;
}
if (fluid_ladspa_set_control_node(fx, av[0], atof(av[1])) != FLUID_OK)
{
fluid_ostream_printf(out, "Failed to set node '%s', maybe it's not a control node?\n",
av[0]);
return FLUID_FAILED;
}
return FLUID_OK;
};
int fluid_handle_ladspa_node(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
{
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
char *name;
char *type;
CHECK_LADSPA_ENABLED(fx, out);
if (ac < 2)
{
fluid_ostream_printf(out, "ladspa_node needs at least two arguments: node name and type.\n");
return FLUID_FAILED;
};
name = av[0];
type = av[1];
/* audio node - additional no arguments */
if (FLUID_STRCMP(type, "audio") == 0)
{
if (fluid_ladspa_add_audio_node(fx, name) != FLUID_OK)
{
fluid_ostream_printf(out, "Failed to add audio node.\n");
return FLUID_FAILED;
}
}
/* control node - arguments: <val> */
else if (FLUID_STRCMP(type, "control") == 0)
{
if (ac != 3)
{
fluid_ostream_printf(out, "Control nodes need 3 arguments.\n");
return FLUID_FAILED;
}
if (fluid_ladspa_add_control_node(fx, name, atof(av[2])) != FLUID_OK)
{
fluid_ostream_printf(out, "Failed to add contrl node.\n");
return FLUID_FAILED;
}
}
else {
fluid_ostream_printf(out, "Invalid node type.\n");
return FLUID_FAILED;
}
return FLUID_OK;
};
int fluid_handle_ladspa_plugin(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
{
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
int plugin_id;
CHECK_LADSPA_ENABLED(fx, out);
if (ac != 2)
{
fluid_ostream_printf(out, "ladspa_plugin needs 2 arguments: library and plugin id.\n");
return FLUID_FAILED;
}
plugin_id = fluid_ladspa_add_plugin(fx, av[0], av[1]);
if (plugin_id < 0)
{
fluid_ostream_printf(out, "Failed to add plugin.\n");
return FLUID_FAILED;
}
/* store current plugin in the handler, so that subsequent ladspa_port
* commands know which plugin to configure */
handler->ladspa_plugin_id = plugin_id;
return FLUID_OK;
}
int fluid_handle_ladspa_port(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out)
{
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
int dir;
CHECK_LADSPA_ENABLED(fx, out);
if (ac != 3)
{
fluid_ostream_printf(out, "ladspa_port needs 3 arguments: "
"port name, direction and node name.\n");
return FLUID_FAILED;
}
if (handler->ladspa_plugin_id == -1)
{
fluid_ostream_printf(out, "Please choose a plugin with ladspa_plugin first.\n");
return FLUID_FAILED;
}
if (FLUID_STRCMP(av[1], "<") == 0)
{
dir = FLUID_LADSPA_INPUT;
}
else if (FLUID_STRCMP(av[1], ">") == 0)
{
dir = FLUID_LADSPA_OUTPUT;
}
else if (FLUID_STRCMP(av[1], "=") == 0)
{
dir = FLUID_LADSPA_FIXED;
}
else
{
fluid_ostream_printf(out, "Invalid direction, please use <, > or =\n");
return FLUID_FAILED;
}
/* Check port and node name before trying to connect them by name. This is
* redundant, as fluid_ladspa_connect checks them as well, but we do it
* here anyway to give the user better feedback in case a port or node
* could not be found.
*/
if (!fluid_ladspa_port_exists(fx, handler->ladspa_plugin_id, av[0]))
{
fluid_ostream_printf(out, "Port '%s' not found.\n", av[0]);
return FLUID_FAILED;
}
if (dir != FLUID_LADSPA_FIXED && !fluid_ladspa_node_exists(fx, av[2]))
{
fluid_ostream_printf(out, "Node '%s' not found.\n", av[2]);
return FLUID_FAILED;
}
if (fluid_ladspa_connect(fx, handler->ladspa_plugin_id, dir, av[0], av[2]) != FLUID_OK)
{
fluid_ostream_printf(out, "Failed to connect plugin port.\n");
return FLUID_FAILED;
}
return FLUID_OK;
}
#endif /* LADSPA */
int
fluid_is_number(char* a)
{
@ -1943,6 +2219,10 @@ fluid_cmd_handler_t* new_fluid_cmd_handler(fluid_synth_t* synth, fluid_midi_rout
}
}
#ifdef LADSPA
handler->ladspa_plugin_id = -1;
#endif
return handler;
}

View file

@ -86,6 +86,16 @@ int fluid_handle_router_chan(fluid_cmd_handler_t* handler, int ac, char** av, fl
int fluid_handle_router_par1(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out);
int fluid_handle_router_par2(fluid_cmd_handler_t* handler, int ac, char** av, fluid_ostream_t out);
#ifdef LADSPA
int fluid_handle_ladspa_plugin(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
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_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);
int fluid_handle_ladspa_reset(fluid_cmd_handler_t *handler, int ac, char **av, fluid_ostream_t out);
#endif
fluid_cmd_t* fluid_cmd_copy(fluid_cmd_t* cmd);
void delete_fluid_cmd(fluid_cmd_t* cmd);

File diff suppressed because it is too large Load diff

View file

@ -21,220 +21,130 @@
/* Author: Markus Nentwig, nentwig@users.sourceforge.net
*/
#ifndef _FLUID_LADSPA_H
#define _FLUID_LADSPA_H
/***************************************************************
*
* INCLUDES
*/
#include "fluid_sys.h"
#include "fluidsynth_priv.h"
#ifdef LADSPA
#include "fluid_list.h"
#include <pthread.h>
#include <ladspa.h>
#include <pthread.h>
/***************************************************************
*
* DEFINES
*/
#define FLUID_LADSPA_MAX_LIBS 100
#define FLUID_LADSPA_MAX_PLUGINS 100
#define FLUID_LADSPA_MAX_NODES 100
#define FLUID_LADSPA_MAX_PATH_LENGTH 512
/* How many different plugin libraries may be used at the same time? */
#define FLUID_LADSPA_MaxLibs 100
/* How many plugin instances may be used at the same time? */
#define FLUID_LADSPA_MaxPlugins 100
/* How many nodes are allowed? */
#define FLUID_LADSPA_MaxNodes 100
/* How many tokens are allowed in one command line? (for example 152 => max. 50 port plugin allowed) */
#define FLUID_LADSPA_MaxTokens 152
/* What is the maximum path length? */
#define FLUID_LADSPA_MaxPathLength 512
/***************************************************************
*
* ENUM
*/
#define FLUID_LADSPA_INACTIVE (0)
#define FLUID_LADSPA_ACTIVE (1)
typedef enum {
fluid_LADSPA_NoMatch,
fluid_LADSPA_PartialMatch,
fluid_LADSPA_FullMatch
} fluid_LADSPA_Stringmatch_t;
typedef enum _fluid_ladspa_dir_t {
FLUID_LADSPA_INPUT,
FLUID_LADSPA_OUTPUT,
FLUID_LADSPA_FIXED
/* Bypass state of the Fx unit */
typedef enum {
fluid_LADSPA_Active,
fluid_LADSPA_Bypassed,
fluid_LADSPA_BypassRequest
} fluid_LADSPA_BypassState;
} fluid_ladspa_dir_t;
typedef enum {
fluid_LADSPA_node_is_source=1,
fluid_LADSPA_node_is_sink=2,
fluid_LADSPA_node_is_audio=4,
fluid_LADSPA_node_is_control=8,
fluid_LADSPA_node_is_dummy=16,
fluid_LADSPA_node_is_user_ctrl=32
} fluid_LADSPA_nodeflags;
typedef enum _fluid_ladspa_node_type_t {
FLUID_LADSPA_NODE_AUDIO,
FLUID_LADSPA_NODE_CONTROL,
/* fluid_LADSPA_Node_t
* An internal node of the Fx unit.
* A 'node' is the 'glue' that connects several LADSPA plugins.
* Basically it's a real-valued variable (control node) or a real-valued buffer (audio node).
*/
typedef struct {
LADSPA_Data * buf; /*Either the buffer (Audio node) or a single control value (Control node)*/
char * Name; /* Unique identifier*/
int InCount; /* How many sources feed into this node? (0 or 1) */
int OutCount; /* How many other elements take data out of this node? */
int flags;
} fluid_LADSPA_Node_t;
} fluid_ladspa_node_type_t;
/*
* fluid_LADSPA_Fx_t
* Fx unit using LADSPA.
* This includes a number of LADSPA plugins, their libraries, nodes etc.
* The Fx unit connects its input to Fluidsynth and its output to the soundcard.
*/
typedef struct {
/* LADSPA-plugins are in shared libraries (for example aw.so).
* Pointers to them are stored here. A library is uniquely identified through
* its filename (full path).*/
fluid_synth_t* synth;
typedef struct _fluid_ladspa_lib_t
{
char *filename;
void *dlib;
LADSPA_Descriptor_Function descriptor;
int NumberLibs;
void * ppvPluginLibs[FLUID_LADSPA_MaxLibs];
char * ppvPluginLibNames[FLUID_LADSPA_MaxLibs];
} fluid_ladspa_lib_t;
/*List of plugins (descriptor and instance)
* A LADSPA plugin descriptor points to the code, which is executed, when a plugin is run.
* The plugin instance is given as a parameter, when calling.
*/
int NumberPlugins;
const LADSPA_Descriptor * PluginDescriptorTable[FLUID_LADSPA_MaxPlugins];
LADSPA_Handle * PluginInstanceTable[FLUID_LADSPA_MaxPlugins];
typedef struct _fluid_ladspa_port_state_t
{
int num_inputs;
int num_outputs;
/* List of nodes */
int NumberNodes;
fluid_LADSPA_Node_t * Nodelist[FLUID_LADSPA_MaxNodes];
} fluid_ladspa_port_state_t;
/* List of Command lines
* During the setup phase, each ladspa_add command creates one command sequence. For example:
* ./aw.so alienwah_stereo Input <- Master_L_Synth Output -> Master_R_Synth Parameter <- $42.0
* Those lists are stored in LADSPA_Command_Sequence.
* One command line results in one plugin => size MaxPlugins.
*/
int NumberCommands;
char ** LADSPA_Command_Sequence[FLUID_LADSPA_MaxPlugins];
typedef struct _fluid_ladspa_plugin_t
{
/* plugin instance id unique to the synth */
int id;
/* User control nodes
* A user control node is declared at any time before the ladspa_start command.
* It acts as a constant node, but it has a name and can be changed with the ladspa_nodeset command. */
int NumberUserControlNodes;
char * UserControlNodeNames[FLUID_LADSPA_MaxNodes];
fluid_real_t UserControlNodeValues[FLUID_LADSPA_MaxNodes];
const LADSPA_Descriptor *desc;
LADSPA_Handle *handle;
/* Bypass switch
* If set, the LADSPA Fx unit does not touch the signal.*/
fluid_LADSPA_BypassState Bypass;
volatile int active;
/* Communication between the 'command line' process and the synthesis process.
* A possible conflict situation arises, when fluid_clear is called, and starts to destroy
* the plugins. But the synthesis thread still processes plugins at the same time. The consequences are ugly.
* Therefore ladspa_clear waits for acknowledgement from the synthesis thread, that the Fx unit is bypassed.
* 'cond' is used for the communication, the mutex is required for changing the condition.
*/
pthread_cond_t cond;
pthread_mutex_t mutex;
} fluid_LADSPA_FxUnit_t;
/* Used to keep track of the port connection states */
fluid_ladspa_port_state_t *ports;
/*
* misc
*/
} fluid_ladspa_plugin_t;
/* Purpose:
* Creates a new Fx unit in bypass mode with default settings.
* It is ready for further calls (add, clear, start).
*/
fluid_LADSPA_FxUnit_t* new_fluid_LADSPA_FxUnit(fluid_synth_t* synth);
typedef struct _fluid_ladspa_node_t
{
char *name;
fluid_ladspa_node_type_t type;
LADSPA_Data *buf;
/* Purpose:
* Applies the master gain (from command line option --gain or gain command).
* Processes one block of sound data (generated from the synthesizer) through
* the LADSPA Fx unit.
* Acknowledges a bypass request.
*/
void fluid_LADSPA_run(fluid_LADSPA_FxUnit_t* Fx_unit, fluid_real_t* left_buf[], fluid_real_t* right_buf[], fluid_real_t* fx_left_buf[], fluid_real_t* fx_right_buf[]);
char num_inputs;
char num_outputs;
/* Purpose:
* Returns the node belonging to Name or NULL, if not found
*/
fluid_LADSPA_Node_t* fluid_LADSPA_RetrieveNode(fluid_LADSPA_FxUnit_t* FxUnit, char * Name);
} fluid_ladspa_node_t;
/* Purpose:
* Creates a new node with the given characteristics.
*/
fluid_LADSPA_Node_t* fluid_LADSPA_CreateNode(fluid_LADSPA_FxUnit_t* FxUnit, char * Name, int flags);
typedef struct _fluid_ladspa_fx_t
{
int sample_rate;
/* Purpose:
* - Resets LADSPA Fx unit to bypass.
* - Removes all plugins from the reverb unit.
* - Releases all libraries.
* Note: It would be more efficient to keep the libraries. But then the user would have to restart fluidsynth each time
* a plugin is recompiled.
*/
void fluid_LADSPA_clear(fluid_LADSPA_FxUnit_t* FxUnit);
int audio_groups;
int effects_channels;
int audio_channels;
/* Purpose:
* Frees all memory and shuts down the Fx block.
* The synthesis thread must be stopped, when calling.
*/
void fluid_LADSPA_shutdown(fluid_LADSPA_FxUnit_t* FxUnit);
fluid_ladspa_lib_t *libs[FLUID_LADSPA_MAX_LIBS];
int num_libs;
fluid_ladspa_node_t *nodes[FLUID_LADSPA_MAX_NODES];
int num_nodes;
/* plugins are really plugin instances */
fluid_ladspa_plugin_t *plugins[FLUID_LADSPA_MAX_PLUGINS];
int num_plugins;
/* used to generate the unique plugin ids */
int next_plugin_id;
fluid_rec_mutex_t api_mutex;
volatile int state;
fluid_cond_mutex_t *state_mutex;
fluid_cond_t *state_cond;
} fluid_ladspa_fx_t;
fluid_ladspa_fx_t *new_fluid_ladspa_fx(fluid_synth_t *synth);
void delete_fluid_ladspa_fx(fluid_ladspa_fx_t *fx);
/*
* fluid_handle_LADSPA_XXX
* Those functions are called from fluid_cmd, when a command is entered on the command line.
*/
int fluid_ladspa_is_active(fluid_ladspa_fx_t *fx);
int fluid_ladspa_activate(fluid_ladspa_fx_t *fx, fluid_synth_t *synth);
int fluid_ladspa_deactivate(fluid_ladspa_fx_t *fx, fluid_synth_t *synth);
int fluid_ladspa_reset(fluid_ladspa_fx_t *fx);
/* Purpose:
* - Resets LADSPA Fx unit to bypass.
* - Removes all plugins from the reverb unit.
* - Releases all libraries.
* Note: It would be more efficient to keep the libraries. But then the user would have to restart fluidsynth each time
* a plugin is recompiled.
*/
int fluid_LADSPA_handle_clear(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
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[]);
/* Purpose:
* Loads the plugins added with 'ladspa_add' and then start the Fx unit.
* Internal processes:
* - load the LADSPA plugin libraries
* - instantiate the plugins
* - connect the plugins
* - set the bypass switch to 'not bypassed'
*/
int fluid_LADSPA_handle_start(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
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);
/* Purpose:
* Adds one plugin into the list of the LADSPA Fx unit.
* This is only allowed, while the Fx block is in 'bypass' state (after clear).
*/
int fluid_LADSPA_handle_add(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
int fluid_ladspa_add_audio_node(fluid_ladspa_fx_t *fx, const char *name);
int fluid_ladspa_add_control_node(fluid_ladspa_fx_t *fx, const char *name, fluid_real_t val);
int fluid_ladspa_set_control_node(fluid_ladspa_fx_t *fx, const char *name, fluid_real_t val);
int fluid_ladspa_node_exists(fluid_ladspa_fx_t *fx, const char *name);
/* Purpose:
* Declares a user control node and a value; for further processing in ladspa_start.
*/
int fluid_LADSPA_handle_declnode(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
/* Purpose:
* Assigns a value to the a user control node
*/
int fluid_LADSPA_handle_setnode(fluid_synth_t* synth, int ac, char** av, fluid_ostream_t out);
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);
#endif /* LADSPA */
#endif /* _FLUID_LADSPA_H */
#endif /* _FLUID_LADSPA_H */

View file

@ -121,6 +121,10 @@ fluid_rvoice_event_dispatch(fluid_rvoice_event_t* event)
EVENTFUNC_ALL(fluid_rvoice_mixer_set_chorus_params, fluid_rvoice_mixer_t*);
EVENTFUNC_R4(fluid_rvoice_mixer_set_reverb_params, fluid_rvoice_mixer_t*);
#ifdef LADSPA
EVENTFUNC_0(fluid_rvoice_mixer_deactivate_ladspa, fluid_rvoice_mixer_t*);
#endif
FLUID_LOG(FLUID_ERR, "fluid_rvoice_event_dispatch: Unknown method %p to dispatch!", event->method);
}

View file

@ -81,7 +81,7 @@ struct _fluid_rvoice_mixer_t {
int current_blockcount; /**< Read-only: how many blocks to process this time */
#ifdef LADSPA
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Used by mixer only: Effects unit for LADSPA support. Never created or freed */
fluid_ladspa_fx_t* ladspa_fx; /**< Used by mixer only: Effects unit for LADSPA support. Never created or freed */
#endif
#ifdef ENABLE_MIXER_THREADS
@ -142,7 +142,7 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
#ifdef LADSPA
/* Run the signal through the LADSPA Fx unit */
if (mixer->LADSPA_FxUnit) {
if (mixer->ladspa_fx && mixer->ladspa_fx->state == FLUID_LADSPA_ACTIVE) {
int j;
FLUID_DECLARE_VLA(fluid_real_t*, left_buf, mixer->buffers.buf_count);
FLUID_DECLARE_VLA(fluid_real_t*, right_buf, mixer->buffers.buf_count);
@ -157,8 +157,8 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
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_FxUnit, left_buf, right_buf, fx_left_buf,
fx_right_buf);
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;
@ -642,10 +642,20 @@ void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t* mixer)
#ifdef LADSPA
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
fluid_LADSPA_FxUnit_t* ladspa)
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer, fluid_ladspa_fx_t *ladspa_fx)
{
mixer->LADSPA_FxUnit = ladspa;
mixer->ladspa_fx = ladspa_fx;
}
void fluid_rvoice_mixer_deactivate_ladspa(fluid_rvoice_mixer_t *mixer)
{
if (mixer->ladspa_fx == NULL) return;
mixer->ladspa_fx->state = FLUID_LADSPA_INACTIVE;
/* Signal LADSPA engine that deactivation has been processed */
fluid_cond_mutex_lock(mixer->ladspa_fx->state_mutex);
fluid_cond_broadcast(mixer->ladspa_fx->state_cond);
fluid_cond_mutex_unlock(mixer->ladspa_fx->state_mutex);
}
#endif

View file

@ -69,8 +69,8 @@ void fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t* mixer, int thread_coun
int prio_level);
#ifdef LADSPA
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
fluid_LADSPA_FxUnit_t* ladspa);
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer, fluid_ladspa_fx_t* ladspa_fx);
void fluid_rvoice_mixer_deactivate_ladspa(fluid_rvoice_mixer_t *mixer);
#endif
#endif

View file

@ -711,12 +711,12 @@ new_fluid_synth(fluid_settings_t *settings)
/* Create and initialize the Fx unit.*/
fluid_settings_getint(settings, "synth.ladspa.active", &with_ladspa);
if (with_ladspa) {
synth->LADSPA_FxUnit = new_fluid_LADSPA_FxUnit(synth);
if(synth->LADSPA_FxUnit == NULL) {
synth->ladspa_fx = new_fluid_ladspa_fx(synth);
if(synth->ladspa_fx == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery;
}
fluid_rvoice_mixer_set_ladspa(synth->eventhandler->mixer, synth->LADSPA_FxUnit);
fluid_rvoice_mixer_set_ladspa(synth->eventhandler->mixer, synth->ladspa_fx);
}
#endif
@ -928,10 +928,9 @@ delete_fluid_synth(fluid_synth_t* synth)
fluid_private_free (synth->tuning_iter);
#ifdef LADSPA
/* Release the LADSPA Fx unit */
if (synth->LADSPA_FxUnit) {
fluid_LADSPA_shutdown(synth->LADSPA_FxUnit);
FLUID_FREE(synth->LADSPA_FxUnit);
/* Release the LADSPA effects unit */
if (synth->ladspa_fx) {
delete_fluid_ladspa_fx(synth->ladspa_fx);
}
#endif
@ -5269,3 +5268,24 @@ int fluid_synth_set_channel_type(fluid_synth_t* synth, int chan, int type)
FLUID_API_RETURN(FLUID_OK);
}
#ifdef LADSPA
/**
* Deactivate the LADSPA effects
*
* @param synth FluidSynth instance
* @return FLUID_OK on success, FLUID_FAILED otherwise
*/
int fluid_synth_deactivate_ladspa(fluid_synth_t *synth)
{
int ret;
fluid_return_val_if_fail (synth != NULL, FLUID_FAILED);
fluid_synth_api_enter(synth);
ret = fluid_rvoice_eventhandler_push(synth->eventhandler,
fluid_rvoice_mixer_deactivate_ladspa,
synth->eventhandler->mixer, 0, 0.0f);
FLUID_API_RETURN(ret);
}
#endif /* LADSPA */

View file

@ -100,7 +100,7 @@ typedef struct _fluid_sfont_info_t {
* ticks_since_start - atomic, set by rendering thread only
* cpu_load - atomic, set by rendering thread only
* cur, curmax, dither_index - used by rendering thread only
* LADSPA_FxUnit - same instance copied in rendering thread. Synchronising handled internally (I think...?).
* ladspa_fx - same instance copied in rendering thread. Synchronising handled internally.
*
*/
@ -170,7 +170,7 @@ struct _fluid_synth_t
fluid_mod_t* default_mod; /**< the (dynamic) list of default modulators */
#ifdef LADSPA
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Effects unit for LADSPA support */
fluid_ladspa_fx_t* ladspa_fx; /**< Effects unit for LADSPA support */
#endif
};
@ -199,6 +199,10 @@ int fluid_synth_reset_chorus(fluid_synth_t* synth);
int fluid_synth_set_chorus_full(fluid_synth_t* synth, int set, int nr, double level,
double speed, double depth_ms, int type);
#ifdef LADSPA
int fluid_synth_deactivate_ladspa(fluid_synth_t *synth);
#endif
fluid_sample_timer_t* new_fluid_sample_timer(fluid_synth_t* synth, fluid_timer_callback_t callback, void* data);
int delete_fluid_sample_timer(fluid_synth_t* synth, fluid_sample_timer_t* timer);