Add mod_ladspa (Audio plugin framework for linux) http://http://www.ladspa.org/ try it with autotalent http://web.mit.edu/tbaran/www/autotalent.html
This commit is contained in:
parent
c6f6732231
commit
2d3d8f8d34
|
@ -0,0 +1,73 @@
|
|||
<include>
|
||||
|
||||
<X-PRE-PROCESS cmd="set" data="AT_EPENT1=0 0 0 -1 -1 0 -1 0 -1 -1 0 -1"/>
|
||||
<X-PRE-PROCESS cmd="set" data="AT_EPENT2=1 1 1 -1 -1 1 -1 1 -1 -1 1 -1"/>
|
||||
<X-PRE-PROCESS cmd="set" data="AT_CPENT1=0 -1 -1 0 -1 0 0 0 -1 -1 0 -1"/>
|
||||
<X-PRE-PROCESS cmd="set" data="AT_CPENT2=1 -1 -1 1 -1 1 1 1 -1 -1 1 -1"/>
|
||||
<X-PRE-PROCESS cmd="set" data="AT_CMAJ1=0 -1 0 0 -1 0 -1 0 0 -1 0 -1"/>
|
||||
<X-PRE-PROCESS cmd="set" data="AT_CMAJ2=1 -1 1 1 -1 1 -1 1 1 -1 1 -1"/>
|
||||
<X-PRE-PROCESS cmd="set" data="AT_BBLUES=1 -1 1 -1 -1 1 -1 1 1 1 -1 -1"/>
|
||||
<X-PRE-PROCESS cmd="set" data="ATGPENT2=-1 1 -1 1 -1 1 -1 -1 1 -1 1 -1"/>
|
||||
|
||||
<extension name="101">
|
||||
<condition field="destination_number" expression="^101$">
|
||||
<!-- AUTOTALENT DEFAULTS
|
||||
<action application="set" data="AT_TUNE=440"/>
|
||||
<action application="set" data="AT_FIXED=0"/>
|
||||
<action application="set" data="AT_PULL=0"/>
|
||||
<action application="set" data="AT_A=0"/>
|
||||
<action application="set" data="AT_Bb=-1"/>
|
||||
<action application="set" data="AT_B=0"/>
|
||||
<action application="set" data="AT_C=0"/>
|
||||
<action application="set" data="AT_Db=-1"/>
|
||||
<action application="set" data="AT_D=0"/>
|
||||
<action application="set" data="AT_Eb=-1"/>
|
||||
<action application="set" data="AT_E=0"/>
|
||||
<action application="set" data="AT_F=0"/>
|
||||
<action application="set" data="AT_Gb=-1"/>
|
||||
<action application="set" data="AT_G=0"/>
|
||||
<action application="set" data="AT_Ab=-1"/>
|
||||
<action application="set" data="AT_AMOUNT=1"/>
|
||||
<action application="set" data="AT_SMOOTH=0"/>
|
||||
<action application="set" data="AT_SHIFT=0"/>
|
||||
<action application="set" data="AT_OUTSCALE=0"/>
|
||||
<action application="set" data="AT_LFODEPTH=0"/>
|
||||
<action application="set" data="AT_LFORATE=5"/>
|
||||
<action application="set" data="AT_LFOSHAPE=0"/>
|
||||
<action application="set" data="AT_LFOSYMM=0"/>
|
||||
<action application="set" data="AT_LFOQUANT=0"/>
|
||||
<action application="set" data="AT_FCORR=0"/>
|
||||
<action application="set" data="AT_FWARP=0"/>
|
||||
<action application="set" data="AT_MIX=1"/>
|
||||
-->
|
||||
|
||||
|
||||
<action application="set" data="AT_TUNE=440"/>
|
||||
<action application="set" data="AT_FIXED=0"/>
|
||||
<action application="set" data="AT_PULL=0"/>
|
||||
|
||||
<action application="set" data="AT_AMOUNT=1"/>
|
||||
<action application="set" data="AT_SMOOTH=0"/>
|
||||
<action application="set" data="AT_SHIFT=1"/>
|
||||
<action application="set" data="AT_OUTSCALE=0"/>
|
||||
<action application="set" data="AT_LFODEPTH=0"/>
|
||||
<action application="set" data="AT_LFORATE=5"/>
|
||||
<action application="set" data="AT_LFOSHAPE=0"/>
|
||||
<action application="set" data="AT_LFOSYMM=0"/>
|
||||
<action application="set" data="AT_LFOQUANT=0"/>
|
||||
<action application="set" data="AT_FCORR=0"/>
|
||||
<action application="set" data="AT_FWARP=0"/>
|
||||
<action application="set" data="AT_MIX=1"/>
|
||||
|
||||
<!-- you have to download the ladspa package and the desired plugins from their desired site -->
|
||||
|
||||
<action application="set" data="ladspa_params=${AT_TUNE} ${AT_FIXED} ${AT_PULL} ${AT_EPENT2} ${AT_AMOUNT} ${AT_SMOOTH} ${AT_SHIFT} ${AT_OUTSCALE} ${AT_LFODEPTH} ${AT_LFORATE} ${AT_LFOSHAPE} ${AT_LFOSYMM} ${AT_LFOQUANT} ${AT_FCORR} ${AT_FWARP} ${AT_MIX}"/>
|
||||
|
||||
<action application="ladspa_run" data="r|autotalent||${ladspa_params}"/>
|
||||
<action application="ladspa_run" data="r|tap_chorusflanger||"/>
|
||||
<action application="ladspa_run" data="r|phasers_1217.so|autoPhaser|"/>
|
||||
<action application="bridge" data="sofia/internal/888@conference.freeswitch.org"/>
|
||||
</condition>
|
||||
</extension>
|
||||
|
||||
</include>
|
|
@ -0,0 +1,5 @@
|
|||
BASE=../../../..
|
||||
|
||||
LOCAL_OBJS += load.o
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/* load.c
|
||||
|
||||
Free software by Richard W.E. Furse. Do with as you will. No
|
||||
warranty. */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "ladspa.h"
|
||||
#include "utils.h"
|
||||
#include "inttypes.h"
|
||||
#include "switch.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
/* This function provides a wrapping of dlopen(). When the filename is
|
||||
not an absolute path (i.e. does not begin with / character), this
|
||||
routine will search the LADSPA_PATH for the file. */
|
||||
static void *dlopenLADSPA(const char *pcFilename, int iFlag)
|
||||
{
|
||||
|
||||
char *pcBuffer;
|
||||
const char *pcEnd;
|
||||
const char *pcLADSPAPath;
|
||||
const char *pcStart;
|
||||
int iEndsInSO;
|
||||
int iNeedSlash;
|
||||
size_t iFilenameLength;
|
||||
void *pvResult;
|
||||
|
||||
iFilenameLength = strlen(pcFilename);
|
||||
pvResult = NULL;
|
||||
|
||||
if (pcFilename[0] == '/') {
|
||||
|
||||
/* The filename is absolute. Assume the user knows what he/she is
|
||||
doing and simply dlopen() it. */
|
||||
|
||||
pvResult = dlopen(pcFilename, iFlag);
|
||||
if (pvResult != NULL)
|
||||
return pvResult;
|
||||
|
||||
} else {
|
||||
|
||||
/* If the filename is not absolute then we wish to check along the
|
||||
LADSPA_PATH path to see if we can find the file there. We do
|
||||
NOT call dlopen() directly as this would find plugins on the
|
||||
LD_LIBRARY_PATH, whereas the LADSPA_PATH is the correct place
|
||||
to search. */
|
||||
|
||||
pcLADSPAPath = getenv("LADSPA_PATH");
|
||||
|
||||
if (pcLADSPAPath) {
|
||||
|
||||
pcStart = pcLADSPAPath;
|
||||
while (*pcStart != '\0') {
|
||||
pcEnd = pcStart;
|
||||
while (*pcEnd != ':' && *pcEnd != '\0')
|
||||
pcEnd++;
|
||||
|
||||
pcBuffer = malloc(iFilenameLength + 2 + (pcEnd - pcStart));
|
||||
if (pcEnd > pcStart)
|
||||
strncpy(pcBuffer, pcStart, pcEnd - pcStart);
|
||||
iNeedSlash = 0;
|
||||
if (pcEnd > pcStart)
|
||||
if (*(pcEnd - 1) != '/') {
|
||||
iNeedSlash = 1;
|
||||
pcBuffer[pcEnd - pcStart] = '/';
|
||||
}
|
||||
strcpy(pcBuffer + iNeedSlash + (pcEnd - pcStart), pcFilename);
|
||||
|
||||
pvResult = dlopen(pcBuffer, iFlag);
|
||||
|
||||
free(pcBuffer);
|
||||
if (pvResult != NULL)
|
||||
return pvResult;
|
||||
|
||||
pcStart = pcEnd;
|
||||
if (*pcStart == ':')
|
||||
pcStart++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* As a last ditch effort, check if filename does not end with
|
||||
".so". In this case, add this suffix and recurse. */
|
||||
iEndsInSO = 0;
|
||||
if (iFilenameLength > 3)
|
||||
iEndsInSO = (strcmp(pcFilename + iFilenameLength - 3, ".so") == 0);
|
||||
if (!iEndsInSO) {
|
||||
pcBuffer = malloc(iFilenameLength + 4);
|
||||
strcpy(pcBuffer, pcFilename);
|
||||
strcat(pcBuffer, ".so");
|
||||
pvResult = dlopenLADSPA(pcBuffer, iFlag);
|
||||
free(pcBuffer);
|
||||
}
|
||||
|
||||
if (pvResult != NULL)
|
||||
return pvResult;
|
||||
|
||||
/* If nothing has worked, then at least we can make sure we set the
|
||||
correct error message - and this should correspond to a call to
|
||||
dlopen() with the actual filename requested. The dlopen() manual
|
||||
page does not specify whether the first or last error message
|
||||
will be kept when multiple calls are made to dlopen(). We've
|
||||
covered the former case - now we can handle the latter by calling
|
||||
dlopen() again here. */
|
||||
return dlopen(pcFilename, iFlag);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void *loadLADSPAPluginLibrary(const char *pcPluginFilename)
|
||||
{
|
||||
|
||||
void *pvPluginHandle;
|
||||
|
||||
pvPluginHandle = dlopenLADSPA(pcPluginFilename, RTLD_NOW);
|
||||
if (!pvPluginHandle) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load plugin \"%s\": %s\n", pcPluginFilename, dlerror());
|
||||
}
|
||||
|
||||
return pvPluginHandle;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void unloadLADSPAPluginLibrary(void *pvLADSPAPluginLibrary)
|
||||
{
|
||||
dlclose(pvLADSPAPluginLibrary);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const LADSPA_Descriptor *findLADSPAPluginDescriptor(void *pvLADSPAPluginLibrary, const char *pcPluginLibraryFilename, const char *pcPluginLabel)
|
||||
{
|
||||
|
||||
const LADSPA_Descriptor *psDescriptor;
|
||||
LADSPA_Descriptor_Function pfDescriptorFunction;
|
||||
unsigned long lPluginIndex;
|
||||
|
||||
dlerror();
|
||||
pfDescriptorFunction = (LADSPA_Descriptor_Function) (intptr_t)dlsym(pvLADSPAPluginLibrary, "ladspa_descriptor");
|
||||
if (!pfDescriptorFunction) {
|
||||
const char *pcError = dlerror();
|
||||
if (pcError) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Unable to find ladspa_descriptor() function in plugin "
|
||||
"library file \"%s\": %s.\n" "Are you sure this is a LADSPA plugin file?\n", pcPluginLibraryFilename, pcError);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (lPluginIndex = 0;; lPluginIndex++) {
|
||||
psDescriptor = pfDescriptorFunction(lPluginIndex);
|
||||
if (psDescriptor == NULL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Unable to find label \"%s\" in plugin library file \"%s\".\n", pcPluginLabel, pcPluginLibraryFilename);
|
||||
return NULL;
|
||||
}
|
||||
if (strcmp(psDescriptor->Label, pcPluginLabel) == 0)
|
||||
return psDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* EOF */
|
|
@ -0,0 +1,579 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* mod_ladspa.c -- LADSPA
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
#include "ladspa.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* Prototypes */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown);
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_ladspa_runtime);
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load);
|
||||
|
||||
/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
|
||||
* Defines a switch_loadable_module_function_table_t and a static const char[] modname
|
||||
*/
|
||||
SWITCH_MODULE_DEFINITION(mod_ladspa, mod_ladspa_load, mod_ladspa_shutdown, NULL);
|
||||
|
||||
#define MAX_INDEX 256
|
||||
|
||||
typedef struct {
|
||||
switch_core_session_t *session;
|
||||
char *plugin_name;
|
||||
char *label_name;
|
||||
void *library_handle;
|
||||
const LADSPA_Descriptor *ldesc;
|
||||
LADSPA_Handle handle;
|
||||
LADSPA_Data config[MAX_INDEX];
|
||||
uint8_t has_config[MAX_INDEX];
|
||||
int skip;
|
||||
LADSPA_Data in_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
||||
LADSPA_Data out_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
||||
LADSPA_Data out_ports[MAX_INDEX];
|
||||
} switch_ladspa_t;
|
||||
|
||||
|
||||
|
||||
int check_range(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data val)
|
||||
{
|
||||
if (ldesc->PortRangeHints[i].LowerBound && ldesc->PortRangeHints[i].UpperBound &&
|
||||
(val < ldesc->PortRangeHints[i].LowerBound || val > ldesc->PortRangeHints[i].UpperBound)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Param %f out of bounds %f-%f\n",
|
||||
val, ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int find_default(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data *ptr)
|
||||
|
||||
{
|
||||
LADSPA_Data dftval = 0;
|
||||
int fail = 0;
|
||||
|
||||
LADSPA_PortRangeHintDescriptor port_hint = ldesc->PortRangeHints[i].HintDescriptor;
|
||||
|
||||
switch (port_hint & LADSPA_HINT_DEFAULT_MASK) {
|
||||
case LADSPA_HINT_DEFAULT_NONE:
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_MINIMUM:
|
||||
dftval = ldesc->PortRangeHints[i].LowerBound;
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_LOW:
|
||||
if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
|
||||
dftval = exp(log(ldesc->PortRangeHints[i].LowerBound)
|
||||
* 0.75 + log(ldesc->PortRangeHints[i].UpperBound)
|
||||
* 0.25);
|
||||
} else {
|
||||
dftval = (ldesc->PortRangeHints[i].LowerBound * 0.75 + ldesc->PortRangeHints[i].UpperBound * 0.25);
|
||||
}
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_MIDDLE:
|
||||
if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
|
||||
dftval = sqrt(ldesc->PortRangeHints[i].LowerBound * ldesc->PortRangeHints[i].UpperBound);
|
||||
} else {
|
||||
dftval = 0.5 * (ldesc->PortRangeHints[i].LowerBound + ldesc->PortRangeHints[i].UpperBound);
|
||||
}
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_HIGH:
|
||||
if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
|
||||
dftval = exp(log(ldesc->PortRangeHints[i].LowerBound)
|
||||
* 0.25 + log(ldesc->PortRangeHints[i].UpperBound)
|
||||
* 0.75);
|
||||
} else {
|
||||
dftval = (ldesc->PortRangeHints[i].LowerBound * 0.25 + ldesc->PortRangeHints[i].UpperBound * 0.75);
|
||||
}
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_MAXIMUM:
|
||||
dftval = ldesc->PortRangeHints[i].UpperBound;
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_0:
|
||||
dftval = 0;
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_1:
|
||||
dftval = 1;
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_100:
|
||||
dftval = 100;
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_440:
|
||||
dftval = 440;
|
||||
break;
|
||||
default:
|
||||
fail = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fail) {
|
||||
*ptr = dftval;
|
||||
}
|
||||
|
||||
return !fail;
|
||||
}
|
||||
|
||||
static void dump_info(const LADSPA_Descriptor *ldesc)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Name: \"%s\"\n", ldesc->Name);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Label: \"%s\"\n", ldesc->Label);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Unique ID: %lu\n", ldesc->UniqueID);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Maker: \"%s\"\n", ldesc->Maker);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Copyright: \"%s\"\n", ldesc->Copyright);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Must Run Real-Time: ");
|
||||
if (LADSPA_IS_REALTIME(ldesc->Properties))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has activate() Function: ");
|
||||
if (ldesc->activate != NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has deactivate() Function: ");
|
||||
if (ldesc->deactivate != NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has run_adding() Function: ");
|
||||
if (ldesc->run_adding != NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
|
||||
|
||||
if (ldesc->instantiate == NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO INSTANTIATE FUNCTION.\n");
|
||||
if (ldesc->connect_port == NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CONNECT_PORT FUNCTION.\n");
|
||||
if (ldesc->run == NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO RUN FUNCTION.\n");
|
||||
if (ldesc->run_adding != NULL && ldesc->set_run_adding_gain == NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS RUN_ADDING FUNCTION BUT " "NOT SET_RUN_ADDING_GAIN.\n");
|
||||
if (ldesc->run_adding == NULL && ldesc->set_run_adding_gain != NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS SET_RUN_ADDING_GAIN FUNCTION BUT " "NOT RUN_ADDING.\n");
|
||||
if (ldesc->cleanup == NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CLEANUP FUNCTION.\n");
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Environment: ");
|
||||
if (LADSPA_IS_HARD_RT_CAPABLE(ldesc->Properties))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal or Hard Real-Time\n");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal\n");
|
||||
|
||||
if (LADSPA_IS_INPLACE_BROKEN(ldesc->Properties))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "This plugin cannot use in-place processing. " "It will not work with all hosts.\n");
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Ports:");
|
||||
|
||||
if (ldesc->PortCount == 0)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\tERROR: PLUGIN HAS NO PORTS.\n");
|
||||
|
||||
for (i = 0; i < ldesc->PortCount; i++) {
|
||||
LADSPA_Data dft = 0.0f;
|
||||
int found = 0;
|
||||
|
||||
if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) {
|
||||
found = find_default(ldesc, i, &dft);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n \"%s\" ", ldesc->PortNames[i]);
|
||||
|
||||
if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i])
|
||||
&& LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: INPUT AND OUTPUT");
|
||||
else if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "input");
|
||||
else if (LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "output");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: NEITHER INPUT NOR OUTPUT");
|
||||
|
||||
if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])
|
||||
&& LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: CONTROL AND AUDIO");
|
||||
else if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", control");
|
||||
else if (LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", audio");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: NEITHER CONTROL NOR AUDIO");
|
||||
|
||||
if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) {
|
||||
if (found) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n RANGE: %f-%f DEFAULT: %f\n",
|
||||
ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound, dft);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n RANGE: %f-%f DEFAULT: none.\n",
|
||||
ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static switch_bool_t ladspa_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
|
||||
{
|
||||
switch_ladspa_t *pvt = (switch_ladspa_t *) user_data;
|
||||
//switch_frame_t *frame = NULL;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(pvt->session);
|
||||
|
||||
switch (type) {
|
||||
case SWITCH_ABC_TYPE_INIT:
|
||||
{
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
LADSPA_PortDescriptor port_desc;
|
||||
int i = 0, j = 0, k = 0;
|
||||
|
||||
switch_core_session_get_read_impl(pvt->session, &read_impl);
|
||||
|
||||
if (!(pvt->library_handle = loadLADSPAPluginLibrary(pvt->plugin_name))) {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
if (!(pvt->ldesc = findLADSPAPluginDescriptor(pvt->library_handle, pvt->plugin_name, pvt->label_name))) {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
|
||||
pvt->handle = pvt->ldesc->instantiate(pvt->ldesc, read_impl.actual_samples_per_second);
|
||||
|
||||
dump_info(pvt->ldesc);
|
||||
|
||||
|
||||
for (i = 0; i < pvt->ldesc->PortCount; i++) {
|
||||
port_desc = pvt->ldesc->PortDescriptors[i];
|
||||
|
||||
if (LADSPA_IS_PORT_CONTROL(port_desc) && LADSPA_IS_PORT_INPUT(port_desc)) {
|
||||
LADSPA_Data dft = 0.0f;
|
||||
int found = find_default(pvt->ldesc, i, &dft);
|
||||
|
||||
if (found && !pvt->has_config[j]) {
|
||||
pvt->config[j] = dft;
|
||||
pvt->has_config[j] = 1;
|
||||
}
|
||||
|
||||
if (pvt->has_config[j]) {
|
||||
if (!check_range(pvt->ldesc, i, pvt->config[j])) {
|
||||
pvt->config[j] = dft;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_WARNING, "FALLING TO DEFAULT PARAM %d [%s] (%f)\n",
|
||||
j+1,
|
||||
pvt->ldesc->PortNames[i],
|
||||
pvt->config[j]);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "ADDING PARAM %d [%s] (%f)\n",
|
||||
j+1,
|
||||
pvt->ldesc->PortNames[i],
|
||||
pvt->config[j]);
|
||||
pvt->ldesc->connect_port(pvt->handle, i, &pvt->config[j++]);
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
if (LADSPA_IS_PORT_INPUT(port_desc) && LADSPA_IS_PORT_AUDIO(port_desc)) {
|
||||
pvt->ldesc->connect_port(pvt->handle, i, pvt->in_buf);
|
||||
}
|
||||
|
||||
if (LADSPA_IS_PORT_OUTPUT(port_desc)) {
|
||||
if (LADSPA_IS_PORT_AUDIO(port_desc)) {
|
||||
pvt->ldesc->connect_port(pvt->handle, i, pvt->out_buf);
|
||||
} else if (k < MAX_INDEX) {
|
||||
pvt->ldesc->connect_port(pvt->handle, i, &pvt->out_ports[k++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SWITCH_ABC_TYPE_CLOSE:
|
||||
{
|
||||
|
||||
if (pvt->handle && pvt->ldesc) {
|
||||
pvt->ldesc->cleanup(pvt->handle);
|
||||
}
|
||||
|
||||
if (pvt->library_handle) {
|
||||
unloadLADSPAPluginLibrary(pvt->library_handle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SWITCH_ABC_TYPE_WRITE_REPLACE:
|
||||
case SWITCH_ABC_TYPE_READ_REPLACE:
|
||||
{
|
||||
switch_frame_t *rframe;
|
||||
int16_t *slin;
|
||||
|
||||
if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
|
||||
rframe = switch_core_media_bug_get_read_replace_frame(bug);
|
||||
} else {
|
||||
rframe = switch_core_media_bug_get_write_replace_frame(bug);
|
||||
}
|
||||
|
||||
slin = rframe->data;
|
||||
|
||||
if (switch_channel_media_ready(channel)) {
|
||||
switch_short_to_float(slin, pvt->in_buf, rframe->samples);
|
||||
pvt->ldesc->run(pvt->handle, rframe->samples);
|
||||
switch_float_to_short(pvt->out_buf, slin, rframe->samples);
|
||||
}
|
||||
|
||||
if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
|
||||
switch_core_media_bug_set_read_replace_frame(bug, rframe);
|
||||
} else {
|
||||
switch_core_media_bug_set_write_replace_frame(bug, rframe);
|
||||
}
|
||||
|
||||
if (pvt->skip && !--pvt->skip) {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_WRITE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SWITCH_TRUE;
|
||||
}
|
||||
|
||||
switch_status_t stop_ladspa_session(switch_core_session_t *session)
|
||||
{
|
||||
switch_media_bug_t *bug;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if ((bug = switch_channel_get_private(channel, "ladspa"))) {
|
||||
switch_channel_set_private(channel, "ladspa", NULL);
|
||||
switch_core_media_bug_remove(session, &bug);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
switch_status_t ladspa_session(switch_core_session_t *session, const char *flags, const char *plugin_name, const char *label, const char *params)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_media_bug_t *bug;
|
||||
switch_status_t status;
|
||||
switch_ladspa_t *pvt = { 0 };
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
int i, bflags = SMBF_READ_REPLACE | SMBF_ANSWER_REQ;
|
||||
char *pstr;
|
||||
int argc;
|
||||
char *argv[50];
|
||||
char *dparams = NULL;
|
||||
|
||||
if (zstr(plugin_name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s INVALID PLUGIN\n", switch_channel_get_name(channel));
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (zstr(flags)) {
|
||||
flags = "r";
|
||||
}
|
||||
|
||||
if (strchr(flags, 'w')) {
|
||||
bflags = SMBF_WRITE_REPLACE;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "FLAGS: %s PLUGIN: %s LABEL: %s PARAMS: %s\n",
|
||||
flags, plugin_name, label, params);
|
||||
|
||||
switch_core_session_get_read_impl(session, &read_impl);
|
||||
|
||||
pvt = switch_core_session_alloc(session, sizeof(*pvt));
|
||||
|
||||
pvt->session = session;
|
||||
if (!zstr(label)) {
|
||||
pvt->label_name = switch_core_session_strdup(session, label);
|
||||
} else {
|
||||
char *p;
|
||||
pvt->label_name = switch_core_session_strdup(session, plugin_name);
|
||||
if ((p = strrchr(pvt->label_name, '.'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (strstr(plugin_name, ".so")) {
|
||||
pvt->plugin_name = switch_core_session_strdup(session, plugin_name);
|
||||
} else {
|
||||
pvt->plugin_name = switch_core_session_sprintf(session, "%s.so", plugin_name);
|
||||
}
|
||||
|
||||
dparams = switch_core_session_strdup(session, params);
|
||||
|
||||
argc = switch_split(dparams, ' ', argv);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
pvt->config[i] = atof(argv[i]);
|
||||
pvt->has_config[i] = 1;
|
||||
}
|
||||
|
||||
if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
pstr = switch_core_session_sprintf(session, "%s|%s|%s|%s", flags, plugin_name, label, params);
|
||||
|
||||
if ((status = switch_core_media_bug_add(session, "ladspa", pstr,
|
||||
ladspa_callback, pvt, 0, bflags | SMBF_NO_PAUSE, &bug)) != SWITCH_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_channel_set_private(channel, "ladspa", bug);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void ladspa_parse(switch_core_session_t *session, const char *data)
|
||||
{
|
||||
char *argv[5] = { 0 };
|
||||
int argc;
|
||||
char *lbuf;
|
||||
|
||||
if (data) {
|
||||
lbuf = strdup(data);
|
||||
argc = switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
ladspa_session(session, argv[0], argv[1], argv[2], argv[3]);
|
||||
free(lbuf);
|
||||
}
|
||||
}
|
||||
|
||||
#define APP_SYNTAX "<flags>|<plugin>|<label>|<params>"
|
||||
SWITCH_STANDARD_APP(ladspa_run_function)
|
||||
{
|
||||
ladspa_parse(session, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define API_SYNTAX "<uuid>|<flags>|<plugin>|<label>|<params>"
|
||||
SWITCH_STANDARD_API(ladspa_api)
|
||||
{
|
||||
char *uuid = NULL;
|
||||
char *data;
|
||||
char *p;
|
||||
switch_core_session_t *ksession = NULL;
|
||||
|
||||
if (!cmd) goto err;
|
||||
|
||||
data = strdup(cmd);
|
||||
|
||||
if ((p = strchr(data, ' '))) {
|
||||
uuid = data;
|
||||
*p++ = '\0';
|
||||
|
||||
if ((ksession = switch_core_session_locate(uuid))) {
|
||||
ladspa_parse(ksession, p);
|
||||
switch_core_session_rwunlock(ksession);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR non-existant UUID\n");
|
||||
}
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR Usage %s\n", API_SYNTAX);
|
||||
}
|
||||
|
||||
free(data);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
err:
|
||||
|
||||
stream->write_function(stream, "-ERR Operation Failed\n");
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Macro expands to: switch_status_t mod_ladspa_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load)
|
||||
{
|
||||
switch_application_interface_t *app_interface;
|
||||
switch_api_interface_t *api_interface;
|
||||
|
||||
char *path = getenv("LADSPA_PATH");
|
||||
|
||||
if (zstr(path)) {
|
||||
if (switch_directory_exists("/usr/lib64/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
|
||||
putenv("LADSPA_PATH=/usr/lib64/ladspa/:/usr/local/lib/ladspa");
|
||||
} else if (switch_directory_exists("/usr/lib/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
|
||||
putenv("LADSPA_PATH=/usr/lib/ladspa/:/usr/local/lib/ladspa");
|
||||
}
|
||||
}
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "ladspa_run", "ladspa_run", NULL, ladspa_run_function, APP_SYNTAX, SAF_NONE);
|
||||
SWITCH_ADD_API(api_interface, "uuid_ladspa", "ladspa", ladspa_api, API_SYNTAX);
|
||||
|
||||
switch_console_set_complete("add uuid_ladspa ::console::list_uuid");
|
||||
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
Called when the system shuts down
|
||||
Macro expands to: switch_status_t mod_ladspa_shutdown() */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown)
|
||||
{
|
||||
/* Cleanup dynamically allocated config settings */
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
|
@ -0,0 +1,72 @@
|
|||
/* utils.h
|
||||
|
||||
Free software by Richard W.E. Furse. Do with as you will. No
|
||||
warranty. */
|
||||
|
||||
#ifndef LADSPA_SDK_LOAD_PLUGIN_LIB
|
||||
#define LADSPA_SDK_LOAD_PLUGIN_LIB
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "ladspa.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Functions in load.c: */
|
||||
|
||||
/* This function call takes a plugin library filename, searches for
|
||||
the library along the LADSPA_PATH, loads it with dlopen() and
|
||||
returns a plugin handle for use with findPluginDescriptor() or
|
||||
unloadLADSPAPluginLibrary(). Errors are handled by writing a
|
||||
message to stderr and calling exit(1). It is alright (although
|
||||
inefficient) to call this more than once for the same file. */
|
||||
void * loadLADSPAPluginLibrary(const char * pcPluginFilename);
|
||||
|
||||
/* This function unloads a LADSPA plugin library. */
|
||||
void unloadLADSPAPluginLibrary(void * pvLADSPAPluginLibrary);
|
||||
|
||||
/* This function locates a LADSPA plugin within a plugin library
|
||||
loaded with loadLADSPAPluginLibrary(). Errors are handled by
|
||||
writing a message to stderr and calling exit(1). Note that the
|
||||
plugin library filename is only included to help provide
|
||||
informative error messages. */
|
||||
const LADSPA_Descriptor *
|
||||
findLADSPAPluginDescriptor(void * pvLADSPAPluginLibrary,
|
||||
const char * pcPluginLibraryFilename,
|
||||
const char * pcPluginLabel);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Functions in search.c: */
|
||||
|
||||
/* Callback function for use with LADSPAPluginSearch(). The callback
|
||||
function passes the filename (full path), a plugin handle (dlopen()
|
||||
style) and a LADSPA_DescriptorFunction (from which
|
||||
LADSPA_Descriptors can be acquired). */
|
||||
typedef void LADSPAPluginSearchCallbackFunction
|
||||
(const char * pcFullFilename,
|
||||
void * pvPluginHandle,
|
||||
LADSPA_Descriptor_Function fDescriptorFunction);
|
||||
|
||||
/* Search through the $(LADSPA_PATH) (or a default path) for any
|
||||
LADSPA plugin libraries. Each plugin library is tested using
|
||||
dlopen() and dlsym(,"ladspa_descriptor"). After loading each
|
||||
library, the callback function is called to process it. This
|
||||
function leaves items passed to the callback function open. */
|
||||
void LADSPAPluginSearch(LADSPAPluginSearchCallbackFunction fCallbackFunction);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Function in default.c: */
|
||||
|
||||
/* Find the default value for a port. Return 0 if a default is found
|
||||
and -1 if not. */
|
||||
int getLADSPADefault(const LADSPA_PortRangeHint * psPortRangeHint,
|
||||
const unsigned long lSampleRate,
|
||||
LADSPA_Data * pfResult);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
Loading…
Reference in New Issue