mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-10-29 05:40:25 -04:00 
			
		
		
		
	Abramo Bagnara <abramo@alsa-project.org>
Sat, 11 Dec 1999 08:45:24 +0100 - changed lowlevel drivers to use pcm_misc.c functions - fixed some bugs in pcm_plugin_build - the plugin code is shared between alsa-lib and alsa-driver
This commit is contained in:
		
							parent
							
								
									0f0ce09509
								
							
						
					
					
						commit
						20ebae20a7
					
				
					 13 changed files with 596 additions and 508 deletions
				
			
		|  | @ -52,6 +52,7 @@ int snd_pcm_munmap(snd_pcm_t *handle, int channel); | |||
| 
 | ||||
| int snd_pcm_format_signed(int format); | ||||
| int snd_pcm_format_unsigned(int format); | ||||
| int snd_pcm_format_linear(int format); | ||||
| int snd_pcm_format_little_endian(int format); | ||||
| int snd_pcm_format_big_endian(int format); | ||||
| int snd_pcm_format_width(int format);		/* in bits */ | ||||
|  |  | |||
|  | @ -2,7 +2,8 @@ SUBDIRS = plugin | |||
| 
 | ||||
| EXTRA_LTLIBRARIES = libpcm.la | ||||
| 
 | ||||
| libpcm_la_SOURCES = pcm.c pcm_plugin.c pcm_misc.c pcm_loopback.c | ||||
| libpcm_la_SOURCES = pcm.c pcm_plugin.c pcm_plugin_build.c pcm_misc.c \ | ||||
| 		    pcm_loopback.c | ||||
| libpcm_la_LIBADD = plugin/libpcmplugin.la | ||||
| all: libpcm.la | ||||
| 
 | ||||
|  |  | |||
|  | @ -39,3 +39,19 @@ struct snd_pcm { | |||
| 	void *plugin_alloc_xptr[2]; | ||||
| 	long plugin_alloc_xsize[2]; | ||||
| }; | ||||
| 
 | ||||
| unsigned int snd_pcm_plugin_formats(unsigned int formats); | ||||
| int snd_pcm_plugin_hwparams(snd_pcm_channel_params_t *params, | ||||
| 			    snd_pcm_channel_info_t *hwinfo, | ||||
| 			    snd_pcm_channel_params_t *hwparams); | ||||
| int snd_pcm_plugin_format(snd_pcm_t *pcm,  | ||||
| 			  snd_pcm_channel_params_t *params,  | ||||
| 			  snd_pcm_channel_params_t *hwparams, | ||||
| 			  snd_pcm_channel_info_t *hwinfo); | ||||
| 
 | ||||
| #if 0 | ||||
| #define PLUGIN_DEBUG | ||||
| #define pdprintf( args... ) printf( "plugin: " ##args) | ||||
| #else | ||||
| #define pdprintf( args... ) { ; } | ||||
| #endif | ||||
|  |  | |||
|  | @ -19,15 +19,18 @@ | |||
|  * | ||||
|  */ | ||||
|    | ||||
| #ifdef ALSA_BUILD | ||||
| #include "../include/driver.h" | ||||
| #else | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/mman.h> | ||||
| #include <endian.h> | ||||
| #include <byteswap.h> | ||||
| #include "pcm_local.h" | ||||
| #endif | ||||
| 
 | ||||
| int snd_pcm_format_signed(int format) | ||||
| { | ||||
|  | @ -63,6 +66,11 @@ int snd_pcm_format_unsigned(int format) | |||
| 	return val; | ||||
| } | ||||
| 
 | ||||
| int snd_pcm_format_linear(int format) | ||||
| { | ||||
| 	return snd_pcm_format_signed(format) >= 0; | ||||
| } | ||||
| 
 | ||||
| int snd_pcm_format_little_endian(int format) | ||||
| { | ||||
| 	switch (format) { | ||||
|  |  | |||
|  | @ -162,65 +162,6 @@ snd_pcm_plugin_t *snd_pcm_plugin_last(snd_pcm_t *pcm, int channel) | |||
| 	return pcm->plugin_last[channel]; | ||||
| } | ||||
| 
 | ||||
| ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *pcm, int channel, size_t drv_size) | ||||
| { | ||||
| 	snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next; | ||||
| 	 | ||||
| 	if (!pcm || channel < 0 || channel > 1) | ||||
| 		return -EINVAL; | ||||
| 	if (drv_size == 0) | ||||
| 		return 0; | ||||
| 	if (drv_size < 0) | ||||
| 		return -EINVAL; | ||||
| 	if (channel == SND_PCM_CHANNEL_PLAYBACK) { | ||||
| 		plugin = snd_pcm_plugin_last(pcm, channel); | ||||
| 		while (plugin) { | ||||
| 			plugin_prev = plugin->prev; | ||||
| 			if (plugin->src_size) | ||||
| 				drv_size = plugin->src_size(plugin, drv_size); | ||||
| 			plugin = plugin_prev; | ||||
| 		} | ||||
| 	} else if (channel == SND_PCM_CHANNEL_CAPTURE) { | ||||
| 		plugin = snd_pcm_plugin_first(pcm, channel); | ||||
| 		while (plugin) { | ||||
| 			plugin_next = plugin->next; | ||||
| 			if (plugin->dst_size) | ||||
| 				drv_size = plugin->dst_size(plugin, drv_size); | ||||
| 			plugin = plugin_next; | ||||
| 		} | ||||
| 	} | ||||
| 	return drv_size; | ||||
| } | ||||
| 
 | ||||
| ssize_t snd_pcm_plugin_hardware_size(snd_pcm_t *pcm, int channel, size_t trf_size) | ||||
| { | ||||
| 	snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next; | ||||
| 	 | ||||
| 	if (!pcm || channel < 0 || channel > 1) | ||||
| 		return -EINVAL; | ||||
| 	if (trf_size == 0) | ||||
| 		return 0; | ||||
| 	if (trf_size < 0) | ||||
| 		return -EINVAL; | ||||
| 	if (channel == SND_PCM_CHANNEL_PLAYBACK) { | ||||
| 		plugin = snd_pcm_plugin_first(pcm, channel); | ||||
| 		while (plugin) { | ||||
| 			plugin_next = plugin->next; | ||||
| 			if (plugin->dst_size) | ||||
| 				trf_size = plugin->dst_size(plugin, trf_size); | ||||
| 			plugin = plugin_next; | ||||
| 		} | ||||
| 	} else if (channel == SND_PCM_CHANNEL_CAPTURE) { | ||||
| 		plugin = snd_pcm_plugin_last(pcm, channel); | ||||
| 		while (plugin) { | ||||
| 			plugin_prev = plugin->prev; | ||||
| 			if (plugin->src_size) | ||||
| 				trf_size = plugin->src_size(plugin, trf_size); | ||||
| 			plugin = plugin_prev; | ||||
| 		} | ||||
| 	}  | ||||
| 	return trf_size; | ||||
| } | ||||
| 
 | ||||
| double snd_pcm_plugin_transfer_ratio(snd_pcm_t *pcm, int channel) | ||||
| { | ||||
|  | @ -246,23 +187,13 @@ double snd_pcm_plugin_hardware_ratio(snd_pcm_t *pcm, int channel) | |||
|  * | ||||
|  */ | ||||
| 
 | ||||
| static unsigned int snd_pcm_plugin_formats(snd_pcm_t *pcm, unsigned int formats) | ||||
| { | ||||
| 	formats |= SND_PCM_FMT_MU_LAW | SND_PCM_FMT_A_LAW | SND_PCM_FMT_IMA_ADPCM; | ||||
| 	if (formats & (SND_PCM_FMT_U8|SND_PCM_FMT_S8| | ||||
| 		       SND_PCM_FMT_U16_LE|SND_PCM_FMT_S16_LE)) | ||||
| 		formats |= SND_PCM_FMT_U8|SND_PCM_FMT_S8| | ||||
| 			   SND_PCM_FMT_U16_LE|SND_PCM_FMT_S16_LE; | ||||
| 	return formats; | ||||
| } | ||||
| 
 | ||||
| int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) | ||||
| { | ||||
| 	int err; | ||||
| 	 | ||||
| 	if ((err = snd_pcm_channel_info(pcm, info)) < 0) | ||||
| 		return err; | ||||
| 	info->formats = snd_pcm_plugin_formats(pcm, info->formats); | ||||
| 	info->formats = snd_pcm_plugin_formats(info->formats); | ||||
| 	info->min_rate = 4000; | ||||
| 	info->max_rate = 192000; | ||||
| 	info->rates = SND_PCM_RATE_8000_48000; | ||||
|  | @ -285,27 +216,15 @@ static int snd_pcm_plugin_action(snd_pcm_t *pcm, int channel, int action) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
| #define PLUGIN_DEBUG | ||||
| #define pdprintf( args... ) printf( "plugin: " ##args) | ||||
| #else | ||||
| #define pdprintf( args... ) { ; } | ||||
| #endif | ||||
| 
 | ||||
| int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params) | ||||
| { | ||||
| 	snd_pcm_channel_params_t hwparams; | ||||
| 	snd_pcm_channel_params_t srcparams, tmpparams; | ||||
| 	snd_pcm_channel_params_t *dstparams; | ||||
| 	snd_pcm_channel_info_t hwinfo; | ||||
| 	snd_pcm_plugin_t *plugin; | ||||
| 	int err; | ||||
| 	 | ||||
| 	if (!pcm || !params || params->channel < 0 || params->channel > 1) | ||||
| 		return -EINVAL; | ||||
| 	memcpy(&hwparams, params, sizeof(hwparams)); | ||||
| 
 | ||||
| 	pdprintf("params begin\n"); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 *  try to decide, if a conversion is required | ||||
|  | @ -317,302 +236,16 @@ int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params) | |||
| 		snd_pcm_plugin_clear(pcm, params->channel); | ||||
| 		return err; | ||||
| 	} | ||||
| 	if ((hwinfo.formats & (1 << params->format.format)) == 0) { | ||||
| 		if ((snd_pcm_plugin_formats(pcm, hwinfo.formats) & (1 << params->format.format)) == 0) | ||||
| 			return -EINVAL; | ||||
| 		switch (params->format.format) { | ||||
| 		case SND_PCM_SFMT_U8: | ||||
| 			if (hwinfo.formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S8; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_S8: | ||||
| 			if (hwinfo.formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U8; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_S16_LE: | ||||
| 			if (hwinfo.formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S8; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U8; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_U16_LE: | ||||
| 			if (hwinfo.formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U8; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S8; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_MU_LAW: | ||||
| 			if (hwinfo.formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S8; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U8; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_A_LAW: | ||||
| 			if (hwinfo.formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S8; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U8; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 		case SND_PCM_SFMT_IMA_ADPCM: | ||||
| 			if (hwinfo.formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_S8; | ||||
| 			} else if (hwinfo.formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams.format.format = SND_PCM_SFMT_U8; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| 		default: | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* voices */ | ||||
|       	if (params->format.voices < hwinfo.min_voices || | ||||
|       	    params->format.voices > hwinfo.max_voices) { | ||||
| 		int dst_voices = params->format.voices < hwinfo.min_voices ? | ||||
| 				 hwinfo.min_voices : hwinfo.max_voices; | ||||
| 		if ((params->format.rate < hwinfo.min_rate || | ||||
| 		     params->format.rate > hwinfo.max_rate) && | ||||
| 		    dst_voices > 2) | ||||
| 			dst_voices = 2; | ||||
| 		hwparams.format.voices = dst_voices; | ||||
| 		pdprintf("params voice correction: dst_voices=%i\n", dst_voices); | ||||
| 	} | ||||
| 	if ((err = snd_pcm_plugin_hwparams(params, &hwinfo, &hwparams)) < 0) | ||||
| 		return err; | ||||
| 
 | ||||
| 	/* rate */ | ||||
|         if (params->format.rate < hwinfo.min_rate || | ||||
|             params->format.rate > hwinfo.max_rate) { | ||||
|         	int dst_rate = params->format.rate < hwinfo.min_rate ? | ||||
|         		       hwinfo.min_rate : hwinfo.max_rate; | ||||
| 		hwparams.format.rate = dst_rate; | ||||
| 		pdprintf("params rate correction: dst_rate=%i\n", dst_rate); | ||||
| 	} | ||||
| 
 | ||||
| 	/* interleave */ | ||||
| 	hwparams.format.interleave = params->format.interleave; | ||||
| 	if (!(hwinfo.flags & SND_PCM_CHNINFO_INTERLEAVE)) | ||||
| 		hwparams.format.interleave = 0; | ||||
| 	if (!(hwinfo.flags & SND_PCM_CHNINFO_NONINTERLEAVE)) | ||||
| 		hwparams.format.interleave = 1; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 *  add necessary plugins | ||||
| 	 */ | ||||
| 
 | ||||
| 	snd_pcm_plugin_clear(pcm, params->channel); | ||||
| 
 | ||||
| 	if (params->channel == SND_PCM_CHANNEL_PLAYBACK) { | ||||
| 		memcpy(&srcparams, params, sizeof(srcparams)); | ||||
| 		memcpy(&tmpparams, params, sizeof(tmpparams)); | ||||
| 		dstparams = &hwparams; | ||||
| 	} else { | ||||
| 		memcpy(&srcparams, &hwparams, sizeof(srcparams)); | ||||
| 		memcpy(&tmpparams, &hwparams, sizeof(tmpparams)); | ||||
| 		dstparams = params; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Convert to interleaved format if needed */ | ||||
| 	if (!srcparams.format.interleave && | ||||
| 	    (srcparams.format.voices != dstparams->format.voices || | ||||
| 	     (srcparams.format.rate != dstparams->format.rate && | ||||
| 	      srcparams.format.voices > 1))) { | ||||
| 		tmpparams.format.interleave = 1; | ||||
| 		pdprintf("params interleave plugin: src=%i, dst=%i\n", srcparams.format.interleave, tmpparams.format.interleave); | ||||
| 		err = snd_pcm_plugin_build_interleave(&srcparams.format, | ||||
| 						      &tmpparams.format, | ||||
| 						      &plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		}      					     | ||||
| 		err = snd_pcm_plugin_append(pcm, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.interleave = 1; | ||||
| 		/* Avoid useless interleave revert */ | ||||
| 		if (params->channel == SND_PCM_CHANNEL_PLAYBACK && | ||||
| 		    (hwinfo.flags & SND_PCM_CHNINFO_INTERLEAVE)) | ||||
| 			dstparams->format.interleave = 1; | ||||
|       	} | ||||
| 
 | ||||
| 	/* voices reduction */ | ||||
| 	if (srcparams.format.voices > dstparams->format.voices) { | ||||
| 		tmpparams.format.voices = dstparams->format.voices; | ||||
| 		pdprintf("params voices reduction: src=%i, dst=%i\n", srcparams.format.voices, tmpparams.format.voices); | ||||
| 		err = snd_pcm_plugin_build_voices(&srcparams.format, | ||||
| 						  &tmpparams.format, | ||||
| 						  &plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		err = snd_pcm_plugin_append(pcm, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.voices = dstparams->format.voices; | ||||
|         } | ||||
| 
 | ||||
| 	/* rate resampling (when the source format has a highter resolution) */ | ||||
|         if (srcparams.format.format > dstparams->format.format && | ||||
| 	    srcparams.format.format <= SND_PCM_SFMT_FLOAT64_BE && | ||||
|             srcparams.format.rate != dstparams->format.rate) { | ||||
| 		tmpparams.format.rate = dstparams->format.rate; | ||||
| 		pdprintf("params rate resampling (1): src=%i, dst=%i\n", srcparams.format.rate, tmpparams.format.rate); | ||||
|         	err = snd_pcm_plugin_build_rate(&srcparams.format, | ||||
| 						&tmpparams.format, | ||||
| 						&plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		}      					     | ||||
| 		err = snd_pcm_plugin_append(pcm, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.rate = dstparams->format.rate; | ||||
|         } | ||||
| 
 | ||||
| 	/* format change */ | ||||
| 	if (srcparams.format.format != dstparams->format.format) { | ||||
| 		tmpparams.format.format = dstparams->format.format; | ||||
| 		pdprintf("params format change: src=%i, dst=%i\n", srcparams.format.format, tmpparams.format.format); | ||||
| 		switch (params->format.format) { | ||||
| 		case SND_PCM_SFMT_MU_LAW: | ||||
| 			err = snd_pcm_plugin_build_mulaw(&srcparams.format, | ||||
| 							 &tmpparams.format, | ||||
| 							 &plugin); | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_A_LAW: | ||||
| 			err = snd_pcm_plugin_build_alaw(&srcparams.format, | ||||
| 							&tmpparams.format, | ||||
| 							&plugin); | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_IMA_ADPCM: | ||||
| 			err = snd_pcm_plugin_build_adpcm(&srcparams.format, | ||||
| 							 &tmpparams.format, | ||||
| 							 &plugin); | ||||
| 			break; | ||||
| 		default: | ||||
| 			err = snd_pcm_plugin_build_linear(&srcparams.format, | ||||
| 							  &tmpparams.format, | ||||
| 							  &plugin); | ||||
| 		} | ||||
| 		if (err < 0) | ||||
| 			return err; | ||||
| 		err = snd_pcm_plugin_append(pcm, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.format = dstparams->format.format; | ||||
| 	} | ||||
| 
 | ||||
| 	/* rate resampling (when the destonation format has an equal or highter resolution) */ | ||||
|         if (srcparams.format.format <= dstparams->format.format && | ||||
|             srcparams.format.rate != dstparams->format.rate) { | ||||
| 		tmpparams.format.rate = dstparams->format.rate; | ||||
| 		pdprintf("params rate resampling (2): src=%i, dst=%i\n", srcparams.format.rate, tmpparams.format.rate); | ||||
|         	err = snd_pcm_plugin_build_rate(&srcparams.format, | ||||
| 						&tmpparams.format, | ||||
| 						&plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		}      					     | ||||
| 		err = snd_pcm_plugin_append(pcm, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.rate = dstparams->format.rate; | ||||
|         } | ||||
|        | ||||
| 	/* voices extension  */ | ||||
| 	if (srcparams.format.voices < dstparams->format.voices) { | ||||
| 		tmpparams.format.voices = dstparams->format.voices; | ||||
| 		pdprintf("params voices extension: src=%i, dst=%i\n", srcparams.format.voices, tmpparams.format.voices); | ||||
| 		err = snd_pcm_plugin_build_voices(&srcparams.format, | ||||
| 						  &tmpparams.format, | ||||
| 						  &plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		}      					     | ||||
| 		err = snd_pcm_plugin_append(pcm, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.voices = dstparams->format.voices; | ||||
| 	} | ||||
| 
 | ||||
| 	/* interleave change */ | ||||
| 	if (params->format.voices > 1 &&  | ||||
| 	    hwinfo.mode == SND_PCM_MODE_BLOCK && | ||||
| 	    srcparams.format.interleave != dstparams->format.interleave) { | ||||
| 		tmpparams.format.interleave = dstparams->format.interleave; | ||||
| 		pdprintf("params interleave change: src=%i, dst=%i\n", srcparams.format.interleave, tmpparams.format.interleave); | ||||
| 		err = snd_pcm_plugin_build_interleave(&srcparams.format, | ||||
| 						      &tmpparams.format, | ||||
| 						      &plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		}      					     | ||||
| 		err = snd_pcm_plugin_append(pcm, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.interleave = dstparams->format.interleave; | ||||
| 	} | ||||
| 	/*  add necessary plugins */ | ||||
| 	if ((err = snd_pcm_plugin_format(pcm, params, &hwparams, &hwinfo)) < 0) | ||||
| 		return err; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 *  I/O plugins | ||||
|  |  | |||
							
								
								
									
										439
									
								
								src/pcm/pcm_plugin_build.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										439
									
								
								src/pcm/pcm_plugin_build.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,439 @@ | |||
| /*
 | ||||
|  *  PCM Plug-In shared (kernel/library) code | ||||
|  *  Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> | ||||
|  * | ||||
|  * | ||||
|  *   This library is free software; you can redistribute it and/or modify | ||||
|  *   it under the terms of the GNU Library General Public License as | ||||
|  *   published by the Free Software Foundation; either version 2 of | ||||
|  *   the License, or (at your option) any later version. | ||||
|  * | ||||
|  *   This program is distributed in the hope that it will be useful, | ||||
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *   GNU Library General Public License for more details. | ||||
|  * | ||||
|  *   You should have received a copy of the GNU Library General Public | ||||
|  *   License along with this library; if not, write to the Free Software | ||||
|  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
|  * | ||||
|  */ | ||||
|    | ||||
| #ifdef __KERNEL__ | ||||
| #define PLUGIN_DEBUG | ||||
| #include "../include/driver.h" | ||||
| #include "../include/pcm.h" | ||||
| typedef snd_pcm_runtime_t PLUGIN_BASE; | ||||
| #define snd_pcm_plugin_first(pb, channel) ((pb)->oss.plugin_first) | ||||
| #define snd_pcm_plugin_last(pb, channel) ((pb)->oss.plugin_last) | ||||
| #define snd_pcm_plugin_append(pb, channel, plugin) snd_pcm_oss_plugin_append(pb, plugin) | ||||
| #else | ||||
| #include <errno.h> | ||||
| #include "pcm_local.h" | ||||
| typedef snd_pcm_t PLUGIN_BASE; | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| ssize_t snd_pcm_plugin_transfer_size(PLUGIN_BASE *pb, int channel, size_t drv_size) | ||||
| { | ||||
| 	snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next; | ||||
| 	 | ||||
| 	if (!pb || (channel != SND_PCM_CHANNEL_PLAYBACK && | ||||
| 		    channel != SND_PCM_CHANNEL_CAPTURE)) | ||||
| 		return -EINVAL; | ||||
| 	if (drv_size == 0) | ||||
| 		return 0; | ||||
| 	if (drv_size < 0) | ||||
| 		return -EINVAL; | ||||
| 	if (channel == SND_PCM_CHANNEL_PLAYBACK) { | ||||
| 		plugin = snd_pcm_plugin_last(pb, channel); | ||||
| 		while (plugin) { | ||||
| 			plugin_prev = plugin->prev; | ||||
| 			if (plugin->src_size) | ||||
| 				drv_size = plugin->src_size(plugin, drv_size); | ||||
| 			plugin = plugin_prev; | ||||
| 		} | ||||
| 	} else if (channel == SND_PCM_CHANNEL_CAPTURE) { | ||||
| 		plugin = snd_pcm_plugin_first(pb, channel); | ||||
| 		while (plugin) { | ||||
| 			plugin_next = plugin->next; | ||||
| 			if (plugin->dst_size) | ||||
| 				drv_size = plugin->dst_size(plugin, drv_size); | ||||
| 			plugin = plugin_next; | ||||
| 		} | ||||
| 	} | ||||
| 	return drv_size; | ||||
| } | ||||
| 
 | ||||
| ssize_t snd_pcm_plugin_hardware_size(PLUGIN_BASE *pb, int channel, size_t trf_size) | ||||
| { | ||||
| 	snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next; | ||||
| 	 | ||||
| 	if (!pb || (channel != SND_PCM_CHANNEL_PLAYBACK && | ||||
| 		     channel != SND_PCM_CHANNEL_CAPTURE)) | ||||
| 		return -EINVAL; | ||||
| 	if (trf_size == 0) | ||||
| 		return 0; | ||||
| 	if (trf_size < 0) | ||||
| 		return -EINVAL; | ||||
| 	if (channel == SND_PCM_CHANNEL_PLAYBACK) { | ||||
| 		plugin = snd_pcm_plugin_first(pb, channel); | ||||
| 		while (plugin) { | ||||
| 			plugin_next = plugin->next; | ||||
| 			if (plugin->dst_size) | ||||
| 				trf_size = plugin->dst_size(plugin, trf_size); | ||||
| 			plugin = plugin_next; | ||||
| 		} | ||||
| 	} else if (channel == SND_PCM_CHANNEL_CAPTURE) { | ||||
| 		plugin = snd_pcm_plugin_last(pb, channel); | ||||
| 		while (plugin) { | ||||
| 			plugin_prev = plugin->prev; | ||||
| 			if (plugin->src_size) | ||||
| 				trf_size = plugin->src_size(plugin, trf_size); | ||||
| 			plugin = plugin_prev; | ||||
| 		} | ||||
| 	}  | ||||
| 	return trf_size; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| unsigned int snd_pcm_plugin_formats(unsigned int formats) | ||||
| { | ||||
| 	formats |= SND_PCM_FMT_MU_LAW | SND_PCM_FMT_A_LAW | SND_PCM_FMT_IMA_ADPCM; | ||||
| 	if (formats & (SND_PCM_FMT_U8|SND_PCM_FMT_S8| | ||||
| 		       SND_PCM_FMT_U16_LE|SND_PCM_FMT_S16_LE)) | ||||
| 		formats |= SND_PCM_FMT_U8|SND_PCM_FMT_S8| | ||||
| 			   SND_PCM_FMT_U16_LE|SND_PCM_FMT_S16_LE; | ||||
| 	return formats; | ||||
| } | ||||
| 
 | ||||
| int snd_pcm_plugin_hwparams(snd_pcm_channel_params_t *params, | ||||
| 			    snd_pcm_channel_info_t *hwinfo, | ||||
| 			    snd_pcm_channel_params_t *hwparams) | ||||
| { | ||||
| 	memcpy(hwparams, params, sizeof(*hwparams)); | ||||
| 	if ((hwinfo->formats & (1 << params->format.format)) == 0) { | ||||
| 		if ((snd_pcm_plugin_formats(hwinfo->formats) & (1 << params->format.format)) == 0) | ||||
| 			return -EINVAL; | ||||
| 		switch (params->format.format) { | ||||
| 		case SND_PCM_SFMT_U8: | ||||
| 			if (hwinfo->formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S8; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_S8: | ||||
| 			if (hwinfo->formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U8; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_S16_LE: | ||||
| 			if (hwinfo->formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S8; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U8; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_U16_LE: | ||||
| 			if (hwinfo->formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U8; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S8; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_MU_LAW: | ||||
| 			if (hwinfo->formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S8; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U8; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| #ifndef __KERNEL__ | ||||
| 		case SND_PCM_SFMT_A_LAW: | ||||
| 			if (hwinfo->formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S8; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U8; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 		case SND_PCM_SFMT_IMA_ADPCM: | ||||
| 			if (hwinfo->formats & SND_PCM_FMT_S16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S16_LE; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_U16_LE) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U16_LE; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_S8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_S8; | ||||
| 			} else if (hwinfo->formats & SND_PCM_FMT_U8) { | ||||
| 				hwparams->format.format = SND_PCM_SFMT_U8; | ||||
| 			} else { | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
| 			break; | ||||
| #endif | ||||
| 		default: | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* voices */ | ||||
|       	if (params->format.voices < hwinfo->min_voices || | ||||
|       	    params->format.voices > hwinfo->max_voices) { | ||||
| 		int dst_voices = params->format.voices < hwinfo->min_voices ? | ||||
| 				 hwinfo->min_voices : hwinfo->max_voices; | ||||
| 		if ((params->format.rate < hwinfo->min_rate || | ||||
| 		     params->format.rate > hwinfo->max_rate) && | ||||
| 		    dst_voices > 2) | ||||
| 			dst_voices = 2; | ||||
| 		hwparams->format.voices = dst_voices; | ||||
| 	} | ||||
| 
 | ||||
| 	/* rate */ | ||||
|         if (params->format.rate < hwinfo->min_rate || | ||||
|             params->format.rate > hwinfo->max_rate) { | ||||
|         	int dst_rate = params->format.rate < hwinfo->min_rate ? | ||||
|         		       hwinfo->min_rate : hwinfo->max_rate; | ||||
| 		hwparams->format.rate = dst_rate; | ||||
| 	} | ||||
| 
 | ||||
| 	/* interleave */ | ||||
| 	if (!(hwinfo->flags & SND_PCM_CHNINFO_INTERLEAVE)) | ||||
| 		hwparams->format.interleave = 0; | ||||
| 	if (!(hwinfo->flags & SND_PCM_CHNINFO_NONINTERLEAVE)) | ||||
| 		hwparams->format.interleave = 1; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int snd_pcm_plugin_format(PLUGIN_BASE *pb,  | ||||
| 			  snd_pcm_channel_params_t *params,  | ||||
| 			  snd_pcm_channel_params_t *hwparams, | ||||
| 			  snd_pcm_channel_info_t *hwinfo) | ||||
| { | ||||
| 	snd_pcm_channel_params_t srcparams, tmpparams; | ||||
| 	snd_pcm_channel_params_t *dstparams; | ||||
| 	snd_pcm_plugin_t *plugin; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (params->channel == SND_PCM_CHANNEL_PLAYBACK) { | ||||
| 		memcpy(&srcparams, params, sizeof(srcparams)); | ||||
| 		memcpy(&tmpparams, params, sizeof(tmpparams)); | ||||
| 		dstparams = hwparams; | ||||
| 	} else { | ||||
| 		memcpy(&srcparams, &hwparams, sizeof(srcparams)); | ||||
| 		memcpy(&tmpparams, &hwparams, sizeof(tmpparams)); | ||||
| 		dstparams = params; | ||||
| 	} | ||||
| 
 | ||||
| 	pdprintf("srcparams: interleave=%i, format=%i, rate=%i, voices=%i\n",  | ||||
| 		 srcparams.format.interleave, | ||||
| 		 srcparams.format.format, | ||||
| 		 srcparams.format.rate, | ||||
| 		 srcparams.format.voices); | ||||
| 	pdprintf("dstparams: interleave=%i, format=%i, rate=%i, voices=%i\n",  | ||||
| 		 dstparams->format.interleave, | ||||
| 		 dstparams->format.format, | ||||
| 		 dstparams->format.rate, | ||||
| 		 dstparams->format.voices); | ||||
| 	/* Convert to interleaved format if needed */ | ||||
| 	if (!srcparams.format.interleave && | ||||
| 	    (srcparams.format.voices != dstparams->format.voices || | ||||
| 	     (srcparams.format.rate != dstparams->format.rate && | ||||
| 	      srcparams.format.voices > 1))) { | ||||
| 		tmpparams.format.interleave = 1; | ||||
| 		err = snd_pcm_plugin_build_interleave(&srcparams.format, | ||||
| 						      &tmpparams.format, | ||||
| 						      &plugin); | ||||
| 		pdprintf("params interleave change: src=%i, dst=%i returns %i\n", srcparams.format.interleave, tmpparams.format.interleave, err); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		}      					     | ||||
| 		err = snd_pcm_plugin_append(pb, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.interleave = 1; | ||||
| 		/* Avoid useless interleave revert */ | ||||
| 		if (params->channel == SND_PCM_CHANNEL_PLAYBACK && | ||||
| 		    (hwinfo->flags & SND_PCM_CHNINFO_INTERLEAVE)) | ||||
| 			dstparams->format.interleave = 1; | ||||
|       	} | ||||
| 
 | ||||
| 	/* voices reduction */ | ||||
| 	if (srcparams.format.voices > dstparams->format.voices) { | ||||
| 		tmpparams.format.voices = dstparams->format.voices; | ||||
| 		err = snd_pcm_plugin_build_voices(&srcparams.format, | ||||
| 						  &tmpparams.format, | ||||
| 						  &plugin); | ||||
| 		pdprintf("params voices reduction: src=%i, dst=%i returns %i\n", srcparams.format.voices, tmpparams.format.voices, err); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		err = snd_pcm_plugin_append(pb, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.voices = dstparams->format.voices; | ||||
|         } | ||||
| 
 | ||||
| 	/* rate down resampling */ | ||||
|         if (srcparams.format.rate > dstparams->format.rate && | ||||
| 	    snd_pcm_format_linear(srcparams.format.format) && | ||||
| 	    snd_pcm_format_width(srcparams.format.format) <= 16 && | ||||
| 	    snd_pcm_format_width(srcparams.format.format) >= snd_pcm_format_width(srcparams.format.format)) { | ||||
| 		tmpparams.format.rate = dstparams->format.rate; | ||||
|         	err = snd_pcm_plugin_build_rate(&srcparams.format, | ||||
| 						&tmpparams.format, | ||||
| 						&plugin); | ||||
| 		pdprintf("params rate down resampling: src=%i, dst=%i\n returns %i", srcparams.format.rate, tmpparams.format.rate, err); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		}      					     | ||||
| 		err = snd_pcm_plugin_append(pb, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.rate = dstparams->format.rate; | ||||
|         } | ||||
| 
 | ||||
| 	/* format change */ | ||||
| 	if (srcparams.format.format != dstparams->format.format) { | ||||
| 		tmpparams.format.format = dstparams->format.format; | ||||
| 		switch (srcparams.format.format) { | ||||
| 		case SND_PCM_SFMT_MU_LAW: | ||||
| 			err = snd_pcm_plugin_build_mulaw(&srcparams.format, | ||||
| 							 &tmpparams.format, | ||||
| 							 &plugin); | ||||
| 			break; | ||||
| #ifndef __KERNEL__ | ||||
| 		case SND_PCM_SFMT_A_LAW: | ||||
| 			err = snd_pcm_plugin_build_alaw(&srcparams.format, | ||||
| 							&tmpparams.format, | ||||
| 							&plugin); | ||||
| 			break; | ||||
| 		case SND_PCM_SFMT_IMA_ADPCM: | ||||
| 			err = snd_pcm_plugin_build_adpcm(&srcparams.format, | ||||
| 							 &tmpparams.format, | ||||
| 							 &plugin); | ||||
| 			break; | ||||
| #endif | ||||
| 		default: | ||||
| 			err = snd_pcm_plugin_build_linear(&srcparams.format, | ||||
| 							  &tmpparams.format, | ||||
| 							  &plugin); | ||||
| 		} | ||||
| 		pdprintf("params format change: src=%i, dst=%i returns %i\n", srcparams.format.format, tmpparams.format.format, err); | ||||
| 		if (err < 0) | ||||
| 			return err; | ||||
| 		err = snd_pcm_plugin_append(pb, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.format = dstparams->format.format; | ||||
| 	} | ||||
| 
 | ||||
| 	/* rate resampling */ | ||||
|         if (srcparams.format.rate != dstparams->format.rate) { | ||||
| 		tmpparams.format.rate = dstparams->format.rate; | ||||
|         	err = snd_pcm_plugin_build_rate(&srcparams.format, | ||||
| 						&tmpparams.format, | ||||
| 						&plugin); | ||||
| 		pdprintf("params rate resampling: src=%i, dst=%i return %i\n", srcparams.format.rate, tmpparams.format.rate, err); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		}      					     | ||||
| 		err = snd_pcm_plugin_append(pb, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.rate = dstparams->format.rate; | ||||
|         } | ||||
|        | ||||
| 	/* voices extension  */ | ||||
| 	if (srcparams.format.voices != dstparams->format.voices) { | ||||
| 		tmpparams.format.voices = dstparams->format.voices; | ||||
| 		err = snd_pcm_plugin_build_voices(&srcparams.format, | ||||
| 						  &tmpparams.format, | ||||
| 						  &plugin); | ||||
| 		pdprintf("params voices extension: src=%i, dst=%i returns %i\n", srcparams.format.voices, tmpparams.format.voices, err); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		}      					     | ||||
| 		err = snd_pcm_plugin_append(pb, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.voices = dstparams->format.voices; | ||||
| 	} | ||||
| 
 | ||||
| 	/* interleave change */ | ||||
| 	if (dstparams->format.voices > 1 &&  | ||||
| 	    hwinfo->mode == SND_PCM_MODE_BLOCK && | ||||
| 	    srcparams.format.interleave != dstparams->format.interleave) { | ||||
| 		tmpparams.format.interleave = dstparams->format.interleave; | ||||
| 		err = snd_pcm_plugin_build_interleave(&srcparams.format, | ||||
| 						      &tmpparams.format, | ||||
| 						      &plugin); | ||||
| 		pdprintf("params interleave change: src=%i, dst=%i return %i\n", srcparams.format.interleave, tmpparams.format.interleave, err); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		}      					     | ||||
| 		err = snd_pcm_plugin_append(pb, params->channel, plugin); | ||||
| 		if (err < 0) { | ||||
| 			snd_pcm_plugin_free(plugin); | ||||
| 			return err; | ||||
| 		} | ||||
| 		srcparams.format.interleave = dstparams->format.interleave; | ||||
| 	} | ||||
| 	if (srcparams.format.interleave != dstparams->format.interleave && | ||||
| 	    srcparams.format.voices > 1) | ||||
| 		return -EINVAL; | ||||
| 	if (srcparams.format.format != dstparams->format.format) | ||||
| 		return -EINVAL; | ||||
| 	if (srcparams.format.rate != dstparams->format.rate) | ||||
| 		return -EINVAL; | ||||
| 	if (srcparams.format.voices != dstparams->format.voices) | ||||
| 		return -EINVAL; | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -892,9 +892,12 @@ int snd_pcm_plugin_build_adpcm(snd_pcm_format_t *src_format, | |||
| 		return -EINVAL; | ||||
| 	*r_plugin = NULL; | ||||
| 
 | ||||
| 	if (src_format->interleave != dst_format->interleave || | ||||
| 	    src_format->voices != dst_format->voices || | ||||
| 	    src_format->rate != dst_format->rate) | ||||
| 	if (src_format->interleave != dst_format->interleave &&  | ||||
| 	    src_format->voices > 1) | ||||
| 		return -EINVAL; | ||||
| 	if (src_format->rate != dst_format->rate) | ||||
| 		return -EINVAL; | ||||
| 	if (src_format->voices != dst_format->voices) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (dst_format->format == SND_PCM_SFMT_IMA_ADPCM) { | ||||
|  |  | |||
|  | @ -426,7 +426,8 @@ int snd_pcm_plugin_build_alaw(snd_pcm_format_t *src_format, | |||
| 		return -EINVAL; | ||||
| 	*r_plugin = NULL; | ||||
| 
 | ||||
| 	if (src_format->interleave != dst_format->interleave) | ||||
| 	if (src_format->interleave != dst_format->interleave &&  | ||||
| 	    src_format->voices > 1) | ||||
| 		return -EINVAL; | ||||
| 	if (src_format->rate != dst_format->rate) | ||||
| 		return -EINVAL; | ||||
|  |  | |||
|  | @ -19,6 +19,10 @@ | |||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifdef __KERNEL__ | ||||
| #include "../../include/driver.h" | ||||
| #include "../../include/pcm_plugin.h" | ||||
| #else | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
|  | @ -27,6 +31,7 @@ | |||
| #include <endian.h> | ||||
| #include <byteswap.h> | ||||
| #include "../pcm_local.h" | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  *  Basic interleave / non-interleave conversion plugin | ||||
|  | @ -188,6 +193,8 @@ int snd_pcm_plugin_build_interleave(snd_pcm_format_t *src_format, | |||
| 
 | ||||
| 	if (!r_plugin) | ||||
| 		return -EINVAL; | ||||
| 	*r_plugin = NULL; | ||||
| 
 | ||||
| 	if (src_format->interleave && !dst_format->interleave) { | ||||
| 		cmd = _INTERLEAVE_NON; | ||||
| 	} else if (!src_format->interleave && dst_format->interleave) { | ||||
|  | @ -236,3 +243,7 @@ int snd_pcm_plugin_build_interleave(snd_pcm_format_t *src_format, | |||
| 	*r_plugin = plugin; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef __KERNEL__ | ||||
| EXPORT_SYMBOL(snd_pcm_plugin_build_interleave); | ||||
| #endif | ||||
|  |  | |||
|  | @ -19,6 +19,11 @@ | |||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifdef __KERNEL__ | ||||
| #include "../../include/driver.h" | ||||
| #include "../../include/pcm.h" | ||||
| #include "../../include/pcm_plugin.h" | ||||
| #else | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
|  | @ -27,6 +32,7 @@ | |||
| #include <endian.h> | ||||
| #include <byteswap.h> | ||||
| #include "../pcm_local.h" | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  *  Basic linear conversion plugin | ||||
|  | @ -48,14 +54,15 @@ typedef enum { | |||
| } combination_t; | ||||
|   | ||||
| typedef enum { | ||||
| 	NONE, | ||||
| 	SOURCE, | ||||
| 	DESTINATION, | ||||
| 	BOTH, | ||||
| 	SIGN_NONE, | ||||
| 	SIGN_SOURCE, | ||||
| 	SIGN_DESTINATION, | ||||
| 	SIGN_BOTH, | ||||
| 	NONE = 0, | ||||
| 	SOURCE = 1, | ||||
| 	DESTINATION = 2, | ||||
| 	BOTH = 3, | ||||
| 	SIGN = 4, | ||||
| 	SIGN_NONE = 4, | ||||
| 	SIGN_SOURCE = 5, | ||||
| 	SIGN_DESTINATION = 6, | ||||
| 	SIGN_BOTH = 7, | ||||
| } endian_t; | ||||
|   | ||||
| struct linear_private_data { | ||||
|  | @ -128,8 +135,8 @@ static void linear_conv_sign_16bit_8bit_swap(unsigned short *src_ptr, | |||
| } | ||||
| 
 | ||||
| static ssize_t linear_transfer(snd_pcm_plugin_t *plugin, | ||||
| 			     char *src_ptr, size_t src_size, | ||||
| 			     char *dst_ptr, size_t dst_size) | ||||
| 			       char *src_ptr, size_t src_size, | ||||
| 			       char *dst_ptr, size_t dst_size) | ||||
| { | ||||
| 	struct linear_private_data *data; | ||||
| 
 | ||||
|  | @ -170,13 +177,13 @@ static ssize_t linear_transfer(snd_pcm_plugin_t *plugin, | |||
| 		case NONE: | ||||
| 			linear_conv_16bit_8bit((short *)src_ptr, dst_ptr, src_size); | ||||
| 			break; | ||||
| 		case DESTINATION: | ||||
| 		case SOURCE: | ||||
| 			linear_conv_16bit_8bit_swap((short *)src_ptr, dst_ptr, src_size); | ||||
| 			break; | ||||
| 		case SIGN_NONE: | ||||
| 			linear_conv_sign_16bit_8bit((short *)src_ptr, dst_ptr, src_size); | ||||
| 			break; | ||||
| 		case SIGN_DESTINATION: | ||||
| 		case SIGN_SOURCE: | ||||
| 			linear_conv_sign_16bit_8bit_swap((short *)src_ptr, dst_ptr, src_size); | ||||
| 			break; | ||||
| 		default: | ||||
|  | @ -248,68 +255,6 @@ static ssize_t linear_dst_size(snd_pcm_plugin_t *plugin, size_t size) | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int linear_wide(int format) | ||||
| { | ||||
| 	if (format >= 0 && format <= 1) | ||||
| 		return 8; | ||||
| 	if (format >= 2 && format <= 5) | ||||
| 		return 16; | ||||
| 	if (format >= 6 && format <= 9) | ||||
| 		return 24; | ||||
| 	if (format >= 10 && format <= 13) | ||||
| 		return 32; | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| static int linear_endian(int format) | ||||
| { | ||||
| 	switch (format) { | ||||
| 	case SND_PCM_SFMT_S8: | ||||
| 	case SND_PCM_SFMT_U8: | ||||
| 		return 0; | ||||
| 	case SND_PCM_SFMT_S16_LE: | ||||
| 	case SND_PCM_SFMT_U16_LE: | ||||
| 	case SND_PCM_SFMT_S24_LE: | ||||
| 	case SND_PCM_SFMT_U24_LE: | ||||
| 	case SND_PCM_SFMT_S32_LE: | ||||
| 	case SND_PCM_SFMT_U32_LE: | ||||
| 		return __LITTLE_ENDIAN; | ||||
| 	case SND_PCM_SFMT_S16_BE: | ||||
| 	case SND_PCM_SFMT_U16_BE: | ||||
| 	case SND_PCM_SFMT_S24_BE: | ||||
| 	case SND_PCM_SFMT_U24_BE: | ||||
| 	case SND_PCM_SFMT_S32_BE: | ||||
| 	case SND_PCM_SFMT_U32_BE: | ||||
| 		return __BIG_ENDIAN; | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
| } | ||||
|   | ||||
| static int linear_sign(int format) | ||||
| { | ||||
| 	switch (format) { | ||||
| 	case SND_PCM_SFMT_S8: | ||||
| 	case SND_PCM_SFMT_S16_LE: | ||||
| 	case SND_PCM_SFMT_S16_BE: | ||||
| 	case SND_PCM_SFMT_S24_LE: | ||||
| 	case SND_PCM_SFMT_S24_BE: | ||||
| 	case SND_PCM_SFMT_S32_LE: | ||||
| 	case SND_PCM_SFMT_S32_BE: | ||||
| 		return 1; | ||||
| 	case SND_PCM_SFMT_U8: | ||||
| 	case SND_PCM_SFMT_U16_LE: | ||||
| 	case SND_PCM_SFMT_U24_LE: | ||||
| 	case SND_PCM_SFMT_U32_LE: | ||||
| 	case SND_PCM_SFMT_U16_BE: | ||||
| 	case SND_PCM_SFMT_U24_BE: | ||||
| 	case SND_PCM_SFMT_U32_BE: | ||||
| 		return 0; | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
| } | ||||
|   | ||||
| int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format, | ||||
| 				snd_pcm_format_t *dst_format, | ||||
| 				snd_pcm_plugin_t **r_plugin) | ||||
|  | @ -317,40 +262,40 @@ int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format, | |||
| 	struct linear_private_data *data; | ||||
| 	snd_pcm_plugin_t *plugin; | ||||
| 	combination_t cmd; | ||||
| 	int wide1, wide2, endian1, endian2, sign1, sign2; | ||||
| 	int width1, width2, endian1, endian2, sign1, sign2; | ||||
| 
 | ||||
| 	if (!r_plugin) | ||||
| 		return -EINVAL; | ||||
| 	*r_plugin = NULL; | ||||
| 
 | ||||
| 	if (src_format->interleave != dst_format->interleave) | ||||
| 	if (src_format->interleave != dst_format->interleave &&  | ||||
| 	    src_format->voices > 1) | ||||
| 		return -EINVAL; | ||||
| 	if (src_format->rate != dst_format->rate) | ||||
| 		return -EINVAL; | ||||
| 	if (src_format->voices != dst_format->voices) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	wide1 = linear_wide(src_format->format); | ||||
| 	endian1 = linear_endian(src_format->format); | ||||
| 	sign1 = linear_sign(src_format->format); | ||||
| 	wide2 = linear_wide(dst_format->format); | ||||
| 	endian2 = linear_endian(dst_format->format); | ||||
| 	sign2 = linear_sign(dst_format->format); | ||||
| 	if (wide1 < 0 || wide2 < 0 || endian1 < 0 || endian2 < 0 || sign1 < 0 || sign2 < 0) | ||||
| 	if (!(snd_pcm_format_linear(src_format->format) && | ||||
| 	      snd_pcm_format_linear(dst_format->format))) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	width1 = snd_pcm_format_width(src_format->format); | ||||
| 	sign1 = snd_pcm_format_signed(src_format->format); | ||||
| 	width2 = snd_pcm_format_width(dst_format->format); | ||||
| 	sign2 = snd_pcm_format_signed(dst_format->format); | ||||
| #if __BYTE_ORDER == __LITTLE_ENDIAN | ||||
| 	endian1 = endian1 == __BIG_ENDIAN ? 1 : 0; | ||||
| 	endian2 = endian2 == __BIG_ENDIAN ? 1 : 0; | ||||
| 	endian1 = snd_pcm_format_little_endian(src_format->format); | ||||
| 	endian2 = snd_pcm_format_little_endian(dst_format->format); | ||||
| #elif __BYTE_ORDER == __BIG_ENDIAN | ||||
| 	endian1 = endian1 == __LITTLE_ENDIAN ? 1 : 0; | ||||
| 	endian2 = endian2 == __LITTLE_ENDIAN ? 1 : 0; | ||||
| 	endian1 = snd_pcm_format_big_endian(src_format->format); | ||||
| 	endian2 = snd_pcm_format_big_endian(dst_format->format); | ||||
| #else | ||||
| #error "Unsupported endian..." | ||||
| #endif | ||||
| 	cmd = _8BIT_16BIT; | ||||
| 	switch (wide1) { | ||||
| 	switch (width1) { | ||||
| 	case 8: | ||||
| 		switch (wide2) { | ||||
| 		switch (width2) { | ||||
| 		case 16:	cmd = _8BIT_16BIT; break; | ||||
| 		case 24:	cmd = _8BIT_24BIT; break; | ||||
| 		case 32:	cmd = _8BIT_32BIT; break; | ||||
|  | @ -358,7 +303,7 @@ int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format, | |||
| 		} | ||||
| 		break; | ||||
| 	case 16: | ||||
| 		switch (wide2) { | ||||
| 		switch (width2) { | ||||
| 		case 8:		cmd = _16BIT_8BIT; break; | ||||
| 		case 24:	cmd = _16BIT_24BIT; break; | ||||
| 		case 32:	cmd = _16BIT_32BIT; break; | ||||
|  | @ -366,7 +311,7 @@ int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format, | |||
| 		} | ||||
| 		break; | ||||
| 	case 24: | ||||
| 		switch (wide2) { | ||||
| 		switch (width2) { | ||||
| 		case 8:		cmd = _24BIT_8BIT; break; | ||||
| 		case 16:	cmd = _24BIT_16BIT; break; | ||||
| 		case 32:	cmd = _24BIT_32BIT; break; | ||||
|  | @ -374,7 +319,7 @@ int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format, | |||
| 		} | ||||
| 		break; | ||||
| 	case 32: | ||||
| 		switch (wide2) { | ||||
| 		switch (width2) { | ||||
| 		case 8:		cmd = _32BIT_8BIT; break; | ||||
| 		case 16:	cmd = _32BIT_16BIT; break; | ||||
| 		case 24:	cmd = _32BIT_24BIT; break; | ||||
|  | @ -390,20 +335,20 @@ int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format, | |||
| 		return -ENOMEM; | ||||
| 	data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin); | ||||
| 	data->cmd = cmd; | ||||
| 	if (!endian1 && !endian2) { | ||||
| 		data->endian = NONE; | ||||
| 	} else if (endian1 && !endian2) { | ||||
| 		data->endian = SOURCE; | ||||
| 	} else if (!endian1 && endian2) { | ||||
| 		data->endian = DESTINATION; | ||||
| 	} else { | ||||
| 		data->endian = BOTH; | ||||
| 	} | ||||
| 	data->endian = NONE; | ||||
| 	if (endian1 == 0) | ||||
| 		data->endian |= SOURCE; | ||||
| 	if (endian2 == 0) | ||||
| 		data->endian |= DESTINATION; | ||||
| 	if (sign1 != sign2) | ||||
| 		data->endian += 4; | ||||
| 		data->endian |= SIGN; | ||||
| 	plugin->transfer = linear_transfer; | ||||
| 	plugin->src_size = linear_src_size; | ||||
| 	plugin->dst_size = linear_dst_size; | ||||
| 	*r_plugin = plugin; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef __KERNEL__ | ||||
| EXPORT_SYMBOL(snd_pcm_plugin_build_linear); | ||||
| #endif | ||||
|  |  | |||
|  | @ -21,6 +21,11 @@ | |||
|  * | ||||
|  */ | ||||
|    | ||||
| #ifdef __KERNEL__ | ||||
| #include "../../include/driver.h" | ||||
| #include "../../include/pcm_plugin.h" | ||||
| #define bswap_16(x) __swab16((x)) | ||||
| #else | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
|  | @ -29,6 +34,7 @@ | |||
| #include <endian.h> | ||||
| #include <byteswap.h> | ||||
| #include "../pcm_local.h" | ||||
| #endif | ||||
| 
 | ||||
| #define	SIGN_BIT	(0x80)		/* Sign bit for a u-law byte. */ | ||||
| #define	QUANT_MASK	(0xf)		/* Quantization field mask. */ | ||||
|  | @ -241,8 +247,8 @@ static void mulaw_conv_mulaw_swap_u16bit(unsigned char *src_ptr, unsigned short | |||
| } | ||||
| 
 | ||||
| static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin, | ||||
| 			      char *src_ptr, size_t src_size, | ||||
| 			      char *dst_ptr, size_t dst_size) | ||||
| 			   char *src_ptr, size_t src_size, | ||||
| 			   char *dst_ptr, size_t dst_size) | ||||
| { | ||||
| 	struct mulaw_private_data *data; | ||||
| 
 | ||||
|  | @ -436,7 +442,8 @@ int snd_pcm_plugin_build_mulaw(snd_pcm_format_t *src_format, | |||
| 		return -EINVAL; | ||||
| 	*r_plugin = NULL; | ||||
| 
 | ||||
| 	if (src_format->interleave != dst_format->interleave) | ||||
| 	if (src_format->interleave != dst_format->interleave &&  | ||||
| 	    src_format->voices > 1) | ||||
| 		return -EINVAL; | ||||
| 	if (src_format->rate != dst_format->rate) | ||||
| 		return -EINVAL; | ||||
|  | @ -480,3 +487,7 @@ int snd_pcm_plugin_build_mulaw(snd_pcm_format_t *src_format, | |||
| 	*r_plugin = plugin; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef __KERNEL__ | ||||
| EXPORT_SYMBOL(snd_pcm_plugin_build_mulaw); | ||||
| #endif | ||||
|  |  | |||
|  | @ -19,6 +19,10 @@ | |||
|  * | ||||
|  */ | ||||
|    | ||||
| #ifdef __KERNEL__ | ||||
| #include "../../include/driver.h" | ||||
| #include "../../include/pcm_plugin.h" | ||||
| #else | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
|  | @ -27,6 +31,7 @@ | |||
| #include <endian.h> | ||||
| #include <byteswap.h> | ||||
| #include "../pcm_local.h" | ||||
| #endif | ||||
| 
 | ||||
| #define SHIFT	11 | ||||
| #define BITS	(1<<SHIFT) | ||||
|  | @ -51,9 +56,9 @@ struct rate_private_data { | |||
| 	ssize_t old_src_size, old_dst_size; | ||||
| }; | ||||
| 
 | ||||
| static void mix16_expand(struct rate_private_data *data, int voices, | ||||
| 			 signed short *src_ptr, int src_size, | ||||
| 			 signed short *dst_ptr, int dst_size) | ||||
| static void resample16_expand(struct rate_private_data *data, int voices, | ||||
| 			      signed short *src_ptr, int src_size, | ||||
| 			      signed short *dst_ptr, int dst_size) | ||||
| { | ||||
| 	unsigned int pos; | ||||
| 	signed int val; | ||||
|  | @ -97,9 +102,9 @@ static void mix16_expand(struct rate_private_data *data, int voices, | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void mix16_shrink(struct rate_private_data *data, int voices, | ||||
| 			 signed short *src_ptr, int src_size, | ||||
| 			 signed short *dst_ptr, int dst_size) | ||||
| static void resample16_shrink(struct rate_private_data *data, int voices, | ||||
| 			      signed short *src_ptr, int src_size, | ||||
| 			      signed short *dst_ptr, int dst_size) | ||||
| { | ||||
| 	unsigned int pos; | ||||
| 	signed int val; | ||||
|  | @ -140,9 +145,9 @@ static void mix16_shrink(struct rate_private_data *data, int voices, | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void mix8_expand(struct rate_private_data *data, int voices, | ||||
| 			unsigned char *src_ptr, int src_size, | ||||
| 			unsigned char *dst_ptr, int dst_size) | ||||
| static void resample8_expand(struct rate_private_data *data, int voices, | ||||
| 			     unsigned char *src_ptr, int src_size, | ||||
| 			     unsigned char *dst_ptr, int dst_size) | ||||
| { | ||||
| 	unsigned int pos; | ||||
| 	signed int val; | ||||
|  | @ -186,9 +191,9 @@ static void mix8_expand(struct rate_private_data *data, int voices, | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void mix8_shrink(struct rate_private_data *data, int voices, | ||||
| 			unsigned char *src_ptr, int src_size, | ||||
| 			unsigned char *dst_ptr, int dst_size) | ||||
| static void resample8_shrink(struct rate_private_data *data, int voices, | ||||
| 			     unsigned char *src_ptr, int src_size, | ||||
| 			     unsigned char *dst_ptr, int dst_size) | ||||
| { | ||||
| 	unsigned int pos; | ||||
| 	signed int val; | ||||
|  | @ -245,21 +250,21 @@ static ssize_t rate_transfer(snd_pcm_plugin_t *plugin, | |||
| 		return -EINVAL; | ||||
| 	if (data->sample_size == 2) { | ||||
| 		if (data->src_rate < data->dst_rate) { | ||||
| 			mix16_expand(data, data->src_voices, | ||||
| 			resample16_expand(data, data->src_voices, | ||||
| 				     (signed short *)src_ptr, src_size / (data->src_voices * 2), | ||||
| 				     (signed short *)dst_ptr, dst_size / (data->dst_voices * 2)); | ||||
| 		} else { | ||||
| 			mix16_shrink(data, data->src_voices, | ||||
| 			resample16_shrink(data, data->src_voices, | ||||
| 				     (signed short *)src_ptr, src_size / (data->src_voices * 2), | ||||
| 				     (signed short *)dst_ptr, dst_size / (data->dst_voices * 2)); | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (data->src_rate < data->dst_rate) { | ||||
| 			mix8_expand(data, data->src_voices, | ||||
| 			resample8_expand(data, data->src_voices, | ||||
| 				    src_ptr, src_size / data->src_voices, | ||||
| 				    dst_ptr, dst_size / data->dst_voices); | ||||
| 		} else { | ||||
| 			mix8_shrink(data, data->src_voices, | ||||
| 			resample8_shrink(data, data->src_voices, | ||||
| 				    src_ptr, src_size / data->src_voices, | ||||
| 				    dst_ptr, dst_size / data->dst_voices); | ||||
| 		} | ||||
|  | @ -365,7 +370,8 @@ int snd_pcm_plugin_build_rate(snd_pcm_format_t *src_format, | |||
| 		return -EINVAL; | ||||
| 	*r_plugin = NULL; | ||||
| 
 | ||||
| 	if (src_format->interleave != dst_format->interleave) | ||||
| 	if (src_format->interleave != dst_format->interleave &&  | ||||
| 	    src_format->voices > 1) | ||||
| 		return -EINVAL; | ||||
| 	if (src_format->format != dst_format->format) | ||||
| 		return -EINVAL; | ||||
|  | @ -410,3 +416,7 @@ int snd_pcm_plugin_build_rate(snd_pcm_format_t *src_format, | |||
| 	*r_plugin = plugin; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef __KERNEL__ | ||||
| EXPORT_SYMBOL(snd_pcm_plugin_build_rate); | ||||
| #endif | ||||
|  |  | |||
|  | @ -19,6 +19,10 @@ | |||
|  * | ||||
|  */ | ||||
|    | ||||
| #ifdef __KERNEL__ | ||||
| #include "../../include/driver.h" | ||||
| #include "../../include/pcm_plugin.h" | ||||
| #else | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
|  | @ -27,6 +31,7 @@ | |||
| #include <endian.h> | ||||
| #include <byteswap.h> | ||||
| #include "../pcm_local.h" | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  *  Basic voices conversion plugin | ||||
|  | @ -59,7 +64,6 @@ static void merge_8bit_unsigned(unsigned char *src_ptr, | |||
| 			        unsigned char *dst_ptr, | ||||
| 			        int size) | ||||
| { | ||||
| 	printf("unsigned!!\n"); | ||||
| 	while (size-- > 0) { | ||||
| 		*dst_ptr++ = ((int)*src_ptr + (int)*(src_ptr + 1)) / 2; | ||||
| 		src_ptr += 2; | ||||
|  | @ -170,7 +174,8 @@ int snd_pcm_plugin_build_voices(snd_pcm_format_t *src_format, | |||
| 		return -EINVAL; | ||||
| 	*r_plugin = NULL; | ||||
| 
 | ||||
| 	if (src_format->interleave != dst_format->interleave) | ||||
| 	if (src_format->interleave != dst_format->interleave &&  | ||||
| 	    src_format->voices > 1) | ||||
| 		return -EINVAL; | ||||
| 	if (!dst_format->interleave) | ||||
| 		return -EINVAL; | ||||
|  | @ -202,3 +207,7 @@ int snd_pcm_plugin_build_voices(snd_pcm_format_t *src_format, | |||
| 	*r_plugin = plugin; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef __KERNEL__ | ||||
| EXPORT_SYMBOL(snd_pcm_plugin_build_voices); | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jaroslav Kysela
						Jaroslav Kysela