1
0
mirror of https://github.com/mpv-player/mpv synced 2025-01-29 11:12:56 +00:00

af_ladspa: change options, use option parser

This commit is contained in:
wm4 2013-12-04 22:37:34 +01:00
parent bcd8afc2ad
commit adc843f984
2 changed files with 116 additions and 162 deletions

View File

@ -471,7 +471,7 @@ Available filters are:
This filter can cause distortion with audio signals that have a very
large dynamic range.
``ladspa=file:label[:controls...]``
``ladspa=file:label:[<control0>,<control1>,...]``
Load a LADSPA (Linux Audio Developer's Simple Plugin API) plugin. This
filter is reentrant, so multiple LADSPA plugins can be used at once.
@ -487,12 +487,21 @@ Available filters are:
one filter, but others contain many of them. Entering 'help' here
will list all available filters within the specified library, which
eliminates the use of 'listplugins' from the LADSPA SDK.
``<controls>``
Controls are zero or more floating point values that determine the
behavior of the loaded plugin (for example delay, threshold or gain).
``[<control0>,<control1>,...]``
Controls are zero or more ``,`` separated floating point values that
determine the behavior of the loaded plugin (for example delay,
threshold or gain).
In verbose mode (add ``-v`` to the mpv command line), all
available controls and their valid ranges are printed. This eliminates
the use of 'analyseplugin' from the LADSPA SDK.
Note that ``,`` is already used by the option parser to separate
filters, so you must quote the list of values with ``[...]`` or
similar.
.. admonition:: Example
``mpv --af=ladspa='/usr/lib/ladspa/delay.so':delay_5s:[0.5,0.2] media.avi``
Does something.
``karaoke``
Simple voice removal filter exploiting the fact that voice is usually

View File

@ -63,6 +63,7 @@ typedef struct af_ladspa_s
char *file;
char *label;
char *controls;
char *myname; /**< It's easy to have a concatenation of file and label */
@ -100,12 +101,18 @@ static int af_ladspa_malloc_failed(char*);
/* ------------------------------------------------------------------------- */
/* Description */
#define OPT_BASE_STRUCT af_ladspa_t
struct af_info af_info_ladspa = {
.info = "LADSPA plugin loader",
.name = "ladspa",
.open = af_open,
.priv_size = sizeof(af_ladspa_t),
.options = (const struct m_option[]) {
OPT_STRING("file", file, 0),
OPT_STRING("label", label, 0),
OPT_STRING("controls", controls, 0),
{0}
},
};
/* ------------------------------------------------------------------------- */
@ -467,13 +474,6 @@ static int af_ladspa_malloc_failed(char *myname) {
* Commands:
* CONTROL_REINIT Sets the af structure with proper values for number
* of channels, rate, format, et cetera.
* CONTROL_COMMAND_LINE Parses the suboptions given to this filter
* through arg. It first parses the filename and
* the label. After that, it loads the filter
* and finds out its proprties. Then in continues
* parsing the controls given on the commandline,
* if any are needed.
*
* \param af Audio filter instance
* \param cmd The command to execute
* \param arg Arguments to the command
@ -483,8 +483,7 @@ static int af_ladspa_malloc_failed(char *myname) {
*/
static int control(struct af_instance *af, int cmd, void *arg) {
af_ladspa_t *setup = (af_ladspa_t*) af->setup;
float val;
af_ladspa_t *setup = (af_ladspa_t*) af->priv;
switch(cmd) {
case AF_CONTROL_REINIT:
@ -498,138 +497,6 @@ static int control(struct af_instance *af, int cmd, void *arg) {
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
return af_test_output(af, (struct mp_audio*)arg);
case AF_CONTROL_COMMAND_LINE: {
char *buf;
char *line = arg;
mp_msg(MSGT_AFILTER, MSGL_V, "%s: parse suboptions\n", setup->myname);
/* suboption parser here!
* format is (ladspa=)file:label:controls....
*/
if (!line) {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("No suboptions specified."));
return AF_ERROR;
}
buf = malloc(strlen(line)+1);
if (!buf) return af_ladspa_malloc_failed(setup->myname);
/* file... */
buf[0] = '\0';
sscanf(line, "%[^:]", buf);
if (buf[0] == '\0') {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("No library file specified."));
free(buf);
return AF_ERROR;
}
line += strlen(buf);
setup->file = strdup(buf);
if (!setup->file) {
free(buf);
return af_ladspa_malloc_failed(setup->myname);
}
mp_msg(MSGT_AFILTER, MSGL_V, "%s: file --> %s\n", setup->myname,
setup->file);
if (*line != '\0') line++; /* read ':' */
/* label... */
buf[0] = '\0';
sscanf(line, "%[^:]", buf);
if (buf[0] == '\0') {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("No filter label specified."));
free(buf);
return AF_ERROR;
}
line += strlen(buf);
setup->label = strdup(buf);
if (!setup->label) {
free(buf);
return af_ladspa_malloc_failed(setup->myname);
}
mp_msg(MSGT_AFILTER, MSGL_V, "%s: label --> %s\n", setup->myname,
setup->label);
/* if (*line != '0') line++; */ /* read ':' */
free(buf); /* no longer needed */
/* set new setup->myname */
free(setup->myname);
setup->myname = calloc(strlen(af_info_ladspa.name)+strlen(setup->file)+
strlen(setup->label)+6, 1);
snprintf(setup->myname, strlen(af_info_ladspa.name)+
strlen(setup->file)+strlen(setup->label)+6, "%s: (%s:%s)",
af_info_ladspa.name, setup->file, setup->label);
/* load plugin :) */
if ( af_ladspa_load_plugin(setup) != AF_OK )
return AF_ERROR;
/* see what inputs, outputs and controls this plugin has */
if ( af_ladspa_parse_plugin(setup) != AF_OK )
return AF_ERROR;
/* ninputcontrols is set by now, read control values from arg */
for (int i = 0; i < setup->ninputcontrols; i++) {
if (!line || *line != ':') {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("Not enough controls specified on the command line."));
return AF_ERROR;
}
line++;
if (sscanf(line, "%f", &val) != 1) {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("Not enough controls specified on the command line."));
return AF_ERROR;
}
setup->inputcontrols[setup->inputcontrolsmap[i]] = val;
line = strchr(line, ':');
}
mp_msg(MSGT_AFILTER, MSGL_V, "%s: input controls: ", setup->myname);
for (int i = 0; i < setup->ninputcontrols; i++) {
mp_msg(MSGT_AFILTER, MSGL_V, "%0.4f ",
setup->inputcontrols[setup->inputcontrolsmap[i]]);
}
mp_msg(MSGT_AFILTER, MSGL_V, "\n");
/* check boundaries of inputcontrols */
mp_msg(MSGT_AFILTER, MSGL_V, "%s: checking boundaries of input controls\n",
setup->myname);
for (int i = 0; i < setup->ninputcontrols; i++) {
int p = setup->inputcontrolsmap[i];
LADSPA_PortRangeHint hint =
setup->plugin_descriptor->PortRangeHints[p];
val = setup->inputcontrols[p];
if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) &&
val < hint.LowerBound) {
mp_tmsg(MSGT_AFILTER, MSGL_ERR, "%s: Input control #%d is below lower boundary of %0.4f.\n",
setup->myname, i, hint.LowerBound);
return AF_ERROR;
}
if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor) &&
val > hint.UpperBound) {
mp_tmsg(MSGT_AFILTER, MSGL_ERR, "%s: Input control #%d is above upper boundary of %0.4f.\n",
setup->myname, i, hint.UpperBound);
return AF_ERROR;
}
}
mp_msg(MSGT_AFILTER, MSGL_V, "%s: all controls have sane values\n",
setup->myname);
/* All is well! */
setup->status = AF_OK;
return AF_OK; }
}
return AF_UNKNOWN;
@ -646,8 +513,8 @@ static int control(struct af_instance *af, int cmd, void *arg) {
*/
static void uninit(struct af_instance *af) {
if (af->setup) {
af_ladspa_t *setup = (af_ladspa_t*) af->setup;
if (af->priv) {
af_ladspa_t *setup = (af_ladspa_t*) af->priv;
const LADSPA_Descriptor *pdes = setup->plugin_descriptor;
if (setup->myname) {
@ -663,8 +530,6 @@ static void uninit(struct af_instance *af) {
free(setup->chhandles);
}
free(setup->file);
free(setup->label);
free(setup->inputcontrolsmap);
free(setup->inputcontrols);
free(setup->outputcontrolsmap);
@ -686,9 +551,6 @@ static void uninit(struct af_instance *af) {
if (setup->libhandle)
dlclose(setup->libhandle);
free(setup);
setup = NULL;
}
}
@ -703,7 +565,7 @@ static void uninit(struct af_instance *af) {
*/
static struct mp_audio* play(struct af_instance *af, struct mp_audio *data) {
af_ladspa_t *setup = af->setup;
af_ladspa_t *setup = af->priv;
const LADSPA_Descriptor *pdes = setup->plugin_descriptor;
float *audio = (float*)data->planes[0];
int nsamples = data->samples*data->nch;
@ -876,20 +738,103 @@ static int af_open(struct af_instance *af) {
af->uninit=uninit;
af->play=play;
af->setup = calloc(1, sizeof(af_ladspa_t));
if (af->setup == NULL) {
return af_ladspa_malloc_failed((char*)af_info_ladspa.name);
}
af_ladspa_t *setup = af->priv;
((af_ladspa_t*)af->setup)->status = AF_ERROR; /* will be set to AF_OK if
setup->status = AF_ERROR; /* will be set to AF_OK if
* all went OK and play()
* should proceed.
*/
((af_ladspa_t*)af->setup)->myname = strdup(af_info_ladspa.name);
if (!((af_ladspa_t*)af->setup)->myname)
setup->myname = strdup(af_info_ladspa.name);
if (!setup->myname)
return af_ladspa_malloc_failed((char*)af_info_ladspa.name);
if (!setup->file || !setup->file[0]) {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("No library file specified."));
uninit(af);
return AF_ERROR;
}
if (!setup->label || !setup->label[0]) {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("No filter label specified."));
uninit(af);
return AF_ERROR;
}
free(setup->myname);
setup->myname = calloc(strlen(af_info_ladspa.name)+strlen(setup->file)+
strlen(setup->label)+6, 1);
snprintf(setup->myname, strlen(af_info_ladspa.name)+
strlen(setup->file)+strlen(setup->label)+6, "%s: (%s:%s)",
af_info_ladspa.name, setup->file, setup->label);
/* load plugin :) */
if ( af_ladspa_load_plugin(setup) != AF_OK )
return AF_ERROR;
/* see what inputs, outputs and controls this plugin has */
if ( af_ladspa_parse_plugin(setup) != AF_OK )
return AF_ERROR;
/* ninputcontrols is set by now, read control values from arg */
float val;
char *line = setup->controls;
for (int i = 0; i < setup->ninputcontrols; i++) {
if (!line || (i != 0 && *line != ',')) {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("Not enough controls specified on the command line."));
return AF_ERROR;
}
if (i != 0)
line++;
if (sscanf(line, "%f", &val) != 1) {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("Not enough controls specified on the command line."));
return AF_ERROR;
}
setup->inputcontrols[setup->inputcontrolsmap[i]] = val;
line = strchr(line, ',');
}
mp_msg(MSGT_AFILTER, MSGL_V, "%s: input controls: ", setup->myname);
for (int i = 0; i < setup->ninputcontrols; i++) {
mp_msg(MSGT_AFILTER, MSGL_V, "%0.4f ",
setup->inputcontrols[setup->inputcontrolsmap[i]]);
}
mp_msg(MSGT_AFILTER, MSGL_V, "\n");
/* check boundaries of inputcontrols */
mp_msg(MSGT_AFILTER, MSGL_V, "%s: checking boundaries of input controls\n",
setup->myname);
for (int i = 0; i < setup->ninputcontrols; i++) {
int p = setup->inputcontrolsmap[i];
LADSPA_PortRangeHint hint =
setup->plugin_descriptor->PortRangeHints[p];
val = setup->inputcontrols[p];
if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) &&
val < hint.LowerBound) {
mp_tmsg(MSGT_AFILTER, MSGL_ERR, "%s: Input control #%d is below lower boundary of %0.4f.\n",
setup->myname, i, hint.LowerBound);
return AF_ERROR;
}
if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor) &&
val > hint.UpperBound) {
mp_tmsg(MSGT_AFILTER, MSGL_ERR, "%s: Input control #%d is above upper boundary of %0.4f.\n",
setup->myname, i, hint.UpperBound);
return AF_ERROR;
}
}
mp_msg(MSGT_AFILTER, MSGL_V, "%s: all controls have sane values\n",
setup->myname);
/* All is well! */
setup->status = AF_OK;
return AF_OK;
}