📄 af_ladspa.c
字号:
/* ------------------------------------------------------------------------- *//* * af_ladspa.c, LADSPA plugin loader * * Written by Ivo van Poorten <ivop@euronet.nl> * Copyright (C) 2004, 2005 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * Changelog * * 2004-12-23 Added to CVS * 2004-12-22 Cleaned up cosmetics * Made conversion loops in play() more cache-friendly * 2004-12-20 Fixed bug for stereo effect on mono signal * (trivial >1 to >=1 change; would segfault otherwise :-) ) * Removed trailing whitespace and fixed warn/err messages * Have CONTROL_REINIT return a proper value * 2004-12-13 More Doxygen comments * 2004-12-12 Made af_ladspa optional (updated configure, af.c, etc.) * 2004-12-11 Added deactivate and cleanup to uninit. * Finished Doxygen comments. * Moved translatable messages to help_mp-en.h * 2004-12-10 Added ranges to list of controls for ease of use. * Fixed sig11 bug. Implemented (dummy) outputcontrols. Some * perfectly normal audio processing filters also have output * controls. * 2004-12-08 Added support for generators (no input, one output) * Added support for stereo effects * Added LADSPA_PATH support! * 2004-12-07 Fixed changing buffersize. Now it's really working, also in * real-time. * 2004-12-06 First working version, mono-effects (1 input --> 1 output) only * 2004-12-05 Started, Loading of plugin/label, Check inputs/outputs/controls * Due to lack of documentation, I studied the ladspa_sdk source * code and the loader code of Audacity (by Dominic Mazzoni). So, * certain similarities in (small) pieces of code are not * coincidental :-) No C&P jobs though! * *//* ------------------------------------------------------------------------- *//* Global Includes */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <inttypes.h>#include <math.h>#include <limits.h>#include <dlfcn.h>#include <ladspa.h>/* ------------------------------------------------------------------------- *//* Local Includes */#include "af.h"#include "../help_mp.h"/* ------------------------------------------------------------------------- *//* Filter specific data */typedef struct af_ladspa_s{ int status; /**< Status of the filter. * Either AF_OK or AF_ERROR * Because MPlayer re-inits audio filters that * _clearly_ returned AF_ERROR anyway, I use this * in play() to skip the processing and return * the data unchanged. */ int activated; /**< 0 or 1. Activate LADSPA filters only once, even * if the buffers get resized, to avoid a stuttering * filter. */ char *file; char *label; char *myname; /**< It's easy to have a concatenation of file and label */ void *libhandle; const LADSPA_Descriptor *plugin_descriptor; int nports; int ninputs; int *inputs; int noutputs; int *outputs; int ninputcontrols; int *inputcontrolsmap; /**< Map input port number [0-] to actual port */ float *inputcontrols; int noutputcontrols; int *outputcontrolsmap; float *outputcontrols; int nch; /**< number of channels */ int bufsize; float **inbufs; float **outbufs; LADSPA_Handle *chhandles;} af_ladspa_t;/* ------------------------------------------------------------------------- */static int open(af_instance_t *af);static int af_ladspa_malloc_failed(char*);/* ------------------------------------------------------------------------- *//* Description */af_info_t af_info_ladspa = { "LADSPA plugin loader", "ladspa", "Ivo van Poorten", "", AF_FLAGS_REENTRANT, open};/* ------------------------------------------------------------------------- *//* By lack of a better word (in my vocabulary) this is called 'parse'. * Feel free to suggest an alternative. *//** \brief Check for inputs, outputs and controls of a given filter. * * This function counts and checks all input, output and control ports * of the filter that was loaded. If it turns out to be a valid * filter for MPlayer use, it prints out a list of all controls and * the corresponding range of its value at message level MSGL_V. * * \param setup Current setup of the filter. Must have its * plugin_descriptor set! * * \return Returns AF_OK if it has a valid input/output/controls * configuration. Else, it returns AF_ERROR. */static int af_ladspa_parse_plugin(af_ladspa_t *setup) { int p, i; const LADSPA_Descriptor *pdes = setup->plugin_descriptor; LADSPA_PortDescriptor d; LADSPA_PortRangeHint hint; if (!setup->libhandle) return AF_ERROR; /* only call parse after a succesful load */ if (!setup->plugin_descriptor) return AF_ERROR; /* same as above */ /* let's do it */ setup->nports = pdes->PortCount; /* allocate memory for all inputs/outputs/controls */ setup->inputs = calloc(setup->nports, sizeof(int)); if (!setup->inputs) return af_ladspa_malloc_failed(setup->myname); setup->outputs = calloc(setup->nports, sizeof(int)); if (!setup->outputs) return af_ladspa_malloc_failed(setup->myname); setup->inputcontrolsmap = calloc(setup->nports, sizeof(int)); if (!setup->inputcontrolsmap) return af_ladspa_malloc_failed(setup->myname); setup->inputcontrols = calloc(setup->nports, sizeof(float)); if (!setup->inputcontrols) return af_ladspa_malloc_failed(setup->myname); setup->outputcontrolsmap = calloc(setup->nports, sizeof(int)); if (!setup->outputcontrolsmap) return af_ladspa_malloc_failed(setup->myname); setup->outputcontrols = calloc(setup->nports, sizeof(float)); if (!setup->outputcontrols) return af_ladspa_malloc_failed(setup->myname); /* set counts to zero */ setup->ninputs = 0; setup->noutputs = 0; setup->ninputcontrols = 0; setup->noutputcontrols = 0; /* check all ports, see what type it is and set variables according to * what we have found */ for (p=0; p<setup->nports; p++) { d = pdes->PortDescriptors[p]; if (LADSPA_IS_PORT_AUDIO(d)) { if (LADSPA_IS_PORT_INPUT(d)) { setup->inputs[setup->ninputs] = p; setup->ninputs++; } else if (LADSPA_IS_PORT_OUTPUT(d)) { setup->outputs[setup->noutputs] = p; setup->noutputs++; } } if (LADSPA_IS_PORT_CONTROL(d)) { if (LADSPA_IS_PORT_INPUT(d)) { setup->inputcontrolsmap[setup->ninputcontrols] = p; setup->ninputcontrols++; /* set control to zero. set values after reading the rest * of the suboptions and check LADSPA_?_HINT's later. */ setup->inputcontrols[p] = 0.0f; } else if (LADSPA_IS_PORT_OUTPUT(d)) { /* read and handle these too, otherwise filters that have them * will sig11 */ setup->outputcontrolsmap[setup->noutputcontrols]=p; setup->noutputcontrols++; setup->outputcontrols[p] = 0.0f; } } } if (setup->ninputs == 0) { af_msg(AF_MSG_WARN, "%s: %s\n", setup->myname, MSGTR_AF_LADSPA_WarnNoInputs); } else if (setup->ninputs == 1) { af_msg(AF_MSG_VERBOSE, "%s: this is a mono effect\n", setup->myname); } else if (setup->ninputs == 2) { af_msg(AF_MSG_VERBOSE, "%s: this is a stereo effect\n", setup->myname); } if (setup->ninputs > 2) { af_msg(AF_MSG_ERROR, "%s: %s\n", setup->myname, MSGTR_AF_LADSPA_ErrMultiChannel); return AF_ERROR; } if (setup->noutputs == 0) { af_msg(AF_MSG_ERROR, "%s: %s\n", setup->myname, MSGTR_AF_LADSPA_ErrNoOutputs); return AF_ERROR; } if (setup->noutputs != setup->ninputs ) { af_msg(AF_MSG_ERROR, "%s: %s\n", setup->myname, MSGTR_AF_LADSPA_ErrInOutDiff); return AF_ERROR; } af_msg(AF_MSG_VERBOSE, "%s: this plugin has %d input control(s)\n", setup->myname, setup->ninputcontrols); /* Print list of controls and its range of values it accepts */ for (i=0; i<setup->ninputcontrols; i++) { p = setup->inputcontrolsmap[i]; hint = pdes->PortRangeHints[p]; af_msg(AF_MSG_VERBOSE, " --- %d %s [", i, pdes->PortNames[p]); if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) { af_msg(AF_MSG_VERBOSE, "%0.2f , ", hint.LowerBound); } else { af_msg(AF_MSG_VERBOSE, "... , "); } if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) { af_msg(AF_MSG_VERBOSE, "%0.2f]\n", hint.UpperBound); } else { af_msg(AF_MSG_VERBOSE, "...]\n"); } } return AF_OK;}/* ------------------------------------------------------------------------- *//* This function might "slightly" look like dlopenLADSPA in the LADSPA SDK :-) * But, I changed a few things, because imho it was broken. It did not support * relative paths, only absolute paths that start with a / * I think ../../some/dir/foobar.so is just as valid. And if one wants to call * his library '...somename...so' he's crazy, but it should be allowed. * So, search the path first, try plain *filename later. * Also, try adding .so first! I like the recursion the SDK did, but it's * better the other way around. -af ladspa=cmt:amp_stereo:0.5 is easier to type * than -af ladspa=cmt.so:amp_stereo:0.5 :-)) *//** \brief dlopen() wrapper * * This is a wrapper around dlopen(). It tries various variations of the * filename (with or without the addition of the .so extension) in various * directories specified by the LADSPA_PATH environment variable. If all fails * it tries the filename directly as an absolute path to the library. * * \param filename filename of the library to load. * \param flag see dlopen(3) for a description of the flags. * * \return returns a pointer to the loaded library on success, or * NULL if it fails to load. */static void* mydlopen(const char *filename, int flag) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -