aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/oss/mulaw.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/oss/mulaw.c')
-rw-r--r--sound/core/oss/mulaw.c90
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
150struct mulaw_priv { 147struct 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
157static 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
155static void mulaw_decode(struct snd_pcm_plugin *plugin, 169static 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
203static 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
197static void mulaw_encode(struct snd_pcm_plugin *plugin, 215static 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
268static int getput_index(int format) 277static 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
287int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug, 298int 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