Blame src/pcm/pcm_ladspa.c

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