mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-12-02 17:12:15 +00:00
Merge pull request #235 from mawe42/ladspa-cleanup
LADSPA effect unit refactor
This commit is contained in:
commit
0600ba7c68
10 changed files with 1784 additions and 1288 deletions
64
doc/ladspa.md
Normal file
64
doc/ladspa.md
Normal 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.
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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)); }
|
||||
|
|
Loading…
Reference in a new issue