Merge pull request #235 from mawe42/ladspa-cleanup

LADSPA effect unit refactor
This commit is contained in:
Tom M 2017-10-21 17:36:04 +02:00 committed by GitHub
commit 0600ba7c68
10 changed files with 1784 additions and 1288 deletions

64
doc/ladspa.md Normal file
View file

@ -0,0 +1,64 @@
# FluidSynth LADSPA Interface
The [LADSPA](http://ladspa.org/) (Linux Audio Developer's Simple Plugin API)
binding can be used to route the FluidSynth audio output through any number
of LADSPA plugins. As the name implies, it is only available on Linux.
## Configuration
To configure and compile FluidSynth with LADSPA support, make sure you have
the LADSPA SDK (basically the ladspa.h header file) installed. Then enable
LADSPA when calling cmake:
cmake -Denable-ladspa=1 <path-to-source>
You should see `LADSPA support: yes` in the cmake output.
To enable the LADSPA engine, use the `synth.ladspa.active` setting when
starting FluidSynth:
fluidsynth -o synth.ladspa.active=1 ...
# Signal Flow
The LADSPA effects unit runs immediately after the internal reverb and chorus
effects have been processed. When no plugins have been configured, the
effects unit is dormant and uses no additional system resources.
When at least one plugin is configured and the engine is activated, the
rendered audio is passed into the LADSPA effects unit, each plugin is
run in the order that they were created and the resulting audio is
passed back into FluidSynth (and from there to the sound card or other
output).
# Loading and Connecting Plugins
Currently the only way to configure the effects unit is via the FluidSynth
shell or via a config file.
## Example Setups
All examples assume that your `LADSPA_PATH` environment variable points
to the directory containing the plugin libraries (e.g. /usr/lib/ladspa).
### Single Plugin
The following loads the delay.so plugin library from the LADSPA SDK and
instantiates the `delay_5s` plugin from that library. It connects the
main left channel output from FluidSynth with the plugin input, the
main left channel input to FluidSynth with the plugin output. It also
sets the two control ports of the plugin to example values and starts
the engine.
ladspa_plugin delay.so delay_5s
ladspa_port Input < in1_L
ladspa_port Output > out1_L
ladspa_port Delay = 1.0
ladspa_port Dry/Wet = 0.5
ladspa_start
The audible effect should be an untouched right channel and a slightly
lower volume on the left with a delay effect of 1 second on top.

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,266 @@ 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) != 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) != 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);
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 +2214,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,133 @@
/* 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>
/***************************************************************
*
* 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)
#define FLUID_LADSPA_RUNNING (2)
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 effects unit */
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;
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
{
unsigned long 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;
int state;
int pending_deactivation;
fluid_cond_mutex_t *run_finished_mutex;
fluid_cond_t *run_finished_cond;
} 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);
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);
/*
* 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);
int fluid_ladspa_deactivate(fluid_ladspa_fx_t *fx);
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

@ -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;
@ -522,6 +522,12 @@ fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samp
fluid_revmodel_samplerate_change(mixer->fx.reverb, samplerate);
for (i=0; i < mixer->active_voices; i++)
fluid_rvoice_set_output_rate(mixer->rvoices[i], samplerate);
#if LADSPA
if (mixer->ladspa_fx != NULL)
{
fluid_ladspa_set_sample_rate(mixer->ladspa_fx, samplerate);
}
#endif
}
@ -642,10 +648,9 @@ 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;
}
#endif

View file

@ -69,8 +69,7 @@ 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);
#endif
#endif

View file

@ -555,7 +555,9 @@ new_fluid_synth(fluid_settings_t *settings)
fluid_sfloader_t* loader;
double gain;
int i, nbuf;
#ifdef LADSPA
int with_ladspa = 0;
#endif
/* initialize all the conversion tables and other stuff */
if (fluid_synth_initialized == 0)
@ -711,12 +713,13 @@ 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->sample_rate, synth->audio_groups,
synth->effects_channels, synth->audio_channels);
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 +931,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
@ -2344,7 +2346,7 @@ fluid_synth_update_presets(fluid_synth_t* synth)
}
}
/* Handler for synth.gain setting. */
/* Handler for synth.sample-rate setting. */
static int
fluid_synth_update_sample_rate(fluid_synth_t* synth, char* name, double value)
{
@ -5263,4 +5265,3 @@ int fluid_synth_set_channel_type(fluid_synth_t* synth, int chan, int type)
FLUID_API_RETURN(FLUID_OK);
}

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
};

View file

@ -267,6 +267,12 @@ do { strncpy(_dst,_src,_n); \
#define FLUID_STRCASECMP strcasecmp
#endif
#if defined(WIN32) && !defined(MINGW32)
#define FLUID_STRNCASECMP _strincmp
#else
#define FLUID_STRNCASECMP strncasecmp
#endif
#define fluid_clip(_val, _min, _max) \
{ (_val) = ((_val) < (_min))? (_min) : (((_val) > (_max))? (_max) : (_val)); }