summaryrefslogtreecommitdiffstats
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.c83
1 files changed, 48 insertions, 35 deletions
diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c
index 91b62429b323..3da3b81626d3 100644
--- a/sound/core/oss/mulaw.c
+++ b/sound/core/oss/mulaw.c
@@ -146,19 +146,32 @@ typedef void (*mulaw_f)(struct snd_pcm_plugin *plugin,
struct mulaw_priv {
mulaw_f func;
- int conv;
+ int cvt_endian; /* need endian conversion? */
+ unsigned int native_ofs; /* byte offset in native format */
+ unsigned int copy_ofs; /* byte offset in s16 format */
+ unsigned int native_bytes; /* byte size of the native format */
+ unsigned int copy_bytes; /* bytes to copy per conversion */
+ u16 flip; /* MSB flip for signedness, done after endian conversion */
};
+static inline void cvt_s16_to_native(struct mulaw_priv *data,
+ unsigned char *dst, u16 sample)
+{
+ sample ^= data->flip;
+ if (data->cvt_endian)
+ sample = swab16(sample);
+ if (data->native_bytes > data->copy_bytes)
+ memset(dst, 0, data->native_bytes);
+ memcpy(dst + data->native_ofs, (char *)&sample + data->copy_ofs,
+ data->copy_bytes);
+}
+
static void mulaw_decode(struct snd_pcm_plugin *plugin,
const struct snd_pcm_plugin_channel *src_channels,
struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames)
{
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef PUT_S16_LABELS
struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data;
- void *put = put_s16_labels[data->conv];
int channel;
int nchannels = plugin->src_format.channels;
for (channel = 0; channel < nchannels; ++channel) {
@@ -180,30 +193,33 @@ static void mulaw_decode(struct snd_pcm_plugin *plugin,
frames1 = frames;
while (frames1-- > 0) {
signed short sample = ulaw2linear(*src);
- goto *put;
-#define PUT_S16_END after
-#include "plugin_ops.h"
-#undef PUT_S16_END
- after:
+ cvt_s16_to_native(data, dst, sample);
src += src_step;
dst += dst_step;
}
}
}
+static inline signed short cvt_native_to_s16(struct mulaw_priv *data,
+ unsigned char *src)
+{
+ u16 sample = 0;
+ memcpy((char *)&sample + data->copy_ofs, src + data->native_ofs,
+ data->copy_bytes);
+ if (data->cvt_endian)
+ sample = swab16(sample);
+ sample ^= data->flip;
+ return (signed short)sample;
+}
+
static void mulaw_encode(struct snd_pcm_plugin *plugin,
const struct snd_pcm_plugin_channel *src_channels,
struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames)
{
-#define GET_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data;
- void *get = get_s16_labels[data->conv];
int channel;
int nchannels = plugin->src_format.channels;
- signed short sample = 0;
for (channel = 0; channel < nchannels; ++channel) {
char *src;
char *dst;
@@ -222,11 +238,7 @@ static void mulaw_encode(struct snd_pcm_plugin *plugin,
dst_step = dst_channels[channel].area.step / 8;
frames1 = frames;
while (frames1-- > 0) {
- goto *get;
-#define GET_S16_END after
-#include "plugin_ops.h"
-#undef GET_S16_END
- after:
+ signed short sample = cvt_native_to_s16(data, src);
*dst = linear2ulaw(sample);
src += src_step;
dst += dst_step;
@@ -262,23 +274,25 @@ static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin,
return frames;
}
-static int getput_index(int format)
+static void init_data(struct mulaw_priv *data, int format)
{
- int sign, width, endian;
- sign = !snd_pcm_format_signed(format);
- width = snd_pcm_format_width(format) / 8 - 1;
- if (width < 0 || width > 3) {
- snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format);
- width = 0;
- }
#ifdef SNDRV_LITTLE_ENDIAN
- endian = snd_pcm_format_big_endian(format);
+ data->cvt_endian = snd_pcm_format_big_endian(format) > 0;
#else
- endian = snd_pcm_format_little_endian(format);
+ data->cvt_endian = snd_pcm_format_little_endian(format) > 0;
#endif
- if (endian < 0)
- endian = 0;
- return width * 4 + endian * 2 + sign;
+ if (!snd_pcm_format_signed(format))
+ data->flip = 0x8000;
+ data->native_bytes = snd_pcm_format_physical_width(format) / 8;
+ data->copy_bytes = data->native_bytes < 2 ? 1 : 2;
+ if (snd_pcm_format_little_endian(format)) {
+ data->native_ofs = data->native_bytes - data->copy_bytes;
+ data->copy_ofs = 2 - data->copy_bytes;
+ } else {
+ /* S24 in 4bytes need an 1 byte offset */
+ data->native_ofs = data->native_bytes -
+ snd_pcm_format_width(format) / 8;
+ }
}
int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug,
@@ -319,8 +333,7 @@ int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug,
return err;
data = (struct mulaw_priv *)plugin->extra_data;
data->func = func;
- data->conv = getput_index(format->format);
- snd_assert(data->conv >= 0 && data->conv < 4*2*2, return -EINVAL);
+ init_data(data, format->format);
plugin->transfer = mulaw_transfer;
*r_plugin = plugin;
return 0;
OpenPOWER on IntegriCloud