| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  Rate conversion Plug-In | 
					
						
							| 
									
										
										
										
											2007-10-15 09:50:19 +02:00
										 |  |  |  *  Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  | #include <linux/time.h>
 | 
					
						
							|  |  |  | #include <sound/core.h>
 | 
					
						
							|  |  |  | #include <sound/pcm.h>
 | 
					
						
							|  |  |  | #include "pcm_plugin.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SHIFT	11
 | 
					
						
							|  |  |  | #define BITS	(1<<SHIFT)
 | 
					
						
							|  |  |  | #define R_MASK	(BITS-1)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  *  Basic rate conversion plugin | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | struct rate_channel { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	signed short last_S1; | 
					
						
							|  |  |  | 	signed short last_S2; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |   | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | typedef void (*rate_f)(struct snd_pcm_plugin *plugin, | 
					
						
							|  |  |  | 		       const struct snd_pcm_plugin_channel *src_channels, | 
					
						
							|  |  |  | 		       struct snd_pcm_plugin_channel *dst_channels, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		       int src_frames, int dst_frames); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | struct rate_priv { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	unsigned int pitch; | 
					
						
							|  |  |  | 	unsigned int pos; | 
					
						
							|  |  |  | 	rate_f func; | 
					
						
							|  |  |  | 	snd_pcm_sframes_t old_src_frames, old_dst_frames; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	struct rate_channel channels[0]; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | static void rate_init(struct snd_pcm_plugin *plugin) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned int channel; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	struct rate_priv *data = (struct rate_priv *)plugin->extra_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	data->pos = 0; | 
					
						
							|  |  |  | 	for (channel = 0; channel < plugin->src_format.channels; channel++) { | 
					
						
							|  |  |  | 		data->channels[channel].last_S1 = 0; | 
					
						
							|  |  |  | 		data->channels[channel].last_S2 = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | static void resample_expand(struct snd_pcm_plugin *plugin, | 
					
						
							|  |  |  | 			    const struct snd_pcm_plugin_channel *src_channels, | 
					
						
							|  |  |  | 			    struct snd_pcm_plugin_channel *dst_channels, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			    int src_frames, int dst_frames) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int pos = 0; | 
					
						
							|  |  |  | 	signed int val; | 
					
						
							|  |  |  | 	signed short S1, S2; | 
					
						
							| 
									
										
										
										
											2006-01-13 12:09:12 +01:00
										 |  |  | 	signed short *src, *dst; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	unsigned int channel; | 
					
						
							|  |  |  | 	int src_step, dst_step; | 
					
						
							|  |  |  | 	int src_frames1, dst_frames1; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	struct rate_priv *data = (struct rate_priv *)plugin->extra_data; | 
					
						
							|  |  |  | 	struct rate_channel *rchannels = data->channels; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	for (channel = 0; channel < plugin->src_format.channels; channel++) { | 
					
						
							|  |  |  | 		pos = data->pos; | 
					
						
							|  |  |  | 		S1 = rchannels->last_S1; | 
					
						
							|  |  |  | 		S2 = rchannels->last_S2; | 
					
						
							|  |  |  | 		if (!src_channels[channel].enabled) { | 
					
						
							|  |  |  | 			if (dst_channels[channel].wanted) | 
					
						
							|  |  |  | 				snd_pcm_area_silence(&dst_channels[channel].area, 0, dst_frames, plugin->dst_format.format); | 
					
						
							|  |  |  | 			dst_channels[channel].enabled = 0; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		dst_channels[channel].enabled = 1; | 
					
						
							| 
									
										
										
										
											2006-01-13 12:09:12 +01:00
										 |  |  | 		src = (signed short *)src_channels[channel].area.addr + | 
					
						
							|  |  |  | 			src_channels[channel].area.first / 8 / 2; | 
					
						
							|  |  |  | 		dst = (signed short *)dst_channels[channel].area.addr + | 
					
						
							|  |  |  | 			dst_channels[channel].area.first / 8 / 2; | 
					
						
							|  |  |  | 		src_step = src_channels[channel].area.step / 8 / 2; | 
					
						
							|  |  |  | 		dst_step = dst_channels[channel].area.step / 8 / 2; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		src_frames1 = src_frames; | 
					
						
							|  |  |  | 		dst_frames1 = dst_frames; | 
					
						
							|  |  |  | 		while (dst_frames1-- > 0) { | 
					
						
							|  |  |  | 			if (pos & ~R_MASK) { | 
					
						
							|  |  |  | 				pos &= R_MASK; | 
					
						
							|  |  |  | 				S1 = S2; | 
					
						
							|  |  |  | 				if (src_frames1-- > 0) { | 
					
						
							| 
									
										
										
										
											2006-01-13 12:09:12 +01:00
										 |  |  | 					S2 = *src; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 					src += src_step; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			val = S1 + ((S2 - S1) * (signed int)pos) / BITS; | 
					
						
							|  |  |  | 			if (val < -32768) | 
					
						
							|  |  |  | 				val = -32768; | 
					
						
							|  |  |  | 			else if (val > 32767) | 
					
						
							|  |  |  | 				val = 32767; | 
					
						
							| 
									
										
										
										
											2006-01-13 12:09:12 +01:00
										 |  |  | 			*dst = val; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			dst += dst_step; | 
					
						
							|  |  |  | 			pos += data->pitch; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		rchannels->last_S1 = S1; | 
					
						
							|  |  |  | 		rchannels->last_S2 = S2; | 
					
						
							|  |  |  | 		rchannels++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data->pos = pos; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | static void resample_shrink(struct snd_pcm_plugin *plugin, | 
					
						
							|  |  |  | 			    const struct snd_pcm_plugin_channel *src_channels, | 
					
						
							|  |  |  | 			    struct snd_pcm_plugin_channel *dst_channels, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			    int src_frames, int dst_frames) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int pos = 0; | 
					
						
							|  |  |  | 	signed int val; | 
					
						
							|  |  |  | 	signed short S1, S2; | 
					
						
							| 
									
										
										
										
											2006-01-13 12:09:12 +01:00
										 |  |  | 	signed short *src, *dst; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	unsigned int channel; | 
					
						
							|  |  |  | 	int src_step, dst_step; | 
					
						
							|  |  |  | 	int src_frames1, dst_frames1; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	struct rate_priv *data = (struct rate_priv *)plugin->extra_data; | 
					
						
							|  |  |  | 	struct rate_channel *rchannels = data->channels; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (channel = 0; channel < plugin->src_format.channels; ++channel) { | 
					
						
							|  |  |  | 		pos = data->pos; | 
					
						
							|  |  |  | 		S1 = rchannels->last_S1; | 
					
						
							|  |  |  | 		S2 = rchannels->last_S2; | 
					
						
							|  |  |  | 		if (!src_channels[channel].enabled) { | 
					
						
							|  |  |  | 			if (dst_channels[channel].wanted) | 
					
						
							|  |  |  | 				snd_pcm_area_silence(&dst_channels[channel].area, 0, dst_frames, plugin->dst_format.format); | 
					
						
							|  |  |  | 			dst_channels[channel].enabled = 0; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		dst_channels[channel].enabled = 1; | 
					
						
							| 
									
										
										
										
											2006-01-13 12:09:12 +01:00
										 |  |  | 		src = (signed short *)src_channels[channel].area.addr + | 
					
						
							|  |  |  | 			src_channels[channel].area.first / 8 / 2; | 
					
						
							|  |  |  | 		dst = (signed short *)dst_channels[channel].area.addr + | 
					
						
							|  |  |  | 			dst_channels[channel].area.first / 8 / 2; | 
					
						
							|  |  |  | 		src_step = src_channels[channel].area.step / 8 / 2; | 
					
						
							|  |  |  | 		dst_step = dst_channels[channel].area.step / 8 / 2; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		src_frames1 = src_frames; | 
					
						
							|  |  |  | 		dst_frames1 = dst_frames; | 
					
						
							|  |  |  | 		while (dst_frames1 > 0) { | 
					
						
							|  |  |  | 			S1 = S2; | 
					
						
							|  |  |  | 			if (src_frames1-- > 0) { | 
					
						
							| 
									
										
										
										
											2009-02-21 08:05:04 -06:00
										 |  |  | 				S2 = *src; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				src += src_step; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (pos & ~R_MASK) { | 
					
						
							|  |  |  | 				pos &= R_MASK; | 
					
						
							|  |  |  | 				val = S1 + ((S2 - S1) * (signed int)pos) / BITS; | 
					
						
							|  |  |  | 				if (val < -32768) | 
					
						
							|  |  |  | 					val = -32768; | 
					
						
							|  |  |  | 				else if (val > 32767) | 
					
						
							|  |  |  | 					val = 32767; | 
					
						
							| 
									
										
										
										
											2006-01-13 12:09:12 +01:00
										 |  |  | 				*dst = val; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				dst += dst_step; | 
					
						
							|  |  |  | 				dst_frames1--; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			pos += data->pitch; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		rchannels->last_S1 = S1; | 
					
						
							|  |  |  | 		rchannels->last_S2 = S2; | 
					
						
							|  |  |  | 		rchannels++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data->pos = pos; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | static snd_pcm_sframes_t rate_src_frames(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	struct rate_priv *data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	snd_pcm_sframes_t res; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 	if (snd_BUG_ON(!plugin)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (frames == 0) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	data = (struct rate_priv *)plugin->extra_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (plugin->src_format.rate < plugin->dst_format.rate) { | 
					
						
							|  |  |  | 		res = (((frames * data->pitch) + (BITS/2)) >> SHIFT); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch);		 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (data->old_src_frames > 0) { | 
					
						
							|  |  |  | 		snd_pcm_sframes_t frames1 = frames, res1 = data->old_dst_frames; | 
					
						
							|  |  |  | 		while (data->old_src_frames < frames1) { | 
					
						
							|  |  |  | 			frames1 >>= 1; | 
					
						
							|  |  |  | 			res1 <<= 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		while (data->old_src_frames > frames1) { | 
					
						
							|  |  |  | 			frames1 <<= 1; | 
					
						
							|  |  |  | 			res1 >>= 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (data->old_src_frames == frames1) | 
					
						
							|  |  |  | 			return res1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data->old_src_frames = frames; | 
					
						
							|  |  |  | 	data->old_dst_frames = res; | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | static snd_pcm_sframes_t rate_dst_frames(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	struct rate_priv *data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	snd_pcm_sframes_t res; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 	if (snd_BUG_ON(!plugin)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (frames == 0) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	data = (struct rate_priv *)plugin->extra_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (plugin->src_format.rate < plugin->dst_format.rate) { | 
					
						
							|  |  |  | 		res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		res = (((frames * data->pitch) + (BITS/2)) >> SHIFT); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (data->old_dst_frames > 0) { | 
					
						
							|  |  |  | 		snd_pcm_sframes_t frames1 = frames, res1 = data->old_src_frames; | 
					
						
							|  |  |  | 		while (data->old_dst_frames < frames1) { | 
					
						
							|  |  |  | 			frames1 >>= 1; | 
					
						
							|  |  |  | 			res1 <<= 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		while (data->old_dst_frames > frames1) { | 
					
						
							|  |  |  | 			frames1 <<= 1; | 
					
						
							|  |  |  | 			res1 >>= 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (data->old_dst_frames == frames1) | 
					
						
							|  |  |  | 			return res1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data->old_dst_frames = frames; | 
					
						
							|  |  |  | 	data->old_src_frames = res; | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | static snd_pcm_sframes_t rate_transfer(struct snd_pcm_plugin *plugin, | 
					
						
							|  |  |  | 			     const struct snd_pcm_plugin_channel *src_channels, | 
					
						
							|  |  |  | 			     struct snd_pcm_plugin_channel *dst_channels, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			     snd_pcm_uframes_t frames) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	snd_pcm_uframes_t dst_frames; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	struct rate_priv *data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 	if (snd_BUG_ON(!plugin || !src_channels || !dst_channels)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (frames == 0) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | #ifdef CONFIG_SND_DEBUG
 | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		unsigned int channel; | 
					
						
							|  |  |  | 		for (channel = 0; channel < plugin->src_format.channels; channel++) { | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 			if (snd_BUG_ON(src_channels[channel].area.first % 8 || | 
					
						
							|  |  |  | 				       src_channels[channel].area.step % 8)) | 
					
						
							|  |  |  | 				return -ENXIO; | 
					
						
							|  |  |  | 			if (snd_BUG_ON(dst_channels[channel].area.first % 8 || | 
					
						
							|  |  |  | 				       dst_channels[channel].area.step % 8)) | 
					
						
							|  |  |  | 				return -ENXIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dst_frames = rate_dst_frames(plugin, frames); | 
					
						
							|  |  |  | 	if (dst_frames > dst_channels[0].frames) | 
					
						
							|  |  |  | 		dst_frames = dst_channels[0].frames; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	data = (struct rate_priv *)plugin->extra_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	data->func(plugin, src_channels, dst_channels, frames, dst_frames); | 
					
						
							|  |  |  | 	return dst_frames; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | static int rate_action(struct snd_pcm_plugin *plugin, | 
					
						
							|  |  |  | 		       enum snd_pcm_plugin_action action, | 
					
						
							| 
									
										
										
										
											2005-11-17 10:18:00 +01:00
										 |  |  | 		       unsigned long udata) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 	if (snd_BUG_ON(!plugin)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	switch (action) { | 
					
						
							|  |  |  | 	case INIT: | 
					
						
							|  |  |  | 	case PREPARE: | 
					
						
							|  |  |  | 		rate_init(plugin); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0;	/* silenty ignore other actions */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | int snd_pcm_plugin_build_rate(struct snd_pcm_substream *plug, | 
					
						
							|  |  |  | 			      struct snd_pcm_plugin_format *src_format, | 
					
						
							|  |  |  | 			      struct snd_pcm_plugin_format *dst_format, | 
					
						
							|  |  |  | 			      struct snd_pcm_plugin **r_plugin) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int err; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	struct rate_priv *data; | 
					
						
							|  |  |  | 	struct snd_pcm_plugin *plugin; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 	if (snd_BUG_ON(!r_plugin)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	*r_plugin = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 	if (snd_BUG_ON(src_format->channels != dst_format->channels)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							|  |  |  | 	if (snd_BUG_ON(src_format->channels <= 0)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							|  |  |  | 	if (snd_BUG_ON(src_format->format != SNDRV_PCM_FORMAT_S16)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							|  |  |  | 	if (snd_BUG_ON(dst_format->format != SNDRV_PCM_FORMAT_S16)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							|  |  |  | 	if (snd_BUG_ON(src_format->rate == dst_format->rate)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	err = snd_pcm_plugin_build(plug, "rate conversion", | 
					
						
							|  |  |  | 				   src_format, dst_format, | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 				   sizeof(struct rate_priv) + | 
					
						
							|  |  |  | 				   src_format->channels * sizeof(struct rate_channel), | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				   &plugin); | 
					
						
							|  |  |  | 	if (err < 0) | 
					
						
							|  |  |  | 		return err; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:49 +01:00
										 |  |  | 	data = (struct rate_priv *)plugin->extra_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (src_format->rate < dst_format->rate) { | 
					
						
							|  |  |  | 		data->pitch = ((src_format->rate << SHIFT) + (dst_format->rate >> 1)) / dst_format->rate; | 
					
						
							|  |  |  | 		data->func = resample_expand; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		data->pitch = ((dst_format->rate << SHIFT) + (src_format->rate >> 1)) / src_format->rate; | 
					
						
							|  |  |  | 		data->func = resample_shrink; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	data->pos = 0; | 
					
						
							|  |  |  | 	rate_init(plugin); | 
					
						
							|  |  |  | 	data->old_src_frames = data->old_dst_frames = 0; | 
					
						
							|  |  |  | 	plugin->transfer = rate_transfer; | 
					
						
							|  |  |  | 	plugin->src_frames = rate_src_frames; | 
					
						
							|  |  |  | 	plugin->dst_frames = rate_dst_frames; | 
					
						
							|  |  |  | 	plugin->action = rate_action; | 
					
						
							|  |  |  | 	*r_plugin = plugin; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } |