diff options
author | Takashi Iwai <tiwai@suse.de> | 2007-08-08 15:50:58 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2007-10-16 15:58:31 +0200 |
commit | 9390ec85c0ab98444140190f936a37fa4eb945a2 (patch) | |
tree | e5b464f2462335399e8e59203617439fb77ff51e /sound/core/oss/linear.c | |
parent | 887f9f0253ba4a52f38810f3056cdf040a6157b3 (diff) |
[ALSA] Simplify the format conversion in PCM OSS emulation
Simplify the format conversion code in PCM OSS emulation.
This patch also adds the support of 3bytes 24bit formats with linear
and mulaw, but they are not enabled in pcm_plugin.c yet.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/core/oss/linear.c')
-rw-r--r-- | sound/core/oss/linear.c | 80 |
1 files changed, 49 insertions, 31 deletions
diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c index a3cfe7cb5873..41b2885d0903 100644 --- a/sound/core/oss/linear.c +++ b/sound/core/oss/linear.c @@ -31,19 +31,34 @@ */ struct linear_priv { - int conv; + int cvt_endian; /* need endian conversion? */ + unsigned int src_ofs; /* byte offset in source format */ + unsigned int dst_ofs; /* byte soffset in destination format */ + unsigned int copy_ofs; /* byte offset in temporary u32 data */ + unsigned int dst_bytes; /* byte size of destination format */ + unsigned int copy_bytes; /* bytes to copy per conversion */ + unsigned int flip; /* MSB flip for signeness, done after endian conv */ }; +static inline void do_convert(struct linear_priv *data, + unsigned char *dst, unsigned char *src) +{ + unsigned int tmp = 0; + unsigned char *p = (unsigned char *)&tmp; + + memcpy(p + data->copy_ofs, src + data->src_ofs, data->copy_bytes); + if (data->cvt_endian) + tmp = swab32(tmp); + tmp ^= data->flip; + memcpy(dst, p + data->dst_ofs, data->dst_bytes); +} + static void convert(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 CONV_LABELS -#include "plugin_ops.h" -#undef CONV_LABELS struct linear_priv *data = (struct linear_priv *)plugin->extra_data; - void *conv = conv_labels[data->conv]; int channel; int nchannels = plugin->src_format.channels; for (channel = 0; channel < nchannels; ++channel) { @@ -64,11 +79,7 @@ static void convert(struct snd_pcm_plugin *plugin, dst_step = dst_channels[channel].area.step / 8; frames1 = frames; while (frames1-- > 0) { - goto *conv; -#define CONV_END after -#include "plugin_ops.h" -#undef CONV_END - after: + do_convert(data, dst, src); src += src_step; dst += dst_step; } @@ -103,29 +114,36 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin, return frames; } -static int conv_index(int src_format, int dst_format) +static void init_data(struct linear_priv *data, int src_format, int dst_format) { - int src_endian, dst_endian, sign, src_width, dst_width; + int src_le, dst_le, src_bytes, dst_bytes; - sign = (snd_pcm_format_signed(src_format) != - snd_pcm_format_signed(dst_format)); -#ifdef SNDRV_LITTLE_ENDIAN - src_endian = snd_pcm_format_big_endian(src_format); - dst_endian = snd_pcm_format_big_endian(dst_format); -#else - src_endian = snd_pcm_format_little_endian(src_format); - dst_endian = snd_pcm_format_little_endian(dst_format); -#endif - - if (src_endian < 0) - src_endian = 0; - if (dst_endian < 0) - dst_endian = 0; + src_bytes = snd_pcm_format_width(src_format) / 8; + dst_bytes = snd_pcm_format_width(dst_format) / 8; + src_le = snd_pcm_format_little_endian(src_format) > 0; + dst_le = snd_pcm_format_little_endian(dst_format) > 0; - src_width = snd_pcm_format_width(src_format) / 8 - 1; - dst_width = snd_pcm_format_width(dst_format) / 8 - 1; - - return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian; + data->dst_bytes = dst_bytes; + data->cvt_endian = src_le != dst_le; + data->copy_bytes = src_bytes < dst_bytes ? src_bytes : dst_bytes; + if (src_le) { + data->copy_ofs = 4 - data->copy_bytes; + data->src_ofs = src_bytes - data->copy_bytes; + } else + data->src_ofs = snd_pcm_format_physical_width(src_format) / 8 - + src_bytes; + if (dst_le) + data->dst_ofs = 4 - data->dst_bytes; + else + data->dst_ofs = snd_pcm_format_physical_width(dst_format) / 8 - + dst_bytes; + if (snd_pcm_format_signed(src_format) != + snd_pcm_format_signed(dst_format)) { + if (dst_le) + data->flip = cpu_to_le32(0x80000000); + else + data->flip = cpu_to_be32(0x80000000); + } } int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug, @@ -151,7 +169,7 @@ int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug, if (err < 0) return err; data = (struct linear_priv *)plugin->extra_data; - data->conv = conv_index(src_format->format, dst_format->format); + init_data(data, src_format->format, dst_format->format); plugin->transfer = linear_transfer; *r_plugin = plugin; return 0; |