Blame src/pcm/pcm_ladspa.c

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