1 /* 2 * Linear conversion Plug-In 3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>, 4 * Abramo Bagnara <abramo@alsa-project.org> 5 * 6 * 7 * This library is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU Library General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 */ 22 23 #include <sound/driver.h> 24 25 #ifdef CONFIG_SND_PCM_OSS_PLUGINS 26 27 #include <linux/time.h> 28 #include <sound/core.h> 29 #include <sound/pcm.h> 30 #include "pcm_plugin.h" 31 32 /* 33 * Basic linear conversion plugin 34 */ 35 36 struct linear_priv { 37 int conv; 38 }; 39 40 static void convert(struct snd_pcm_plugin *plugin, 41 const struct snd_pcm_plugin_channel *src_channels, 42 struct snd_pcm_plugin_channel *dst_channels, 43 snd_pcm_uframes_t frames) 44 { 45 #define CONV_LABELS 46 #include "plugin_ops.h" 47 #undef CONV_LABELS 48 struct linear_priv *data = (struct linear_priv *)plugin->extra_data; 49 void *conv = conv_labels[data->conv]; 50 int channel; 51 int nchannels = plugin->src_format.channels; 52 for (channel = 0; channel < nchannels; ++channel) { 53 char *src; 54 char *dst; 55 int src_step, dst_step; 56 snd_pcm_uframes_t frames1; 57 if (!src_channels[channel].enabled) { 58 if (dst_channels[channel].wanted) 59 snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format); 60 dst_channels[channel].enabled = 0; 61 continue; 62 } 63 dst_channels[channel].enabled = 1; 64 src = src_channels[channel].area.addr + src_channels[channel].area.first / 8; 65 dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8; 66 src_step = src_channels[channel].area.step / 8; 67 dst_step = dst_channels[channel].area.step / 8; 68 frames1 = frames; 69 while (frames1-- > 0) { 70 goto *conv; 71 #define CONV_END after 72 #include "plugin_ops.h" 73 #undef CONV_END 74 after: 75 src += src_step; 76 dst += dst_step; 77 } 78 } 79 } 80 81 static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin, 82 const struct snd_pcm_plugin_channel *src_channels, 83 struct snd_pcm_plugin_channel *dst_channels, 84 snd_pcm_uframes_t frames) 85 { 86 struct linear_priv *data; 87 88 snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO); 89 data = (struct linear_priv *)plugin->extra_data; 90 if (frames == 0) 91 return 0; 92 #ifdef CONFIG_SND_DEBUG 93 { 94 unsigned int channel; 95 for (channel = 0; channel < plugin->src_format.channels; channel++) { 96 snd_assert(src_channels[channel].area.first % 8 == 0 && 97 src_channels[channel].area.step % 8 == 0, 98 return -ENXIO); 99 snd_assert(dst_channels[channel].area.first % 8 == 0 && 100 dst_channels[channel].area.step % 8 == 0, 101 return -ENXIO); 102 } 103 } 104 #endif 105 convert(plugin, src_channels, dst_channels, frames); 106 return frames; 107 } 108 109 static int conv_index(int src_format, int dst_format) 110 { 111 int src_endian, dst_endian, sign, src_width, dst_width; 112 113 sign = (snd_pcm_format_signed(src_format) != 114 snd_pcm_format_signed(dst_format)); 115 #ifdef SNDRV_LITTLE_ENDIAN 116 src_endian = snd_pcm_format_big_endian(src_format); 117 dst_endian = snd_pcm_format_big_endian(dst_format); 118 #else 119 src_endian = snd_pcm_format_little_endian(src_format); 120 dst_endian = snd_pcm_format_little_endian(dst_format); 121 #endif 122 123 if (src_endian < 0) 124 src_endian = 0; 125 if (dst_endian < 0) 126 dst_endian = 0; 127 128 src_width = snd_pcm_format_width(src_format) / 8 - 1; 129 dst_width = snd_pcm_format_width(dst_format) / 8 - 1; 130 131 return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian; 132 } 133 134 int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug, 135 struct snd_pcm_plugin_format *src_format, 136 struct snd_pcm_plugin_format *dst_format, 137 struct snd_pcm_plugin **r_plugin) 138 { 139 int err; 140 struct linear_priv *data; 141 struct snd_pcm_plugin *plugin; 142 143 snd_assert(r_plugin != NULL, return -ENXIO); 144 *r_plugin = NULL; 145 146 snd_assert(src_format->rate == dst_format->rate, return -ENXIO); 147 snd_assert(src_format->channels == dst_format->channels, return -ENXIO); 148 snd_assert(snd_pcm_format_linear(src_format->format) && 149 snd_pcm_format_linear(dst_format->format), return -ENXIO); 150 151 err = snd_pcm_plugin_build(plug, "linear format conversion", 152 src_format, dst_format, 153 sizeof(struct linear_priv), &plugin); 154 if (err < 0) 155 return err; 156 data = (struct linear_priv *)plugin->extra_data; 157 data->conv = conv_index(src_format->format, dst_format->format); 158 plugin->transfer = linear_transfer; 159 *r_plugin = plugin; 160 return 0; 161 } 162 163 #endif 164