summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-12-04 22:37:34 +0100
committerwm4 <wm4@nowhere>2013-12-04 23:13:46 +0100
commitadc843f984ade5603288523245a808a697bea792 (patch)
tree510ad8cacc786b9b7ed2a88ba13ac2f9ec357cdf
parentbcd8afc2ad086b07b1cad8379581bbbae5e67a6e (diff)
downloadmpv-adc843f984ade5603288523245a808a697bea792.tar.bz2
mpv-adc843f984ade5603288523245a808a697bea792.tar.xz
af_ladspa: change options, use option parser
-rw-r--r--DOCS/man/en/af.rst17
-rw-r--r--audio/filter/af_ladspa.c261
2 files changed, 116 insertions, 162 deletions
diff --git a/DOCS/man/en/af.rst b/DOCS/man/en/af.rst
index a0332c1327..4df4b51ae0 100644
--- a/DOCS/man/en/af.rst
+++ b/DOCS/man/en/af.rst
@@ -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
diff --git a/audio/filter/af_ladspa.c b/audio/filter/af_ladspa.c
index 50d0bb5d85..1d7f9c9fa5 100644
--- a/audio/filter/af_ladspa.c
+++ b/audio/filter/af_ladspa.c
@@ -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;
}