|
Packit |
4a16fb |
/**
|
|
Packit |
4a16fb |
* \file pcm/pcm_ladspa.c
|
|
Packit |
4a16fb |
* \ingroup PCM_Plugins
|
|
Packit |
4a16fb |
* \brief ALSA Plugin <-> LADSPA Plugin Interface
|
|
Packit |
4a16fb |
* \author Jaroslav Kysela <perex@perex.cz>
|
|
Packit |
4a16fb |
* \author Jaroslav Kysela <perex@perex.cz>
|
|
Packit |
4a16fb |
* \date 2001,2006
|
|
Packit |
4a16fb |
*/
|
|
Packit |
4a16fb |
/*
|
|
Packit |
4a16fb |
* PCM - LADSPA integration plugin
|
|
Packit |
4a16fb |
* Copyright (c) 2001-2006 by Jaroslav Kysela <perex@perex.cz>
|
|
Packit |
4a16fb |
* Copyright (c) 2005 by Jaroslav Kysela <perex@perex.cz>
|
|
Packit |
4a16fb |
*
|
|
Packit |
4a16fb |
*
|
|
Packit |
4a16fb |
* This library is free software; you can redistribute it and/or modify
|
|
Packit |
4a16fb |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit |
4a16fb |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
4a16fb |
* the License, or (at your option) any later version.
|
|
Packit |
4a16fb |
*
|
|
Packit |
4a16fb |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
4a16fb |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
4a16fb |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
4a16fb |
* GNU Lesser General Public License for more details.
|
|
Packit |
4a16fb |
*
|
|
Packit |
4a16fb |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
4a16fb |
* License along with this library; if not, write to the Free Software
|
|
Packit |
4a16fb |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
4a16fb |
*
|
|
Packit |
4a16fb |
*
|
|
Packit |
4a16fb |
* perex@perex.cz 2005/12/13
|
|
Packit |
4a16fb |
* The LADSPA plugin rewrite was sponsored by MediaNet AG
|
|
Packit |
4a16fb |
* http://www.medianet.ag
|
|
Packit |
4a16fb |
*/
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
#include <dirent.h>
|
|
Packit |
4a16fb |
#include <locale.h>
|
|
Packit |
4a16fb |
#include <math.h>
|
|
Packit |
4a16fb |
#include "pcm_local.h"
|
|
Packit |
4a16fb |
#include "pcm_plugin.h"
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
#include "ladspa.h"
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
#ifndef PIC
|
|
Packit |
4a16fb |
/* entry for static linking */
|
|
Packit |
4a16fb |
const char *_snd_module_pcm_ladspa = "";
|
|
Packit |
4a16fb |
#endif
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
#ifndef DOC_HIDDEN
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
#define NO_ASSIGN 0xffffffff
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
typedef enum _snd_pcm_ladspa_policy {
|
|
Packit |
4a16fb |
SND_PCM_LADSPA_POLICY_NONE, /* use bindings only */
|
|
Packit |
4a16fb |
SND_PCM_LADSPA_POLICY_DUPLICATE /* duplicate bindings for all channels */
|
|
Packit |
4a16fb |
} snd_pcm_ladspa_policy_t;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
typedef struct {
|
|
Packit |
4a16fb |
/* This field need to be the first */
|
|
Packit |
4a16fb |
snd_pcm_plugin_t plug;
|
|
Packit |
4a16fb |
/* Plugin custom fields */
|
|
Packit |
4a16fb |
struct list_head pplugins;
|
|
Packit |
4a16fb |
struct list_head cplugins;
|
|
Packit |
4a16fb |
unsigned int channels; /* forced input channels, 0 = auto */
|
|
Packit |
4a16fb |
unsigned int allocated; /* count of allocated samples */
|
|
Packit |
4a16fb |
LADSPA_Data *zero[2]; /* zero input or dummy output */
|
|
Packit |
4a16fb |
} snd_pcm_ladspa_t;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
typedef struct {
|
|
Packit |
4a16fb |
unsigned int size;
|
|
Packit |
4a16fb |
unsigned int *array;
|
|
Packit |
4a16fb |
} snd_pcm_ladspa_array_t;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
typedef struct {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_array_t channels;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_array_t ports;
|
|
Packit |
4a16fb |
LADSPA_Data **m_data;
|
|
Packit |
4a16fb |
LADSPA_Data **data;
|
|
Packit |
4a16fb |
} snd_pcm_ladspa_eps_t;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
typedef struct snd_pcm_ladspa_instance {
|
|
Packit |
4a16fb |
struct list_head list;
|
|
Packit |
4a16fb |
const LADSPA_Descriptor *desc;
|
|
Packit |
4a16fb |
LADSPA_Handle *handle;
|
|
Packit |
4a16fb |
unsigned int depth;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_eps_t input;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_eps_t output;
|
|
Packit |
4a16fb |
struct snd_pcm_ladspa_instance *prev;
|
|
Packit |
4a16fb |
struct snd_pcm_ladspa_instance *next;
|
|
Packit |
4a16fb |
} snd_pcm_ladspa_instance_t;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
typedef struct {
|
|
Packit |
4a16fb |
LADSPA_PortDescriptor pdesc; /* port description */
|
|
Packit |
4a16fb |
unsigned int port_bindings_size; /* size of array */
|
|
Packit |
4a16fb |
unsigned int *port_bindings; /* index = channel number, value = LADSPA port */
|
|
Packit |
4a16fb |
unsigned int controls_size; /* size of array */
|
|
Packit |
4a16fb |
unsigned char *controls_initialized; /* initialized by ALSA user */
|
|
Packit |
4a16fb |
LADSPA_Data *controls; /* index = LADSPA control port index */
|
|
Packit |
4a16fb |
} snd_pcm_ladspa_plugin_io_t;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
typedef struct {
|
|
Packit |
4a16fb |
struct list_head list;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_policy_t policy;
|
|
Packit |
4a16fb |
char *filename;
|
|
Packit |
4a16fb |
void *dl_handle;
|
|
Packit |
4a16fb |
const LADSPA_Descriptor *desc;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t input;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t output;
|
|
Packit |
4a16fb |
struct list_head instances; /* one LADSPA plugin might be used multiple times */
|
|
Packit |
4a16fb |
} snd_pcm_ladspa_plugin_t;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
#endif /* DOC_HIDDEN */
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static unsigned int snd_pcm_ladspa_count_ports(snd_pcm_ladspa_plugin_t *lplug,
|
|
Packit |
4a16fb |
LADSPA_PortDescriptor pdesc)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int res = 0, idx;
|
|
Packit |
4a16fb |
for (idx = 0; idx < lplug->desc->PortCount; idx++) {
|
|
Packit |
4a16fb |
if ((lplug->desc->PortDescriptors[idx] & pdesc) == pdesc)
|
|
Packit |
4a16fb |
res++;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return res;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_find_port(unsigned int *res,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *lplug,
|
|
Packit |
4a16fb |
LADSPA_PortDescriptor pdesc,
|
|
Packit |
4a16fb |
unsigned int port_idx)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned long idx;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
for (idx = 0; idx < lplug->desc->PortCount; idx++)
|
|
Packit |
4a16fb |
if ((lplug->desc->PortDescriptors[idx] & pdesc) == pdesc) {
|
|
Packit |
4a16fb |
if (port_idx == 0) {
|
|
Packit |
4a16fb |
*res = idx;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
port_idx--;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_find_sport(unsigned int *res,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *lplug,
|
|
Packit |
4a16fb |
LADSPA_PortDescriptor pdesc,
|
|
Packit |
4a16fb |
const char *port_name)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned long idx;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
for (idx = 0; idx < lplug->desc->PortCount; idx++)
|
|
Packit |
4a16fb |
if ((lplug->desc->PortDescriptors[idx] & pdesc) == pdesc &&
|
|
Packit |
4a16fb |
!strcmp(lplug->desc->PortNames[idx], port_name)) {
|
|
Packit |
4a16fb |
*res = idx;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_find_port_idx(unsigned int *res,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *lplug,
|
|
Packit |
4a16fb |
LADSPA_PortDescriptor pdesc,
|
|
Packit |
4a16fb |
unsigned int port)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned long idx;
|
|
Packit |
4a16fb |
unsigned int r = 0;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (port >= lplug->desc->PortCount)
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
for (idx = 0; idx < port; idx++)
|
|
Packit |
4a16fb |
if ((lplug->desc->PortDescriptors[idx] & pdesc) == pdesc)
|
|
Packit |
4a16fb |
r++;
|
|
Packit |
4a16fb |
*res = r;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static void snd_pcm_ladspa_free_io(snd_pcm_ladspa_plugin_io_t *io)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
free(io->controls);
|
|
Packit |
4a16fb |
free(io->controls_initialized);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static void snd_pcm_ladspa_free_plugins(struct list_head *plugins)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
while (!list_empty(plugins)) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *plugin = list_entry(plugins->next, snd_pcm_ladspa_plugin_t, list);
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free_io(&plugin->input);
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free_io(&plugin->output);
|
|
Packit |
4a16fb |
if (plugin->dl_handle)
|
|
Packit |
4a16fb |
dlclose(plugin->dl_handle);
|
|
Packit |
4a16fb |
free(plugin->filename);
|
|
Packit |
4a16fb |
list_del(&plugin->list);
|
|
Packit |
4a16fb |
free(plugin);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static void snd_pcm_ladspa_free(snd_pcm_ladspa_t *ladspa)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int idx;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free_plugins(&ladspa->pplugins);
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free_plugins(&ladspa->cplugins);
|
|
Packit |
4a16fb |
for (idx = 0; idx < 2; idx++) {
|
|
Packit |
4a16fb |
free(ladspa->zero[idx]);
|
|
Packit |
4a16fb |
ladspa->zero[idx] = NULL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
ladspa->allocated = 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_close(snd_pcm_t *pcm)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_pcm_ladspa_t *ladspa = pcm->private_data;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free(ladspa);
|
|
Packit |
4a16fb |
return snd_pcm_generic_close(pcm);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_pcm_ladspa_t *ladspa = pcm->private_data;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHMN };
|
|
Packit |
4a16fb |
err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
|
|
Packit |
4a16fb |
&access_mask);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
err = _snd_pcm_hw_params_set_format(params, SND_PCM_FORMAT_FLOAT);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
if (ladspa->channels > 0 && pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit |
4a16fb |
err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, ladspa->channels, 0);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_pcm_ladspa_t *ladspa = pcm->private_data;
|
|
Packit |
4a16fb |
snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAPN };
|
|
Packit |
4a16fb |
_snd_pcm_hw_params_any(sparams);
|
|
Packit |
4a16fb |
_snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
|
|
Packit |
4a16fb |
&saccess_mask);
|
|
Packit |
4a16fb |
_snd_pcm_hw_params_set_format(sparams, SND_PCM_FORMAT_FLOAT);
|
|
Packit |
4a16fb |
_snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
|
|
Packit |
4a16fb |
if (ladspa->channels > 0 && pcm->stream == SND_PCM_STREAM_CAPTURE)
|
|
Packit |
4a16fb |
_snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, ladspa->channels, 0);
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
|
|
Packit |
4a16fb |
snd_pcm_hw_params_t *sparams)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_RATE |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_BUFFER_SIZE |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_PERIODS |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_PERIOD_TIME |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_BUFFER_TIME |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_TICK_TIME);
|
|
Packit |
4a16fb |
err = _snd_pcm_hw_params_refine(sparams, links, params);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
|
|
Packit |
4a16fb |
snd_pcm_hw_params_t *sparams)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_RATE |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_PERIOD_SIZE |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_BUFFER_SIZE |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_PERIODS |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_PERIOD_TIME |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_BUFFER_TIME |
|
|
Packit |
4a16fb |
SND_PCM_HW_PARBIT_TICK_TIME);
|
|
Packit |
4a16fb |
err = _snd_pcm_hw_params_refine(params, links, sparams);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
return snd_pcm_hw_refine_slave(pcm, params,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_hw_refine_cprepare,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_hw_refine_cchange,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_hw_refine_sprepare,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_hw_refine_schange,
|
|
Packit |
4a16fb |
snd_pcm_generic_hw_refine);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
// snd_pcm_ladspa_t *ladspa = pcm->private_data;
|
|
Packit |
4a16fb |
int err = snd_pcm_hw_params_slave(pcm, params,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_hw_refine_cchange,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_hw_refine_sprepare,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_hw_refine_schange,
|
|
Packit |
4a16fb |
snd_pcm_generic_hw_params);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static void snd_pcm_ladspa_free_eps(snd_pcm_ladspa_eps_t *eps)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
free(eps->channels.array);
|
|
Packit |
4a16fb |
free(eps->ports.array);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static void snd_pcm_ladspa_free_instances(snd_pcm_t *pcm, snd_pcm_ladspa_t *ladspa, int cleanup)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct list_head *list, *pos, *pos1, *next1;
|
|
Packit |
4a16fb |
unsigned int idx;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
list = pcm->stream == SND_PCM_STREAM_PLAYBACK ? &ladspa->pplugins : &ladspa->cplugins;
|
|
Packit |
4a16fb |
list_for_each(pos, list) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list);
|
|
Packit |
4a16fb |
list_for_each_safe(pos1, next1, &plugin->instances) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_instance_t *instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list);
|
|
Packit |
4a16fb |
if (plugin->desc->deactivate)
|
|
Packit |
4a16fb |
plugin->desc->deactivate(instance->handle);
|
|
Packit |
4a16fb |
if (cleanup) {
|
|
Packit |
4a16fb |
if (plugin->desc->cleanup)
|
|
Packit |
4a16fb |
plugin->desc->cleanup(instance->handle);
|
|
Packit |
4a16fb |
if (instance->input.m_data) {
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->input.channels.size; idx++)
|
|
Packit |
4a16fb |
free(instance->input.m_data[idx]);
|
|
Packit |
4a16fb |
free(instance->input.m_data);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (instance->output.m_data) {
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->output.channels.size; idx++)
|
|
Packit |
4a16fb |
free(instance->output.m_data[idx]);
|
|
Packit |
4a16fb |
free(instance->output.m_data);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
free(instance->input.data);
|
|
Packit |
4a16fb |
free(instance->output.data);
|
|
Packit |
4a16fb |
list_del(&(instance->list));
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free_eps(&instance->input);
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free_eps(&instance->output);
|
|
Packit |
4a16fb |
free(instance);
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
if (plugin->desc->activate)
|
|
Packit |
4a16fb |
plugin->desc->activate(instance->handle);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (cleanup) {
|
|
Packit |
4a16fb |
assert(list_empty(&plugin->instances));
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_add_to_carray(snd_pcm_ladspa_array_t *array,
|
|
Packit |
4a16fb |
unsigned int idx,
|
|
Packit |
4a16fb |
unsigned int val)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int *narray;
|
|
Packit |
4a16fb |
unsigned int idx1;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (idx >= array->size) {
|
|
Packit |
4a16fb |
narray = realloc(array->array, sizeof(unsigned int) * (idx + 1));
|
|
Packit |
4a16fb |
if (narray == NULL)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
for (idx1 = array->size; idx1 < idx; idx1++)
|
|
Packit |
4a16fb |
narray[idx1] = NO_ASSIGN;
|
|
Packit |
4a16fb |
array->array = narray;
|
|
Packit |
4a16fb |
array->size = idx + 1;
|
|
Packit |
4a16fb |
array->array[idx] = val;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (array->array[idx] == NO_ASSIGN)
|
|
Packit |
4a16fb |
array->array[idx] = val;
|
|
Packit |
4a16fb |
else
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_add_to_array(snd_pcm_ladspa_array_t *array,
|
|
Packit |
4a16fb |
unsigned int idx,
|
|
Packit |
4a16fb |
unsigned int val)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int *narray;
|
|
Packit |
4a16fb |
unsigned int idx1;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (idx >= array->size) {
|
|
Packit |
4a16fb |
narray = realloc(array->array, sizeof(unsigned int) * (idx + 1));
|
|
Packit |
4a16fb |
if (narray == NULL)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
for (idx1 = array->size; idx1 < idx; idx1++)
|
|
Packit |
4a16fb |
narray[idx1] = NO_ASSIGN;
|
|
Packit |
4a16fb |
array->array = narray;
|
|
Packit |
4a16fb |
array->size = idx + 1;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
array->array[idx] = val;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_connect_plugin1(snd_pcm_ladspa_plugin_t *plugin,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t *io,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_eps_t *eps)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int port, channels, idx, idx1;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
assert(plugin->policy == SND_PCM_LADSPA_POLICY_NONE);
|
|
Packit |
4a16fb |
channels = io->port_bindings_size > 0 ?
|
|
Packit |
4a16fb |
io->port_bindings_size :
|
|
Packit |
4a16fb |
snd_pcm_ladspa_count_ports(plugin, io->pdesc | LADSPA_PORT_AUDIO);
|
|
Packit |
4a16fb |
for (idx = idx1 = 0; idx < channels; idx++) {
|
|
Packit |
4a16fb |
if (io->port_bindings_size > 0)
|
|
Packit |
4a16fb |
port = io->port_bindings[idx];
|
|
Packit |
4a16fb |
else {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_find_port(&port, plugin, io->pdesc | LADSPA_PORT_AUDIO, idx);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("unable to find audio %s port %u plugin '%s'", io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", idx, plugin->desc->Name);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (port == NO_ASSIGN)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_add_to_carray(&eps->channels, idx1, idx);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("unable to add channel %u for audio %s plugin '%s'", idx, io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", plugin->desc->Name);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_add_to_array(&eps->ports, idx1, port);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("unable to add port %u for audio %s plugin '%s'", port, io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", plugin->desc->Name);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
idx1++;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_connect_plugin(snd_pcm_ladspa_plugin_t *plugin,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_instance_t *instance)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_connect_plugin1(plugin, &plugin->input, &instance->input);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_connect_plugin1(plugin, &plugin->output, &instance->output);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_connect_plugin_duplicate1(snd_pcm_ladspa_plugin_t *plugin,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t *io,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_eps_t *eps,
|
|
Packit |
4a16fb |
unsigned int idx)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int port;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
assert(plugin->policy == SND_PCM_LADSPA_POLICY_DUPLICATE);
|
|
Packit |
4a16fb |
if (io->port_bindings_size > 0) {
|
|
Packit |
4a16fb |
port = io->port_bindings[0];
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_find_port(&port, plugin, io->pdesc | LADSPA_PORT_AUDIO, 0);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("unable to find audio %s port %u plugin '%s'", io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", (unsigned int)0, plugin->desc->Name);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_add_to_carray(&eps->channels, 0, idx);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("unable to add channel %u for audio %s plugin '%s'", idx, io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", plugin->desc->Name);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_add_to_array(&eps->ports, 0, port);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("unable to add port %u for audio %s plugin '%s'", port, io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", plugin->desc->Name);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_connect_plugin_duplicate(snd_pcm_ladspa_plugin_t *plugin,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t *in_io,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t *out_io,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_instance_t *instance,
|
|
Packit |
4a16fb |
unsigned int idx)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_connect_plugin_duplicate1(plugin, in_io, &instance->input, idx);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_connect_plugin_duplicate1(plugin, out_io, &instance->output, idx);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static void snd_pcm_ladspa_get_default_cvalue(const LADSPA_Descriptor * desc, unsigned int port, LADSPA_Data *val)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
LADSPA_PortRangeHintDescriptor hdesc;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
hdesc = desc->PortRangeHints[port].HintDescriptor;
|
|
Packit |
4a16fb |
switch (hdesc & LADSPA_HINT_DEFAULT_MASK) {
|
|
Packit |
4a16fb |
case LADSPA_HINT_DEFAULT_MINIMUM:
|
|
Packit |
4a16fb |
*val = desc->PortRangeHints[port].LowerBound;
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
case LADSPA_HINT_DEFAULT_LOW:
|
|
Packit |
4a16fb |
if (LADSPA_IS_HINT_LOGARITHMIC(hdesc)) {
|
|
Packit |
4a16fb |
*val = exp(log(desc->PortRangeHints[port].LowerBound)
|
|
Packit |
4a16fb |
* 0.75
|
|
Packit |
4a16fb |
+ log(desc->PortRangeHints[port].UpperBound)
|
|
Packit |
4a16fb |
* 0.25);
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
*val = (desc->PortRangeHints[port].LowerBound * 0.75) +
|
|
Packit |
4a16fb |
(desc->PortRangeHints[port].UpperBound * 0.25);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
case LADSPA_HINT_DEFAULT_MIDDLE:
|
|
Packit |
4a16fb |
if (LADSPA_IS_HINT_LOGARITHMIC(hdesc)) {
|
|
Packit |
4a16fb |
*val = sqrt(desc->PortRangeHints[port].LowerBound *
|
|
Packit |
4a16fb |
desc->PortRangeHints[port].UpperBound);
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
*val = 0.5 *
|
|
Packit |
4a16fb |
(desc->PortRangeHints[port].LowerBound +
|
|
Packit |
4a16fb |
desc->PortRangeHints[port].UpperBound);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
case LADSPA_HINT_DEFAULT_HIGH:
|
|
Packit |
4a16fb |
if (LADSPA_IS_HINT_LOGARITHMIC(hdesc)) {
|
|
Packit |
4a16fb |
*val = exp(log(desc->PortRangeHints[port].LowerBound)
|
|
Packit |
4a16fb |
* 0.25
|
|
Packit |
4a16fb |
+ log(desc->PortRangeHints[port].UpperBound)
|
|
Packit |
4a16fb |
* 0.75);
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
*val = (desc->PortRangeHints[port].LowerBound * 0.25) +
|
|
Packit |
4a16fb |
(desc->PortRangeHints[port].UpperBound * 0.75);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
case LADSPA_HINT_DEFAULT_MAXIMUM:
|
|
Packit |
4a16fb |
*val = desc->PortRangeHints[port].UpperBound;
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
case LADSPA_HINT_DEFAULT_0:
|
|
Packit |
4a16fb |
*val = 0;
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
case LADSPA_HINT_DEFAULT_1:
|
|
Packit |
4a16fb |
*val = 1;
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
case LADSPA_HINT_DEFAULT_100:
|
|
Packit |
4a16fb |
*val = 100;
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
case LADSPA_HINT_DEFAULT_440:
|
|
Packit |
4a16fb |
*val = 440;
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
default:
|
|
Packit |
4a16fb |
*val = 0; /* reasonable default, if everything fails */
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_connect_controls(snd_pcm_ladspa_plugin_t *plugin,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t *io,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_instance_t *instance)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned long idx, midx;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
for (idx = midx = 0; idx < plugin->desc->PortCount; idx++)
|
|
Packit |
4a16fb |
if ((plugin->desc->PortDescriptors[idx] & (io->pdesc | LADSPA_PORT_CONTROL)) == (io->pdesc | LADSPA_PORT_CONTROL)) {
|
|
Packit |
4a16fb |
if (io->controls_size > midx) {
|
|
Packit |
4a16fb |
if (!io->controls_initialized[midx])
|
|
Packit |
4a16fb |
snd_pcm_ladspa_get_default_cvalue(plugin->desc, idx, &io->controls[midx]);
|
|
Packit |
4a16fb |
plugin->desc->connect_port(instance->handle, idx, &io->controls[midx]);
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
midx++;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_check_connect(snd_pcm_ladspa_plugin_t *plugin,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t *io,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_eps_t *eps,
|
|
Packit |
4a16fb |
unsigned int depth)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int idx, midx;
|
|
Packit |
4a16fb |
int err = 0;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
for (idx = midx = 0; idx < plugin->desc->PortCount; idx++)
|
|
Packit |
4a16fb |
if ((plugin->desc->PortDescriptors[idx] & (io->pdesc | LADSPA_PORT_AUDIO)) == (io->pdesc | LADSPA_PORT_AUDIO)) {
|
|
Packit |
4a16fb |
if (eps->channels.array[midx] == NO_ASSIGN) {
|
|
Packit |
4a16fb |
SNDERR("%s port for plugin %s depth %u is not connected", io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", plugin->desc->Name, depth);
|
|
Packit |
4a16fb |
err++;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
midx++;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (err > 0) {
|
|
Packit |
4a16fb |
SNDERR("%i connection errors total", err);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_allocate_instances(snd_pcm_t *pcm, snd_pcm_ladspa_t *ladspa)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct list_head *list, *pos;
|
|
Packit |
4a16fb |
unsigned int depth, idx, count;
|
|
Packit |
4a16fb |
unsigned int in_channels;
|
|
Packit |
4a16fb |
unsigned int in_ports, out_ports;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_instance_t *instance = NULL;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
list = pcm->stream == SND_PCM_STREAM_PLAYBACK ? &ladspa->pplugins : &ladspa->cplugins;
|
|
Packit |
4a16fb |
in_channels = ladspa->channels > 0 ? ladspa->channels :
|
|
Packit |
4a16fb |
(pcm->stream == SND_PCM_STREAM_PLAYBACK ? pcm->channels : ladspa->plug.gen.slave->channels);
|
|
Packit |
4a16fb |
depth = 0;
|
|
Packit |
4a16fb |
list_for_each(pos, list) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list);
|
|
Packit |
4a16fb |
in_ports = snd_pcm_ladspa_count_ports(plugin, LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO);
|
|
Packit |
4a16fb |
out_ports = snd_pcm_ladspa_count_ports(plugin, LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO);
|
|
Packit |
4a16fb |
count = 1;
|
|
Packit |
4a16fb |
if (plugin->policy == SND_PCM_LADSPA_POLICY_DUPLICATE) {
|
|
Packit |
4a16fb |
if (in_ports == 1 && out_ports == 1)
|
|
Packit |
4a16fb |
count = in_channels;
|
|
Packit |
4a16fb |
else
|
|
Packit |
4a16fb |
plugin->policy = SND_PCM_LADSPA_POLICY_NONE;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
for (idx = 0; idx < count; idx++) {
|
|
Packit |
4a16fb |
instance = (snd_pcm_ladspa_instance_t *)calloc(1, sizeof(snd_pcm_ladspa_instance_t));
|
|
Packit |
4a16fb |
if (instance == NULL)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
instance->desc = plugin->desc;
|
|
Packit |
4a16fb |
instance->handle = plugin->desc->instantiate(plugin->desc, pcm->rate);
|
|
Packit |
4a16fb |
instance->depth = depth;
|
|
Packit |
4a16fb |
if (instance->handle == NULL) {
|
|
Packit |
4a16fb |
SNDERR("Unable to create instance of LADSPA plugin '%s'", plugin->desc->Name);
|
|
Packit |
4a16fb |
free(instance);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
list_add_tail(&instance->list, &plugin->instances);
|
|
Packit |
4a16fb |
if (plugin->policy == SND_PCM_LADSPA_POLICY_DUPLICATE) {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_connect_plugin_duplicate(plugin, &plugin->input, &plugin->output, instance, idx);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("Unable to connect duplicate port of plugin '%s' channel %u depth %u", plugin->desc->Name, idx, instance->depth);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_connect_plugin(plugin, instance);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("Unable to connect plugin '%s' depth %u", plugin->desc->Name, depth);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_connect_controls(plugin, &plugin->input, instance);
|
|
Packit |
4a16fb |
assert(err >= 0);
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_connect_controls(plugin, &plugin->output, instance);
|
|
Packit |
4a16fb |
assert(err >= 0);
|
|
Packit |
4a16fb |
if (plugin->desc->activate)
|
|
Packit |
4a16fb |
plugin->desc->activate(instance->handle);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_check_connect(plugin, &plugin->input, &instance->input, depth);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_check_connect(plugin, &plugin->output, &instance->output, depth);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
depth++;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static LADSPA_Data *snd_pcm_ladspa_allocate_zero(snd_pcm_ladspa_t *ladspa, unsigned int idx)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
if (ladspa->zero[idx] == NULL)
|
|
Packit |
4a16fb |
ladspa->zero[idx] = calloc(ladspa->allocated, sizeof(LADSPA_Data));
|
|
Packit |
4a16fb |
return ladspa->zero[idx];
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_allocate_memory(snd_pcm_t *pcm, snd_pcm_ladspa_t *ladspa)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct list_head *list, *pos, *pos1;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_instance_t *instance;
|
|
Packit |
4a16fb |
unsigned int channels = 16, nchannels;
|
|
Packit |
4a16fb |
unsigned int ichannels, ochannels;
|
|
Packit |
4a16fb |
void **pchannels, **npchannels;
|
|
Packit |
4a16fb |
unsigned int idx, chn;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
ladspa->allocated = 2048;
|
|
Packit |
4a16fb |
if (pcm->buffer_size > ladspa->allocated)
|
|
Packit |
4a16fb |
ladspa->allocated = pcm->buffer_size;
|
|
Packit |
4a16fb |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit |
4a16fb |
ichannels = pcm->channels;
|
|
Packit |
4a16fb |
ochannels = ladspa->plug.gen.slave->channels;
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
ichannels = ladspa->plug.gen.slave->channels;
|
|
Packit |
4a16fb |
ochannels = pcm->channels;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
pchannels = calloc(1, sizeof(void *) * channels);
|
|
Packit |
4a16fb |
if (pchannels == NULL)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
list = pcm->stream == SND_PCM_STREAM_PLAYBACK ? &ladspa->pplugins : &ladspa->cplugins;
|
|
Packit |
4a16fb |
list_for_each(pos, list) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list);
|
|
Packit |
4a16fb |
list_for_each(pos1, &plugin->instances) {
|
|
Packit |
4a16fb |
instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list);
|
|
Packit |
4a16fb |
nchannels = channels;
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->input.channels.size; idx++) {
|
|
Packit |
4a16fb |
chn = instance->input.channels.array[idx];
|
|
Packit |
4a16fb |
assert(instance->input.ports.array[idx] != NO_ASSIGN);
|
|
Packit |
4a16fb |
if (chn >= nchannels)
|
|
Packit |
4a16fb |
nchannels = chn + 1;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->output.channels.size; idx++) {
|
|
Packit |
4a16fb |
chn = instance->output.channels.array[idx];
|
|
Packit |
4a16fb |
assert(instance->output.ports.array[idx] != NO_ASSIGN);
|
|
Packit |
4a16fb |
if (chn >= nchannels)
|
|
Packit |
4a16fb |
nchannels = chn + 1;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (nchannels != channels) {
|
|
Packit |
4a16fb |
npchannels = realloc(pchannels, nchannels * sizeof(void *));
|
|
Packit |
4a16fb |
if (npchannels == NULL) {
|
|
Packit |
4a16fb |
free(pchannels);
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
for (idx = channels; idx < nchannels; idx++)
|
|
Packit |
4a16fb |
npchannels[idx] = NULL;
|
|
Packit |
4a16fb |
pchannels = npchannels;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
assert(instance->input.data == NULL);
|
|
Packit |
4a16fb |
assert(instance->input.m_data == NULL);
|
|
Packit |
4a16fb |
assert(instance->output.data == NULL);
|
|
Packit |
4a16fb |
assert(instance->output.m_data == NULL);
|
|
Packit |
4a16fb |
instance->input.data = calloc(instance->input.channels.size, sizeof(void *));
|
|
Packit |
4a16fb |
instance->input.m_data = calloc(instance->input.channels.size, sizeof(void *));
|
|
Packit |
4a16fb |
instance->output.data = calloc(instance->output.channels.size, sizeof(void *));
|
|
Packit |
4a16fb |
instance->output.m_data = calloc(instance->output.channels.size, sizeof(void *));
|
|
Packit |
4a16fb |
if (instance->input.data == NULL ||
|
|
Packit |
4a16fb |
instance->input.m_data == NULL ||
|
|
Packit |
4a16fb |
instance->output.data == NULL ||
|
|
Packit |
4a16fb |
instance->output.m_data == NULL) {
|
|
Packit |
4a16fb |
free(pchannels);
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->input.channels.size; idx++) {
|
|
Packit |
4a16fb |
chn = instance->input.channels.array[idx];
|
|
Packit |
4a16fb |
if (pchannels[chn] == NULL && chn < ichannels) {
|
|
Packit |
4a16fb |
instance->input.data[idx] = NULL;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
instance->input.data[idx] = pchannels[chn];
|
|
Packit |
4a16fb |
if (instance->input.data[idx] == NULL) {
|
|
Packit |
4a16fb |
instance->input.data[idx] = snd_pcm_ladspa_allocate_zero(ladspa, 0);
|
|
Packit |
4a16fb |
if (instance->input.data[idx] == NULL) {
|
|
Packit |
4a16fb |
free(pchannels);
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->output.channels.size; idx++) {
|
|
Packit |
4a16fb |
chn = instance->output.channels.array[idx];
|
|
Packit |
4a16fb |
/* FIXME/OPTIMIZE: check if we can remove double alloc */
|
|
Packit |
4a16fb |
/* if LADSPA plugin has no broken inplace */
|
|
Packit |
4a16fb |
instance->output.data[idx] = malloc(sizeof(LADSPA_Data) * ladspa->allocated);
|
|
Packit |
4a16fb |
if (instance->output.data[idx] == NULL) {
|
|
Packit |
4a16fb |
free(pchannels);
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
pchannels[chn] = instance->output.m_data[idx] = instance->output.data[idx];
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
/* OPTIMIZE: we have already allocated areas for ALSA output channels */
|
|
Packit |
4a16fb |
/* next loop deallocates the last output LADSPA areas and connects */
|
|
Packit |
4a16fb |
/* them to ALSA areas (NULL) or dummy area ladpsa->free[1] ; */
|
|
Packit |
4a16fb |
/* this algorithm might be optimized to not allocate the last LADSPA outputs */
|
|
Packit |
4a16fb |
list_for_each(pos, list) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list);
|
|
Packit |
4a16fb |
list_for_each(pos1, &plugin->instances) {
|
|
Packit |
4a16fb |
instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list);
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->output.channels.size; idx++) {
|
|
Packit |
4a16fb |
chn = instance->output.channels.array[idx];
|
|
Packit |
4a16fb |
if (instance->output.data[idx] == pchannels[chn]) {
|
|
Packit |
4a16fb |
free(instance->output.m_data[idx]);
|
|
Packit |
4a16fb |
instance->output.m_data[idx] = NULL;
|
|
Packit |
4a16fb |
if (chn < ochannels) {
|
|
Packit |
4a16fb |
instance->output.data[idx] = NULL;
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
instance->output.data[idx] = snd_pcm_ladspa_allocate_zero(ladspa, 1);
|
|
Packit |
4a16fb |
if (instance->output.data[idx] == NULL) {
|
|
Packit |
4a16fb |
free(pchannels);
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
#if 0
|
|
Packit |
4a16fb |
printf("zero[0] = %p\n", ladspa->zero[0]);
|
|
Packit |
4a16fb |
printf("zero[1] = %p\n", ladspa->zero[1]);
|
|
Packit |
4a16fb |
list_for_each(pos, list) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list);
|
|
Packit |
4a16fb |
list_for_each(pos1, &plugin->instances) {
|
|
Packit |
4a16fb |
instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list);
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->input.channels.size; idx++)
|
|
Packit |
4a16fb |
printf("%i:alloc-input%i: data = %p, m_data = %p\n", instance->depth, idx, instance->input.data[idx], instance->input.m_data[idx]);
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->output.channels.size; idx++)
|
|
Packit |
4a16fb |
printf("%i:alloc-output%i: data = %p, m_data = %p\n", instance->depth, idx, instance->output.data[idx], instance->output.m_data[idx]);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
#endif
|
|
Packit |
4a16fb |
free(pchannels);
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_init(snd_pcm_t *pcm)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_pcm_ladspa_t *ladspa = pcm->private_data;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free_instances(pcm, ladspa, 1);
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_allocate_instances(pcm, ladspa);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free_instances(pcm, ladspa, 1);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_allocate_memory(pcm, ladspa);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free_instances(pcm, ladspa, 1);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_hw_free(snd_pcm_t *pcm)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_pcm_ladspa_t *ladspa = pcm->private_data;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free_instances(pcm, ladspa, 1);
|
|
Packit |
4a16fb |
return snd_pcm_generic_hw_free(pcm);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static snd_pcm_uframes_t
|
|
Packit |
4a16fb |
snd_pcm_ladspa_write_areas(snd_pcm_t *pcm,
|
|
Packit |
4a16fb |
const snd_pcm_channel_area_t *areas,
|
|
Packit |
4a16fb |
snd_pcm_uframes_t offset,
|
|
Packit |
4a16fb |
snd_pcm_uframes_t size,
|
|
Packit |
4a16fb |
const snd_pcm_channel_area_t *slave_areas,
|
|
Packit |
4a16fb |
snd_pcm_uframes_t slave_offset,
|
|
Packit |
4a16fb |
snd_pcm_uframes_t *slave_sizep)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_pcm_ladspa_t *ladspa = pcm->private_data;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_instance_t *instance;
|
|
Packit |
4a16fb |
struct list_head *pos, *pos1;
|
|
Packit |
4a16fb |
LADSPA_Data *data;
|
|
Packit |
4a16fb |
unsigned int idx, chn, size1, size2;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (size > *slave_sizep)
|
|
Packit |
4a16fb |
size = *slave_sizep;
|
|
Packit |
4a16fb |
size2 = size;
|
|
Packit |
4a16fb |
#if 0 /* no processing - for testing purposes only */
|
|
Packit |
4a16fb |
snd_pcm_areas_copy(slave_areas, slave_offset,
|
|
Packit |
4a16fb |
areas, offset,
|
|
Packit |
4a16fb |
pcm->channels, size, pcm->format);
|
|
Packit |
4a16fb |
#else
|
|
Packit |
4a16fb |
while (size > 0) {
|
|
Packit |
4a16fb |
size1 = size;
|
|
Packit |
4a16fb |
if (size1 > ladspa->allocated)
|
|
Packit |
4a16fb |
size1 = ladspa->allocated;
|
|
Packit |
4a16fb |
list_for_each(pos, &ladspa->pplugins) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list);
|
|
Packit |
4a16fb |
list_for_each(pos1, &plugin->instances) {
|
|
Packit |
4a16fb |
instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list);
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->input.channels.size; idx++) {
|
|
Packit |
4a16fb |
chn = instance->input.channels.array[idx];
|
|
Packit |
4a16fb |
data = instance->input.data[idx];
|
|
Packit |
4a16fb |
if (data == NULL) {
|
|
Packit |
4a16fb |
data = (LADSPA_Data *)((char *)areas[chn].addr + (areas[chn].first / 8));
|
|
Packit |
4a16fb |
data += offset;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
instance->desc->connect_port(instance->handle, instance->input.ports.array[idx], data);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->output.channels.size; idx++) {
|
|
Packit |
4a16fb |
chn = instance->output.channels.array[idx];
|
|
Packit |
4a16fb |
data = instance->output.data[idx];
|
|
Packit |
4a16fb |
if (data == NULL) {
|
|
Packit |
4a16fb |
data = (LADSPA_Data *)((char *)slave_areas[chn].addr + (areas[chn].first / 8));
|
|
Packit |
4a16fb |
data += slave_offset;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
instance->desc->connect_port(instance->handle, instance->output.ports.array[idx], data);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
instance->desc->run(instance->handle, size1);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
offset += size1;
|
|
Packit |
4a16fb |
slave_offset += size1;
|
|
Packit |
4a16fb |
size -= size1;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
#endif
|
|
Packit |
4a16fb |
*slave_sizep = size2;
|
|
Packit |
4a16fb |
return size2;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static snd_pcm_uframes_t
|
|
Packit |
4a16fb |
snd_pcm_ladspa_read_areas(snd_pcm_t *pcm,
|
|
Packit |
4a16fb |
const snd_pcm_channel_area_t *areas,
|
|
Packit |
4a16fb |
snd_pcm_uframes_t offset,
|
|
Packit |
4a16fb |
snd_pcm_uframes_t size,
|
|
Packit |
4a16fb |
const snd_pcm_channel_area_t *slave_areas,
|
|
Packit |
4a16fb |
snd_pcm_uframes_t slave_offset,
|
|
Packit |
4a16fb |
snd_pcm_uframes_t *slave_sizep)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_pcm_ladspa_t *ladspa = pcm->private_data;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_instance_t *instance;
|
|
Packit |
4a16fb |
struct list_head *pos, *pos1;
|
|
Packit |
4a16fb |
LADSPA_Data *data;
|
|
Packit |
4a16fb |
unsigned int idx, chn, size1, size2;;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (size > *slave_sizep)
|
|
Packit |
4a16fb |
size = *slave_sizep;
|
|
Packit |
4a16fb |
size2 = size;
|
|
Packit |
4a16fb |
#if 0 /* no processing - for testing purposes only */
|
|
Packit |
4a16fb |
snd_pcm_areas_copy(areas, offset,
|
|
Packit |
4a16fb |
slave_areas, slave_offset,
|
|
Packit |
4a16fb |
pcm->channels, size, pcm->format);
|
|
Packit |
4a16fb |
#else
|
|
Packit |
4a16fb |
while (size > 0) {
|
|
Packit |
4a16fb |
size1 = size;
|
|
Packit |
4a16fb |
if (size1 > ladspa->allocated)
|
|
Packit |
4a16fb |
size1 = ladspa->allocated;
|
|
Packit |
4a16fb |
list_for_each(pos, &ladspa->cplugins) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list);
|
|
Packit |
4a16fb |
list_for_each(pos1, &plugin->instances) {
|
|
Packit |
4a16fb |
instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list);
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->input.channels.size; idx++) {
|
|
Packit |
4a16fb |
chn = instance->input.channels.array[idx];
|
|
Packit |
4a16fb |
data = instance->input.data[idx];
|
|
Packit |
4a16fb |
if (data == NULL) {
|
|
Packit |
4a16fb |
data = (LADSPA_Data *)((char *)slave_areas[chn].addr + (areas[chn].first / 8));
|
|
Packit |
4a16fb |
data += slave_offset;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
instance->desc->connect_port(instance->handle, instance->input.ports.array[idx], data);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
for (idx = 0; idx < instance->output.channels.size; idx++) {
|
|
Packit |
4a16fb |
chn = instance->output.channels.array[idx];
|
|
Packit |
4a16fb |
data = instance->output.data[idx];
|
|
Packit |
4a16fb |
if (data == NULL) {
|
|
Packit |
4a16fb |
data = (LADSPA_Data *)((char *)areas[chn].addr + (areas[chn].first / 8));
|
|
Packit |
4a16fb |
data += offset;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
instance->desc->connect_port(instance->handle, instance->output.ports.array[idx], data);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
instance->desc->run(instance->handle, size1);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
offset += size1;
|
|
Packit |
4a16fb |
slave_offset += size1;
|
|
Packit |
4a16fb |
size -= size1;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
#endif
|
|
Packit |
4a16fb |
*slave_sizep = size2;
|
|
Packit |
4a16fb |
return size2;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static void snd_pcm_ladspa_dump_direction(snd_pcm_ladspa_plugin_t *plugin,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t *io,
|
|
Packit |
4a16fb |
snd_output_t *out)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int idx, midx;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (io->port_bindings_size == 0)
|
|
Packit |
4a16fb |
goto __control;
|
|
Packit |
4a16fb |
snd_output_printf(out, " Audio %s port bindings:\n", io->pdesc == LADSPA_PORT_INPUT ? "input" : "output");
|
|
Packit |
4a16fb |
for (idx = 0; idx < io->port_bindings_size; idx++) {
|
|
Packit |
4a16fb |
if (io->port_bindings[idx] == NO_ASSIGN)
|
|
Packit |
4a16fb |
snd_output_printf(out, " %i -> NONE\n", idx);
|
|
Packit |
4a16fb |
else
|
|
Packit |
4a16fb |
snd_output_printf(out, " %i -> %i\n", idx, io->port_bindings[idx]);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
__control:
|
|
Packit |
4a16fb |
if (io->controls_size == 0)
|
|
Packit |
4a16fb |
return;
|
|
Packit |
4a16fb |
snd_output_printf(out, " Control %s port initial values:\n", io->pdesc == LADSPA_PORT_INPUT ? "input" : "output");
|
|
Packit |
4a16fb |
for (idx = midx = 0; idx < plugin->desc->PortCount; idx++) {
|
|
Packit |
4a16fb |
if ((plugin->desc->PortDescriptors[idx] & (io->pdesc | LADSPA_PORT_CONTROL)) == (io->pdesc | LADSPA_PORT_CONTROL)) {
|
|
Packit |
4a16fb |
snd_output_printf(out, " %i \"%s\" = %.8f\n", idx, plugin->desc->PortNames[idx], io->controls[midx]);
|
|
Packit |
4a16fb |
midx++;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static void snd_pcm_ladspa_dump_array(snd_output_t *out,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_array_t *array,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *plugin)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int size = array->size;
|
|
Packit |
4a16fb |
unsigned int val, idx = 0;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
while (size-- > 0) {
|
|
Packit |
4a16fb |
if (idx > 0) {
|
|
Packit |
4a16fb |
snd_output_putc(out, ',');
|
|
Packit |
4a16fb |
snd_output_putc(out, ' ');
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
val = array->array[idx++];
|
|
Packit |
4a16fb |
if (val == NO_ASSIGN)
|
|
Packit |
4a16fb |
snd_output_putc(out, '-');
|
|
Packit |
4a16fb |
else
|
|
Packit |
4a16fb |
snd_output_printf(out, "%u", val);
|
|
Packit |
4a16fb |
if (plugin && val != NO_ASSIGN)
|
|
Packit |
4a16fb |
snd_output_printf(out, " \"%s\"", plugin->desc->PortNames[val]);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static void snd_pcm_ladspa_plugins_dump(struct list_head *list, snd_output_t *out)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
struct list_head *pos, *pos2;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
list_for_each(pos, list) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list);
|
|
Packit |
4a16fb |
snd_output_printf(out, " Policy: %s\n", plugin->policy == SND_PCM_LADSPA_POLICY_NONE ? "none" : "duplicate");
|
|
Packit |
4a16fb |
snd_output_printf(out, " Filename: %s\n", plugin->filename);
|
|
Packit |
4a16fb |
snd_output_printf(out, " Plugin Name: %s\n", plugin->desc->Name);
|
|
Packit |
4a16fb |
snd_output_printf(out, " Plugin Label: %s\n", plugin->desc->Label);
|
|
Packit |
4a16fb |
snd_output_printf(out, " Plugin Unique ID: %lu\n", plugin->desc->UniqueID);
|
|
Packit |
4a16fb |
snd_output_printf(out, " Instances:\n");
|
|
Packit |
4a16fb |
list_for_each(pos2, &plugin->instances) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_instance_t *in = (snd_pcm_ladspa_instance_t *) pos2;
|
|
Packit |
4a16fb |
snd_output_printf(out, " Depth: %i\n", in->depth);
|
|
Packit |
4a16fb |
snd_output_printf(out, " InChannels: ");
|
|
Packit |
4a16fb |
snd_pcm_ladspa_dump_array(out, &in->input.channels, NULL);
|
|
Packit |
4a16fb |
snd_output_printf(out, "\n InPorts: ");
|
|
Packit |
4a16fb |
snd_pcm_ladspa_dump_array(out, &in->input.ports, plugin);
|
|
Packit |
4a16fb |
snd_output_printf(out, "\n OutChannels: ");
|
|
Packit |
4a16fb |
snd_pcm_ladspa_dump_array(out, &in->output.channels, NULL);
|
|
Packit |
4a16fb |
snd_output_printf(out, "\n OutPorts: ");
|
|
Packit |
4a16fb |
snd_pcm_ladspa_dump_array(out, &in->output.ports, plugin);
|
|
Packit |
4a16fb |
snd_output_printf(out, "\n");
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
snd_pcm_ladspa_dump_direction(plugin, &plugin->input, out);
|
|
Packit |
4a16fb |
snd_pcm_ladspa_dump_direction(plugin, &plugin->output, out);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static void snd_pcm_ladspa_dump(snd_pcm_t *pcm, snd_output_t *out)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_pcm_ladspa_t *ladspa = pcm->private_data;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_output_printf(out, "LADSPA PCM\n");
|
|
Packit |
4a16fb |
snd_output_printf(out, " Playback:\n");
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugins_dump(&ladspa->pplugins, out);
|
|
Packit |
4a16fb |
snd_output_printf(out, " Capture:\n");
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugins_dump(&ladspa->cplugins, out);
|
|
Packit |
4a16fb |
if (pcm->setup) {
|
|
Packit |
4a16fb |
snd_output_printf(out, "Its setup is:\n");
|
|
Packit |
4a16fb |
snd_pcm_dump_setup(pcm, out);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
snd_output_printf(out, "Slave: ");
|
|
Packit |
4a16fb |
snd_pcm_dump(ladspa->plug.gen.slave, out);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static const snd_pcm_ops_t snd_pcm_ladspa_ops = {
|
|
Packit |
4a16fb |
.close = snd_pcm_ladspa_close,
|
|
Packit |
4a16fb |
.info = snd_pcm_generic_info,
|
|
Packit |
4a16fb |
.hw_refine = snd_pcm_ladspa_hw_refine,
|
|
Packit |
4a16fb |
.hw_params = snd_pcm_ladspa_hw_params,
|
|
Packit |
4a16fb |
.hw_free = snd_pcm_ladspa_hw_free,
|
|
Packit |
4a16fb |
.sw_params = snd_pcm_generic_sw_params,
|
|
Packit |
4a16fb |
.channel_info = snd_pcm_generic_channel_info,
|
|
Packit |
4a16fb |
.dump = snd_pcm_ladspa_dump,
|
|
Packit |
4a16fb |
.nonblock = snd_pcm_generic_nonblock,
|
|
Packit |
4a16fb |
.async = snd_pcm_generic_async,
|
|
Packit |
4a16fb |
.mmap = snd_pcm_generic_mmap,
|
|
Packit |
4a16fb |
.munmap = snd_pcm_generic_munmap,
|
|
Packit |
4a16fb |
.query_chmaps = snd_pcm_generic_query_chmaps,
|
|
Packit |
4a16fb |
.get_chmap = snd_pcm_generic_get_chmap,
|
|
Packit |
4a16fb |
.set_chmap = snd_pcm_generic_set_chmap,
|
|
Packit |
4a16fb |
};
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_check_file(snd_pcm_ladspa_plugin_t * const plugin,
|
|
Packit |
4a16fb |
const char *filename,
|
|
Packit |
4a16fb |
const char *label,
|
|
Packit |
4a16fb |
const unsigned long ladspa_id)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
void *handle;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
assert(filename);
|
|
Packit |
4a16fb |
handle = dlopen(filename, RTLD_LAZY);
|
|
Packit |
4a16fb |
if (handle) {
|
|
Packit |
4a16fb |
LADSPA_Descriptor_Function fcn = (LADSPA_Descriptor_Function)dlsym(handle, "ladspa_descriptor");
|
|
Packit |
4a16fb |
if (fcn) {
|
|
Packit |
4a16fb |
long idx;
|
|
Packit |
4a16fb |
const LADSPA_Descriptor *d;
|
|
Packit |
4a16fb |
for (idx = 0; (d = fcn(idx)) != NULL; idx++) {
|
|
Packit |
4a16fb |
/*
|
|
Packit |
4a16fb |
* avoid locale problems - see ALSA bug#1553
|
|
Packit |
4a16fb |
*/
|
|
Packit |
4a16fb |
#if 0
|
|
Packit |
4a16fb |
if (strcmp(label, d->Label))
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
#else
|
|
Packit |
4a16fb |
char *labellocale;
|
|
Packit |
4a16fb |
struct lconv *lc;
|
|
Packit |
4a16fb |
if (label != NULL) {
|
|
Packit |
4a16fb |
lc = localeconv ();
|
|
Packit |
4a16fb |
labellocale = malloc (strlen (label) + 1);
|
|
Packit |
4a16fb |
if (labellocale == NULL) {
|
|
Packit |
4a16fb |
dlclose(handle);
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
strcpy (labellocale, label);
|
|
Packit |
4a16fb |
if (strrchr(labellocale, '.'))
|
|
Packit |
4a16fb |
*strrchr (labellocale, '.') = *lc->decimal_point;
|
|
Packit |
4a16fb |
if (strcmp(label, d->Label) && strcmp(labellocale, d->Label)) {
|
|
Packit |
4a16fb |
free(labellocale);
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
free (labellocale);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
#endif
|
|
Packit |
4a16fb |
if (ladspa_id > 0 && d->UniqueID != ladspa_id)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
plugin->filename = strdup(filename);
|
|
Packit |
4a16fb |
if (plugin->filename == NULL) {
|
|
Packit |
4a16fb |
dlclose(handle);
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
plugin->dl_handle = handle;
|
|
Packit |
4a16fb |
plugin->desc = d;
|
|
Packit |
4a16fb |
return 1;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
dlclose(handle);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return -ENOENT;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_check_dir(snd_pcm_ladspa_plugin_t * const plugin,
|
|
Packit |
4a16fb |
const char *path,
|
|
Packit |
4a16fb |
const char *label,
|
|
Packit |
4a16fb |
const unsigned long ladspa_id)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
DIR *dir;
|
|
Packit |
4a16fb |
struct dirent * dirent;
|
|
Packit |
4a16fb |
int len = strlen(path), err;
|
|
Packit |
4a16fb |
int need_slash;
|
|
Packit |
4a16fb |
char *filename;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (len < 1)
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
need_slash = path[len - 1] != '/';
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
dir = opendir(path);
|
|
Packit |
4a16fb |
if (!dir)
|
|
Packit |
4a16fb |
return -ENOENT;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
while (1) {
|
|
Packit |
4a16fb |
dirent = readdir(dir);
|
|
Packit |
4a16fb |
if (!dirent) {
|
|
Packit |
4a16fb |
closedir(dir);
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
filename = malloc(len + strlen(dirent->d_name) + 1 + need_slash);
|
|
Packit |
4a16fb |
if (filename == NULL) {
|
|
Packit |
4a16fb |
closedir(dir);
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
strcpy(filename, path);
|
|
Packit |
4a16fb |
if (need_slash)
|
|
Packit |
4a16fb |
strcat(filename, "/");
|
|
Packit |
4a16fb |
strcat(filename, dirent->d_name);
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_check_file(plugin, filename, label, ladspa_id);
|
|
Packit |
4a16fb |
free(filename);
|
|
Packit |
4a16fb |
if (err < 0 && err != -ENOENT) {
|
|
Packit |
4a16fb |
closedir(dir);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (err > 0) {
|
|
Packit |
4a16fb |
closedir(dir);
|
|
Packit |
4a16fb |
return 1;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
/* never reached */
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_look_for_plugin(snd_pcm_ladspa_plugin_t * const plugin,
|
|
Packit |
4a16fb |
const char *path,
|
|
Packit |
4a16fb |
const char *label,
|
|
Packit |
4a16fb |
const long ladspa_id)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
const char *c;
|
|
Packit |
4a16fb |
size_t l;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
for (c = path; (l = strcspn(c, ": ")) > 0; ) {
|
|
Packit |
4a16fb |
char name[l + 1];
|
|
Packit |
4a16fb |
char *fullpath;
|
|
Packit |
4a16fb |
memcpy(name, c, l);
|
|
Packit |
4a16fb |
name[l] = 0;
|
|
Packit |
4a16fb |
err = snd_user_file(name, &fullpath);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_check_dir(plugin, fullpath, label, ladspa_id);
|
|
Packit |
4a16fb |
free(fullpath);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
if (err > 0)
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
c += l;
|
|
Packit |
4a16fb |
if (!*c)
|
|
Packit |
4a16fb |
break;
|
|
Packit |
4a16fb |
c++;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return -ENOENT;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_add_default_controls(snd_pcm_ladspa_plugin_t *lplug,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t *io)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int count = 0;
|
|
Packit |
4a16fb |
LADSPA_Data *array;
|
|
Packit |
4a16fb |
unsigned char *initialized;
|
|
Packit |
4a16fb |
unsigned long idx;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
for (idx = 0; idx < lplug->desc->PortCount; idx++)
|
|
Packit |
4a16fb |
if ((lplug->desc->PortDescriptors[idx] & (io->pdesc | LADSPA_PORT_CONTROL)) == (io->pdesc | LADSPA_PORT_CONTROL))
|
|
Packit |
4a16fb |
count++;
|
|
Packit |
4a16fb |
array = (LADSPA_Data *)calloc(count, sizeof(LADSPA_Data));
|
|
Packit |
4a16fb |
if (!array)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
initialized = (unsigned char *)calloc(count, sizeof(unsigned char));
|
|
Packit |
4a16fb |
if (!initialized) {
|
|
Packit |
4a16fb |
free(array);
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
io->controls_size = count;
|
|
Packit |
4a16fb |
io->controls_initialized = initialized;
|
|
Packit |
4a16fb |
io->controls = array;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_parse_controls(snd_pcm_ladspa_plugin_t *lplug,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t *io,
|
|
Packit |
4a16fb |
snd_config_t *controls)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (snd_config_get_type(controls) != SND_CONFIG_TYPE_COMPOUND) {
|
|
Packit |
4a16fb |
SNDERR("controls definition must be a compound");
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, controls) {
|
|
Packit |
4a16fb |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
const char *id;
|
|
Packit |
4a16fb |
long lval;
|
|
Packit |
4a16fb |
unsigned int port, uval;
|
|
Packit |
4a16fb |
double dval;
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
err = safe_strtol(id, &lval);
|
|
Packit |
4a16fb |
if (err >= 0) {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_find_port(&port, lplug, io->pdesc | LADSPA_PORT_CONTROL, lval);
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_find_sport(&port, lplug, io->pdesc | LADSPA_PORT_CONTROL, id);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("Unable to find an control port (%s)", id);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (snd_config_get_ireal(n, &dval) < 0) {
|
|
Packit |
4a16fb |
SNDERR("Control port %s has not an float or integer value", id);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_find_port_idx(&uval, lplug, io->pdesc | LADSPA_PORT_CONTROL, port);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("internal error");
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
io->controls_initialized[uval] = 1;
|
|
Packit |
4a16fb |
io->controls[uval] = (LADSPA_Data)dval;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_parse_bindings(snd_pcm_ladspa_plugin_t *lplug,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t *io,
|
|
Packit |
4a16fb |
snd_config_t *bindings)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
unsigned int count = 0;
|
|
Packit |
4a16fb |
unsigned int *array;
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (snd_config_get_type(bindings) != SND_CONFIG_TYPE_COMPOUND) {
|
|
Packit |
4a16fb |
SNDERR("bindings definition must be a compound");
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, bindings) {
|
|
Packit |
4a16fb |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
const char *id;
|
|
Packit |
4a16fb |
long channel;
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
err = safe_strtol(id, &channel);
|
|
Packit |
4a16fb |
if (err < 0 || channel < 0) {
|
|
Packit |
4a16fb |
SNDERR("Invalid channel number: %s", id);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (lplug->policy == SND_PCM_LADSPA_POLICY_DUPLICATE && channel > 0) {
|
|
Packit |
4a16fb |
SNDERR("Wrong channel specification for duplicate policy");
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (count < (unsigned int)(channel + 1))
|
|
Packit |
4a16fb |
count = (unsigned int)(channel + 1);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (count > 0) {
|
|
Packit |
4a16fb |
array = (unsigned int *)malloc(count * sizeof(unsigned int));
|
|
Packit |
4a16fb |
if (! array)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
memset(array, 0xff, count * sizeof(unsigned int));
|
|
Packit |
4a16fb |
io->port_bindings_size = count;
|
|
Packit |
4a16fb |
io->port_bindings = array;
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, bindings) {
|
|
Packit |
4a16fb |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
const char *id, *sport;
|
|
Packit |
4a16fb |
long channel, port;
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
err = safe_strtol(id, &channel);
|
|
Packit |
4a16fb |
if (err < 0 || channel < 0) {
|
|
Packit |
4a16fb |
assert(0); /* should never happen */
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_config_get_integer(n, &port);
|
|
Packit |
4a16fb |
if (err >= 0) {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_find_port(&array[channel], lplug, io->pdesc | LADSPA_PORT_AUDIO, port);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("Unable to find an audio port (%li) for channel %s", port, id);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_config_get_string(n, &sport);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("Invalid LADSPA port field type for %s", id);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_find_sport(&array[channel], lplug, io->pdesc | LADSPA_PORT_AUDIO, sport);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("Unable to find an audio port (%s) for channel %s", sport, id);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_parse_ioconfig(snd_pcm_ladspa_plugin_t *lplug,
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_io_t *io,
|
|
Packit |
4a16fb |
snd_config_t *conf)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
snd_config_t *bindings = NULL, *controls = NULL;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* always add default controls for both input and output */
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_add_default_controls(lplug, io);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("error adding default controls");
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (conf == NULL) {
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) {
|
|
Packit |
4a16fb |
SNDERR("input or output definition must be a compound");
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, conf) {
|
|
Packit |
4a16fb |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
const char *id;
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
if (strcmp(id, "bindings") == 0) {
|
|
Packit |
4a16fb |
bindings = n;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(id, "controls") == 0) {
|
|
Packit |
4a16fb |
controls = n;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/* ignore values of parameters for output controls */
|
|
Packit |
4a16fb |
if (controls && !(io->pdesc & LADSPA_PORT_OUTPUT)) {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_parse_controls(lplug, io, controls);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (bindings) {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_parse_bindings(lplug, io, bindings);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_add_plugin(struct list_head *list,
|
|
Packit |
4a16fb |
const char *path,
|
|
Packit |
4a16fb |
snd_config_t *plugin,
|
|
Packit |
4a16fb |
int reverse)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
const char *label = NULL, *filename = NULL;
|
|
Packit |
4a16fb |
long ladspa_id = 0;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_plugin_t *lplug;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_policy_t policy = SND_PCM_LADSPA_POLICY_DUPLICATE;
|
|
Packit |
4a16fb |
snd_config_t *input = NULL, *output = NULL;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, plugin) {
|
|
Packit |
4a16fb |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
const char *id;
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
if (strcmp(id, "label") == 0) {
|
|
Packit |
4a16fb |
err = snd_config_get_string(n, &label);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(id, "id") == 0) {
|
|
Packit |
4a16fb |
err = snd_config_get_integer(n, &ladspa_id);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(id, "filename") == 0) {
|
|
Packit |
4a16fb |
err = snd_config_get_string(n, &filename);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(id, "input") == 0) {
|
|
Packit |
4a16fb |
input = n;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(id, "output") == 0) {
|
|
Packit |
4a16fb |
output = n;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(id, "policy") == 0) {
|
|
Packit |
4a16fb |
const char *str;
|
|
Packit |
4a16fb |
err = snd_config_get_string(n, &str);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("policy field must be a string");
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(str, "none") == 0)
|
|
Packit |
4a16fb |
policy = SND_PCM_LADSPA_POLICY_NONE;
|
|
Packit |
4a16fb |
else if (strcmp(str, "duplicate") == 0)
|
|
Packit |
4a16fb |
policy = SND_PCM_LADSPA_POLICY_DUPLICATE;
|
|
Packit |
4a16fb |
else {
|
|
Packit |
4a16fb |
SNDERR("unknown policy definition");
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (label == NULL && ladspa_id <= 0) {
|
|
Packit |
4a16fb |
SNDERR("no plugin label or id");
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
lplug = (snd_pcm_ladspa_plugin_t *)calloc(1, sizeof(snd_pcm_ladspa_plugin_t));
|
|
Packit |
4a16fb |
if (lplug == NULL)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
lplug->policy = policy;
|
|
Packit |
4a16fb |
lplug->input.pdesc = LADSPA_PORT_INPUT;
|
|
Packit |
4a16fb |
lplug->output.pdesc = LADSPA_PORT_OUTPUT;
|
|
Packit |
4a16fb |
INIT_LIST_HEAD(&lplug->instances);
|
|
Packit |
4a16fb |
if (filename) {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_check_file(lplug, filename, label, ladspa_id);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("Unable to load plugin '%s' ID %li, filename '%s'", label, ladspa_id, filename);
|
|
Packit |
4a16fb |
free(lplug);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_look_for_plugin(lplug, path, label, ladspa_id);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("Unable to find or load plugin '%s' ID %li, path '%s'", label, ladspa_id, path);
|
|
Packit |
4a16fb |
free(lplug);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (!reverse) {
|
|
Packit |
4a16fb |
list_add_tail(&lplug->list, list);
|
|
Packit |
4a16fb |
} else {
|
|
Packit |
4a16fb |
list_add(&lplug->list, list);
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_parse_ioconfig(lplug, &lplug->input, input);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_parse_ioconfig(lplug, &lplug->output, output);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
static int snd_pcm_ladspa_build_plugins(struct list_head *list,
|
|
Packit |
4a16fb |
const char *path,
|
|
Packit |
4a16fb |
snd_config_t *plugins,
|
|
Packit |
4a16fb |
int reverse)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
int idx = 0, hit, err;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (plugins == NULL) /* nothing TODO */
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
if (snd_config_get_type(plugins) != SND_CONFIG_TYPE_COMPOUND) {
|
|
Packit |
4a16fb |
SNDERR("plugins must be defined inside a compound");
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
do {
|
|
Packit |
4a16fb |
hit = 0;
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, plugins) {
|
|
Packit |
4a16fb |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
const char *id;
|
|
Packit |
4a16fb |
long i;
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
err = safe_strtol(id, &i);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
SNDERR("id of field %s is not an integer", id);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (i == idx) {
|
|
Packit |
4a16fb |
idx++;
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_add_plugin(list, path, n, reverse);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
hit = 1;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
} while (hit);
|
|
Packit |
4a16fb |
if (list_empty(list)) {
|
|
Packit |
4a16fb |
SNDERR("empty plugin list is not accepted");
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/**
|
|
Packit |
4a16fb |
* \brief Creates a new LADSPA<->ALSA Plugin
|
|
Packit |
4a16fb |
* \param pcmp Returns created PCM handle
|
|
Packit |
4a16fb |
* \param name Name of PCM
|
|
Packit |
4a16fb |
* \param ladspa_path The path for LADSPA plugins
|
|
Packit |
4a16fb |
* \param channels Force input channel count to LADSPA plugin chain, 0 = no force (auto)
|
|
Packit |
4a16fb |
* \param ladspa_pplugins The playback configuration
|
|
Packit |
4a16fb |
* \param ladspa_cplugins The capture configuration
|
|
Packit |
4a16fb |
* \param slave Slave PCM handle
|
|
Packit |
4a16fb |
* \param close_slave When set, the slave PCM handle is closed with copy PCM
|
|
Packit |
4a16fb |
* \retval zero on success otherwise a negative error code
|
|
Packit |
4a16fb |
* \warning Using of this function might be dangerous in the sense
|
|
Packit |
4a16fb |
* of compatibility reasons. The prototype might be freely
|
|
Packit |
4a16fb |
* changed in future.
|
|
Packit |
4a16fb |
*/
|
|
Packit |
4a16fb |
int snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name,
|
|
Packit |
4a16fb |
const char *ladspa_path,
|
|
Packit |
4a16fb |
unsigned int channels,
|
|
Packit |
4a16fb |
snd_config_t *ladspa_pplugins,
|
|
Packit |
4a16fb |
snd_config_t *ladspa_cplugins,
|
|
Packit |
4a16fb |
snd_pcm_t *slave, int close_slave)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_pcm_t *pcm;
|
|
Packit |
4a16fb |
snd_pcm_ladspa_t *ladspa;
|
|
Packit |
4a16fb |
int err, reverse = 0;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
assert(pcmp && (ladspa_pplugins || ladspa_cplugins) && slave);
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (!ladspa_path && !(ladspa_path = getenv("LADSPA_PATH")))
|
|
Packit |
4a16fb |
return -ENOENT;
|
|
Packit |
4a16fb |
ladspa = calloc(1, sizeof(snd_pcm_ladspa_t));
|
|
Packit |
4a16fb |
if (!ladspa)
|
|
Packit |
4a16fb |
return -ENOMEM;
|
|
Packit |
4a16fb |
snd_pcm_plugin_init(&ladspa->plug);
|
|
Packit |
4a16fb |
ladspa->plug.init = snd_pcm_ladspa_init;
|
|
Packit |
4a16fb |
ladspa->plug.read = snd_pcm_ladspa_read_areas;
|
|
Packit |
4a16fb |
ladspa->plug.write = snd_pcm_ladspa_write_areas;
|
|
Packit |
4a16fb |
ladspa->plug.undo_read = snd_pcm_plugin_undo_read_generic;
|
|
Packit |
4a16fb |
ladspa->plug.undo_write = snd_pcm_plugin_undo_write_generic;
|
|
Packit |
4a16fb |
ladspa->plug.gen.slave = slave;
|
|
Packit |
4a16fb |
ladspa->plug.gen.close_slave = close_slave;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
INIT_LIST_HEAD(&ladspa->pplugins);
|
|
Packit |
4a16fb |
INIT_LIST_HEAD(&ladspa->cplugins);
|
|
Packit |
4a16fb |
ladspa->channels = channels;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
if (slave->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_build_plugins(&ladspa->pplugins, ladspa_path, ladspa_pplugins, reverse);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free(ladspa);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (slave->stream == SND_PCM_STREAM_CAPTURE) {
|
|
Packit |
4a16fb |
if (ladspa_cplugins == ladspa_pplugins)
|
|
Packit |
4a16fb |
reverse = 1;
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_build_plugins(&ladspa->cplugins, ladspa_path, ladspa_cplugins, reverse);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free(ladspa);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
err = snd_pcm_new(&pcm, SND_PCM_TYPE_LADSPA, name, slave->stream, slave->mode);
|
|
Packit |
4a16fb |
if (err < 0) {
|
|
Packit |
4a16fb |
snd_pcm_ladspa_free(ladspa);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
pcm->ops = &snd_pcm_ladspa_ops;
|
|
Packit |
4a16fb |
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
|
|
Packit |
4a16fb |
pcm->private_data = ladspa;
|
|
Packit |
4a16fb |
pcm->poll_fd = slave->poll_fd;
|
|
Packit |
4a16fb |
pcm->poll_events = slave->poll_events;
|
|
Packit |
4a16fb |
pcm->tstamp_type = slave->tstamp_type;
|
|
Packit |
4a16fb |
snd_pcm_set_hw_ptr(pcm, &ladspa->plug.hw_ptr, -1, 0);
|
|
Packit |
4a16fb |
snd_pcm_set_appl_ptr(pcm, &ladspa->plug.appl_ptr, -1, 0);
|
|
Packit |
4a16fb |
*pcmp = pcm;
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
return 0;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/*! \page pcm_plugins
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
\section pcm_plugins_ladpsa Plugin: LADSPA <-> ALSA
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
This plugin allows to apply a set of LADPSA plugins.
|
|
Packit |
4a16fb |
The input and output format is always #SND_PCM_FORMAT_FLOAT (note: this type
|
|
Packit |
4a16fb |
can be either little or big-endian depending on architecture).
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
The policy duplicate means that there must be only one binding definition for
|
|
Packit |
4a16fb |
channel zero. This definition is automatically duplicated for all channels.
|
|
Packit |
4a16fb |
If the LADSPA plugin has multiple audio inputs or outputs the policy duplicate
|
|
Packit |
4a16fb |
is automatically switched to policy none.
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
The plugin serialization works as expected. You can eventually use more
|
|
Packit |
4a16fb |
channels (inputs / outputs) inside the LADPSA plugin chain than processed
|
|
Packit |
4a16fb |
in the ALSA plugin chain. If ALSA channel does not exist for given LADSPA
|
|
Packit |
4a16fb |
input audio port, zero samples are given to this LADSPA port. On the output
|
|
Packit |
4a16fb |
side (ALSA next plugin input), the valid channels are checked, too.
|
|
Packit |
4a16fb |
If specific ALSA channel does not exist, the LADSPA output port is
|
|
Packit |
4a16fb |
connected to a dummy sample area.
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
Instances of LADSPA plugins are created dynamically.
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
\code
|
|
Packit |
4a16fb |
pcm.name {
|
|
Packit |
4a16fb |
type ladspa # ALSA<->LADSPA PCM
|
|
Packit |
4a16fb |
slave STR # Slave name
|
|
Packit |
4a16fb |
# or
|
|
Packit |
4a16fb |
slave { # Slave definition
|
|
Packit |
4a16fb |
pcm STR # Slave PCM name
|
|
Packit |
4a16fb |
# or
|
|
Packit |
4a16fb |
pcm { } # Slave PCM definition
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
[channels INT] # count input channels (input to LADSPA plugin chain)
|
|
Packit |
4a16fb |
[path STR] # Path (directory) with LADSPA plugins
|
|
Packit |
4a16fb |
plugins | # Definition for both directions
|
|
Packit |
4a16fb |
playback_plugins | # Definition for playback direction
|
|
Packit |
4a16fb |
capture_plugins { # Definition for capture direction
|
|
Packit |
4a16fb |
N { # Configuration for LADPSA plugin N
|
|
Packit |
4a16fb |
[id INT] # LADSPA plugin ID (for example 1043)
|
|
Packit |
4a16fb |
[label STR] # LADSPA plugin label (for example 'delay_5s')
|
|
Packit |
4a16fb |
[filename STR] # Full filename of .so library with LADSPA plugin code
|
|
Packit |
4a16fb |
[policy STR] # Policy can be 'none' or 'duplicate'
|
|
Packit |
4a16fb |
input | output {
|
|
Packit |
4a16fb |
bindings {
|
|
Packit |
4a16fb |
C INT or STR # C - channel, INT - audio port index, STR - audio port name
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
controls {
|
|
Packit |
4a16fb |
# valid only in the input block
|
|
Packit |
4a16fb |
I INT or REAL # I - control port index, INT or REAL - control value
|
|
Packit |
4a16fb |
# or
|
|
Packit |
4a16fb |
STR INT or REAL # STR - control port name, INT or REAL - control value
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
\endcode
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
\subsection pcm_plugins_ladspa_funcref Function reference
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
snd_pcm_ladspa_open()
|
|
Packit |
4a16fb |
_snd_pcm_ladspa_open()
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
*/
|
|
Packit |
4a16fb |
|
|
Packit |
4a16fb |
/**
|
|
Packit |
4a16fb |
* \brief Creates a new LADSPA<->ALSA PCM
|
|
Packit |
4a16fb |
* \param pcmp Returns created PCM handle
|
|
Packit |
4a16fb |
* \param name Name of PCM
|
|
Packit |
4a16fb |
* \param root Root configuration node
|
|
Packit |
4a16fb |
* \param conf Configuration node with LADSPA<->ALSA PCM description
|
|
Packit |
4a16fb |
* \param stream Stream type
|
|
Packit |
4a16fb |
* \param mode Stream mode
|
|
Packit |
4a16fb |
* \retval zero on success otherwise a negative error code
|
|
Packit |
4a16fb |
* \warning Using of this function might be dangerous in the sense
|
|
Packit |
4a16fb |
* of compatibility reasons. The prototype might be freely
|
|
Packit |
4a16fb |
* changed in future.
|
|
Packit |
4a16fb |
*/
|
|
Packit |
4a16fb |
int _snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name,
|
|
Packit |
4a16fb |
snd_config_t *root, snd_config_t *conf,
|
|
Packit |
4a16fb |
snd_pcm_stream_t stream, int mode)
|
|
Packit |
4a16fb |
{
|
|
Packit |
4a16fb |
snd_config_iterator_t i, next;
|
|
Packit |
4a16fb |
int err;
|
|
Packit |
4a16fb |
snd_pcm_t *spcm;
|
|
Packit |
4a16fb |
snd_config_t *slave = NULL, *sconf;
|
|
Packit |
4a16fb |
const char *path = NULL;
|
|
Packit |
4a16fb |
long channels = 0;
|
|
Packit |
4a16fb |
snd_config_t *plugins = NULL, *pplugins = NULL, *cplugins = NULL;
|
|
Packit |
4a16fb |
snd_config_for_each(i, next, conf) {
|
|
Packit |
4a16fb |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit |
4a16fb |
const char *id;
|
|
Packit |
4a16fb |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
if (snd_pcm_conf_generic_id(id))
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
if (strcmp(id, "slave") == 0) {
|
|
Packit |
4a16fb |
slave = n;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(id, "path") == 0) {
|
|
Packit |
4a16fb |
snd_config_get_string(n, &path);
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(id, "channels") == 0) {
|
|
Packit |
4a16fb |
snd_config_get_integer(n, &channels);
|
|
Packit |
4a16fb |
if (channels > 1024)
|
|
Packit |
4a16fb |
channels = 1024;
|
|
Packit |
4a16fb |
if (channels < 0)
|
|
Packit |
4a16fb |
channels = 0;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(id, "plugins") == 0) {
|
|
Packit |
4a16fb |
plugins = n;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(id, "playback_plugins") == 0) {
|
|
Packit |
4a16fb |
pplugins = n;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (strcmp(id, "capture_plugins") == 0) {
|
|
Packit |
4a16fb |
cplugins = n;
|
|
Packit |
4a16fb |
continue;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
SNDERR("Unknown field %s", id);
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (!slave) {
|
|
Packit |
4a16fb |
SNDERR("slave is not defined");
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
if (plugins) {
|
|
Packit |
4a16fb |
if (pplugins || cplugins) {
|
|
Packit |
4a16fb |
SNDERR("'plugins' definition cannot be combined with 'playback_plugins' or 'capture_plugins'");
|
|
Packit |
4a16fb |
return -EINVAL;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
pplugins = plugins;
|
|
Packit |
4a16fb |
cplugins = plugins;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
|
Packit |
4a16fb |
snd_config_delete(sconf);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
err = snd_pcm_ladspa_open(pcmp, name, path, channels, pplugins, cplugins, spcm, 1);
|
|
Packit |
4a16fb |
if (err < 0)
|
|
Packit |
4a16fb |
snd_pcm_close(spcm);
|
|
Packit |
4a16fb |
return err;
|
|
Packit |
4a16fb |
}
|
|
Packit |
4a16fb |
#ifndef DOC_HIDDEN
|
|
Packit |
4a16fb |
SND_DLSYM_BUILD_VERSION(_snd_pcm_ladspa_open, SND_PCM_DLSYM_VERSION);
|
|
Packit |
4a16fb |
#endif
|