diff options
Diffstat (limited to 'sound/core/oss/mulaw.c')
-rw-r--r-- | sound/core/oss/mulaw.c | 90 |
1 files changed, 49 insertions, 41 deletions
diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c index 2eb18807e6d0..848db82529ed 100644 --- a/sound/core/oss/mulaw.c +++ b/sound/core/oss/mulaw.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Mu-Law conversion Plug-In Interface | 2 | * Mu-Law conversion Plug-In Interface |
3 | * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> | 3 | * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> |
4 | * Uros Bizjak <uros@kss-loka.si> | 4 | * Uros Bizjak <uros@kss-loka.si> |
5 | * | 5 | * |
6 | * Based on reference implementation by Sun Microsystems, Inc. | 6 | * Based on reference implementation by Sun Microsystems, Inc. |
@@ -22,9 +22,6 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | 24 | #include <sound/driver.h> |
25 | |||
26 | #ifdef CONFIG_SND_PCM_OSS_PLUGINS | ||
27 | |||
28 | #include <linux/time.h> | 25 | #include <linux/time.h> |
29 | #include <sound/core.h> | 26 | #include <sound/core.h> |
30 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
@@ -149,19 +146,32 @@ typedef void (*mulaw_f)(struct snd_pcm_plugin *plugin, | |||
149 | 146 | ||
150 | struct mulaw_priv { | 147 | struct mulaw_priv { |
151 | mulaw_f func; | 148 | mulaw_f func; |
152 | int conv; | 149 | int cvt_endian; /* need endian conversion? */ |
150 | unsigned int native_ofs; /* byte offset in native format */ | ||
151 | unsigned int copy_ofs; /* byte offset in s16 format */ | ||
152 | unsigned int native_bytes; /* byte size of the native format */ | ||
153 | unsigned int copy_bytes; /* bytes to copy per conversion */ | ||
154 | u16 flip; /* MSB flip for signedness, done after endian conversion */ | ||
153 | }; | 155 | }; |
154 | 156 | ||
157 | static inline void cvt_s16_to_native(struct mulaw_priv *data, | ||
158 | unsigned char *dst, u16 sample) | ||
159 | { | ||
160 | sample ^= data->flip; | ||
161 | if (data->cvt_endian) | ||
162 | sample = swab16(sample); | ||
163 | if (data->native_bytes > data->copy_bytes) | ||
164 | memset(dst, 0, data->native_bytes); | ||
165 | memcpy(dst + data->native_ofs, (char *)&sample + data->copy_ofs, | ||
166 | data->copy_bytes); | ||
167 | } | ||
168 | |||
155 | static void mulaw_decode(struct snd_pcm_plugin *plugin, | 169 | static void mulaw_decode(struct snd_pcm_plugin *plugin, |
156 | const struct snd_pcm_plugin_channel *src_channels, | 170 | const struct snd_pcm_plugin_channel *src_channels, |
157 | struct snd_pcm_plugin_channel *dst_channels, | 171 | struct snd_pcm_plugin_channel *dst_channels, |
158 | snd_pcm_uframes_t frames) | 172 | snd_pcm_uframes_t frames) |
159 | { | 173 | { |
160 | #define PUT_S16_LABELS | ||
161 | #include "plugin_ops.h" | ||
162 | #undef PUT_S16_LABELS | ||
163 | struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; | 174 | struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; |
164 | void *put = put_s16_labels[data->conv]; | ||
165 | int channel; | 175 | int channel; |
166 | int nchannels = plugin->src_format.channels; | 176 | int nchannels = plugin->src_format.channels; |
167 | for (channel = 0; channel < nchannels; ++channel) { | 177 | for (channel = 0; channel < nchannels; ++channel) { |
@@ -183,30 +193,33 @@ static void mulaw_decode(struct snd_pcm_plugin *plugin, | |||
183 | frames1 = frames; | 193 | frames1 = frames; |
184 | while (frames1-- > 0) { | 194 | while (frames1-- > 0) { |
185 | signed short sample = ulaw2linear(*src); | 195 | signed short sample = ulaw2linear(*src); |
186 | goto *put; | 196 | cvt_s16_to_native(data, dst, sample); |
187 | #define PUT_S16_END after | ||
188 | #include "plugin_ops.h" | ||
189 | #undef PUT_S16_END | ||
190 | after: | ||
191 | src += src_step; | 197 | src += src_step; |
192 | dst += dst_step; | 198 | dst += dst_step; |
193 | } | 199 | } |
194 | } | 200 | } |
195 | } | 201 | } |
196 | 202 | ||
203 | static inline signed short cvt_native_to_s16(struct mulaw_priv *data, | ||
204 | unsigned char *src) | ||
205 | { | ||
206 | u16 sample = 0; | ||
207 | memcpy((char *)&sample + data->copy_ofs, src + data->native_ofs, | ||
208 | data->copy_bytes); | ||
209 | if (data->cvt_endian) | ||
210 | sample = swab16(sample); | ||
211 | sample ^= data->flip; | ||
212 | return (signed short)sample; | ||
213 | } | ||
214 | |||
197 | static void mulaw_encode(struct snd_pcm_plugin *plugin, | 215 | static void mulaw_encode(struct snd_pcm_plugin *plugin, |
198 | const struct snd_pcm_plugin_channel *src_channels, | 216 | const struct snd_pcm_plugin_channel *src_channels, |
199 | struct snd_pcm_plugin_channel *dst_channels, | 217 | struct snd_pcm_plugin_channel *dst_channels, |
200 | snd_pcm_uframes_t frames) | 218 | snd_pcm_uframes_t frames) |
201 | { | 219 | { |
202 | #define GET_S16_LABELS | ||
203 | #include "plugin_ops.h" | ||
204 | #undef GET_S16_LABELS | ||
205 | struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; | 220 | struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; |
206 | void *get = get_s16_labels[data->conv]; | ||
207 | int channel; | 221 | int channel; |
208 | int nchannels = plugin->src_format.channels; | 222 | int nchannels = plugin->src_format.channels; |
209 | signed short sample = 0; | ||
210 | for (channel = 0; channel < nchannels; ++channel) { | 223 | for (channel = 0; channel < nchannels; ++channel) { |
211 | char *src; | 224 | char *src; |
212 | char *dst; | 225 | char *dst; |
@@ -225,11 +238,7 @@ static void mulaw_encode(struct snd_pcm_plugin *plugin, | |||
225 | dst_step = dst_channels[channel].area.step / 8; | 238 | dst_step = dst_channels[channel].area.step / 8; |
226 | frames1 = frames; | 239 | frames1 = frames; |
227 | while (frames1-- > 0) { | 240 | while (frames1-- > 0) { |
228 | goto *get; | 241 | signed short sample = cvt_native_to_s16(data, src); |
229 | #define GET_S16_END after | ||
230 | #include "plugin_ops.h" | ||
231 | #undef GET_S16_END | ||
232 | after: | ||
233 | *dst = linear2ulaw(sample); | 242 | *dst = linear2ulaw(sample); |
234 | src += src_step; | 243 | src += src_step; |
235 | dst += dst_step; | 244 | dst += dst_step; |
@@ -265,23 +274,25 @@ static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin, | |||
265 | return frames; | 274 | return frames; |
266 | } | 275 | } |
267 | 276 | ||
268 | static int getput_index(int format) | 277 | static void init_data(struct mulaw_priv *data, int format) |
269 | { | 278 | { |
270 | int sign, width, endian; | ||
271 | sign = !snd_pcm_format_signed(format); | ||
272 | width = snd_pcm_format_width(format) / 8 - 1; | ||
273 | if (width < 0 || width > 3) { | ||
274 | snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format); | ||
275 | width = 0; | ||
276 | } | ||
277 | #ifdef SNDRV_LITTLE_ENDIAN | 279 | #ifdef SNDRV_LITTLE_ENDIAN |
278 | endian = snd_pcm_format_big_endian(format); | 280 | data->cvt_endian = snd_pcm_format_big_endian(format) > 0; |
279 | #else | 281 | #else |
280 | endian = snd_pcm_format_little_endian(format); | 282 | data->cvt_endian = snd_pcm_format_little_endian(format) > 0; |
281 | #endif | 283 | #endif |
282 | if (endian < 0) | 284 | if (!snd_pcm_format_signed(format)) |
283 | endian = 0; | 285 | data->flip = 0x8000; |
284 | return width * 4 + endian * 2 + sign; | 286 | data->native_bytes = snd_pcm_format_physical_width(format) / 8; |
287 | data->copy_bytes = data->native_bytes < 2 ? 1 : 2; | ||
288 | if (snd_pcm_format_little_endian(format)) { | ||
289 | data->native_ofs = data->native_bytes - data->copy_bytes; | ||
290 | data->copy_ofs = 2 - data->copy_bytes; | ||
291 | } else { | ||
292 | /* S24 in 4bytes need an 1 byte offset */ | ||
293 | data->native_ofs = data->native_bytes - | ||
294 | snd_pcm_format_width(format) / 8; | ||
295 | } | ||
285 | } | 296 | } |
286 | 297 | ||
287 | int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug, | 298 | int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug, |
@@ -322,11 +333,8 @@ int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug, | |||
322 | return err; | 333 | return err; |
323 | data = (struct mulaw_priv *)plugin->extra_data; | 334 | data = (struct mulaw_priv *)plugin->extra_data; |
324 | data->func = func; | 335 | data->func = func; |
325 | data->conv = getput_index(format->format); | 336 | init_data(data, format->format); |
326 | snd_assert(data->conv >= 0 && data->conv < 4*2*2, return -EINVAL); | ||
327 | plugin->transfer = mulaw_transfer; | 337 | plugin->transfer = mulaw_transfer; |
328 | *r_plugin = plugin; | 338 | *r_plugin = plugin; |
329 | return 0; | 339 | return 0; |
330 | } | 340 | } |
331 | |||
332 | #endif | ||