11541Srgrimes/* 21541Srgrimes * Mu-Law conversion Plug-In Interface 31541Srgrimes * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> 41541Srgrimes * Uros Bizjak <uros@kss-loka.si> 521777Sbde * 61541Srgrimes * Based on reference implementation by Sun Microsystems, Inc. 71541Srgrimes * 81541Srgrimes * This library is free software; you can redistribute it and/or modify 92257Ssos * it under the terms of the GNU Library General Public License as 1010907Sbde * published by the Free Software Foundation; either version 2 of 111541Srgrimes * the License, or (at your option) any later version. 121541Srgrimes * 1310907Sbde * This program is distributed in the hope that it will be useful, 141541Srgrimes * but WITHOUT ANY WARRANTY; without even the implied warranty of 1510907Sbde * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 161541Srgrimes * GNU Library General Public License for more details. 171541Srgrimes * 1810907Sbde * You should have received a copy of the GNU Library General Public 191541Srgrimes * License along with this library; if not, write to the Free Software 2010907Sbde * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2110907Sbde * 2210907Sbde */ 2310907Sbde 2410907Sbde#include <linux/time.h> 2510907Sbde#include <sound/core.h> 2610907Sbde#include <sound/pcm.h> 2710907Sbde#include "pcm_plugin.h" 281541Srgrimes 2910907Sbde#define SIGN_BIT (0x80) /* Sign bit for a u-law byte. */ 3010907Sbde#define QUANT_MASK (0xf) /* Quantization field mask. */ 3110907Sbde#define NSEGS (8) /* Number of u-law segments. */ 3210907Sbde#define SEG_SHIFT (4) /* Left shift for segment number. */ 3310907Sbde#define SEG_MASK (0x70) /* Segment field mask. */ 3410907Sbde 3510907Sbdestatic inline int val_seg(int val) 3610907Sbde{ 3710907Sbde int r = 0; 3810907Sbde val >>= 7; 391541Srgrimes if (val & 0xf0) { 4010907Sbde val >>= 4; 4110907Sbde r += 4; 4210907Sbde } 4310907Sbde if (val & 0x0c) { 4410907Sbde val >>= 2; 4510907Sbde r += 2; 4610907Sbde } 4710907Sbde if (val & 0x02) 4810907Sbde r += 1; 4910907Sbde return r; 5010907Sbde} 5111295Sswallace 5211295Sswallace#define BIAS (0x84) /* Bias for linear code. */ 5310907Sbde 5410907Sbde/* 5510907Sbde * linear2ulaw() - Convert a linear PCM value to u-law 5610907Sbde * 5710907Sbde * In order to simplify the encoding process, the original linear magnitude 581541Srgrimes * is biased by adding 33 which shifts the encoding range from (0 - 8158) to 5910907Sbde * (33 - 8191). The result can be seen in the following encoding table: 601541Srgrimes * 6111295Sswallace * Biased Linear Input Code Compressed Code 6210907Sbde * ------------------------ --------------- 6310907Sbde * 00000001wxyza 000wxyz 6410907Sbde * 0000001wxyzab 001wxyz 6510907Sbde * 000001wxyzabc 010wxyz 6610907Sbde * 00001wxyzabcd 011wxyz 6710907Sbde * 0001wxyzabcde 100wxyz 6811295Sswallace * 001wxyzabcdef 101wxyz 6910907Sbde * 01wxyzabcdefg 110wxyz 7010907Sbde * 1wxyzabcdefgh 111wxyz 7110907Sbde * 7210907Sbde * Each biased linear code has a leading 1 which identifies the segment 7311295Sswallace * number. The value of the segment number is equal to 7 minus the number 7410907Sbde * of leading 0's. The quantization interval is directly available as the 7510907Sbde * four bits wxyz. * The trailing bits (a - h) are ignored. 7610907Sbde * 7710907Sbde * Ordinarily the complement of the resulting code word is used for 7810907Sbde * transmission, and so the code word is complemented before it is returned. 7910907Sbde * 8010907Sbde * For further information see John C. Bellamy's Digital Telephony, 1982, 8110907Sbde * John Wiley & Sons, pps 98-111 and 472-476. 821541Srgrimes */ 831541Srgrimesstatic unsigned char linear2ulaw(int pcm_val) /* 2's complement (16-bit range) */ 841541Srgrimes{ 8510907Sbde int mask; 8610907Sbde int seg; 8710907Sbde unsigned char uval; 8810907Sbde 8910907Sbde /* Get the sign and the magnitude of the value. */ 9010907Sbde if (pcm_val < 0) { 911549Srgrimes pcm_val = BIAS - pcm_val; 9210907Sbde mask = 0x7F; 9310907Sbde } else { 9410907Sbde pcm_val += BIAS; 9510907Sbde mask = 0xFF; 9610907Sbde } 9710907Sbde if (pcm_val > 0x7FFF) 9810907Sbde pcm_val = 0x7FFF; 9910907Sbde 10010907Sbde /* Convert the scaled magnitude to segment number. */ 10110907Sbde seg = val_seg(pcm_val); 10210907Sbde 10310907Sbde /* 1041541Srgrimes * Combine the sign, segment, quantization bits; 10510907Sbde * and complement the code word. 10610907Sbde */ 1071541Srgrimes uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF); 1081541Srgrimes return uval ^ mask; 10911295Sswallace} 11010907Sbde 11110907Sbde/* 11210907Sbde * ulaw2linear() - Convert a u-law value to 16-bit linear PCM 11310907Sbde * 11410907Sbde * First, a biased linear code is derived from the code word. An unbiased 11510907Sbde * output can then be obtained by subtracting 33 from the biased code. 11611295Sswallace * 11710907Sbde * Note that this function expects to be passed the complement of the 11810907Sbde * original code word. This is in keeping with ISDN conventions. 1191541Srgrimes */ 12011295Sswallacestatic int ulaw2linear(unsigned char u_val) 1211541Srgrimes{ 1221541Srgrimes int t; 12310907Sbde 12410907Sbde /* Complement to obtain normal u-law value. */ 12510907Sbde u_val = ~u_val; 12610907Sbde 12710907Sbde /* 1281541Srgrimes * Extract and bias the quantization bits. Then 1291541Srgrimes * shift up by the segment number and subtract out the bias. 1301541Srgrimes */ 13110907Sbde t = ((u_val & QUANT_MASK) << 3) + BIAS; 1321541Srgrimes t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; 1331541Srgrimes 1341541Srgrimes return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); 13510907Sbde} 13611295Sswallace 13710907Sbde/* 13810907Sbde * Basic Mu-Law plugin 13914220Speter */ 14010907Sbde 14110907Sbdetypedef void (*mulaw_f)(struct snd_pcm_plugin *plugin, 14211295Sswallace const struct snd_pcm_plugin_channel *src_channels, 14310907Sbde struct snd_pcm_plugin_channel *dst_channels, 14410907Sbde snd_pcm_uframes_t frames); 1451541Srgrimes 14610907Sbdestruct mulaw_priv { 14710907Sbde mulaw_f func; 14810907Sbde int cvt_endian; /* need endian conversion? */ 1491541Srgrimes unsigned int native_ofs; /* byte offset in native format */ 1501541Srgrimes unsigned int copy_ofs; /* byte offset in s16 format */ 15110907Sbde unsigned int native_bytes; /* byte size of the native format */ 15210907Sbde unsigned int copy_bytes; /* bytes to copy per conversion */ 15310907Sbde u16 flip; /* MSB flip for signedness, done after endian conversion */ 15410907Sbde}; 15511295Sswallace 15610907Sbdestatic inline void cvt_s16_to_native(struct mulaw_priv *data, 15710907Sbde unsigned char *dst, u16 sample) 15810907Sbde{ 15910907Sbde sample ^= data->flip; 16010907Sbde if (data->cvt_endian) 1611541Srgrimes sample = swab16(sample); 1621541Srgrimes if (data->native_bytes > data->copy_bytes) 1631541Srgrimes memset(dst, 0, data->native_bytes); 1641541Srgrimes memcpy(dst + data->native_ofs, (char *)&sample + data->copy_ofs, 1651541Srgrimes data->copy_bytes); 1661541Srgrimes} 16710907Sbde 16810907Sbdestatic void mulaw_decode(struct snd_pcm_plugin *plugin, 16911295Sswallace const struct snd_pcm_plugin_channel *src_channels, 1701541Srgrimes struct snd_pcm_plugin_channel *dst_channels, 17114220Speter snd_pcm_uframes_t frames) 17214220Speter{ 17314220Speter struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; 17410907Sbde int channel; 1751541Srgrimes int nchannels = plugin->src_format.channels; 17610907Sbde for (channel = 0; channel < nchannels; ++channel) { 1771541Srgrimes char *src; 17810907Sbde char *dst; 1791541Srgrimes int src_step, dst_step; 1801541Srgrimes snd_pcm_uframes_t frames1; 18110907Sbde if (!src_channels[channel].enabled) { 18210907Sbde if (dst_channels[channel].wanted) 18310907Sbde snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format); 18410907Sbde dst_channels[channel].enabled = 0; 18513416Sphk continue; 18610907Sbde } 1871541Srgrimes dst_channels[channel].enabled = 1; 18810907Sbde src = src_channels[channel].area.addr + src_channels[channel].area.first / 8; 1891541Srgrimes dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8; 19011295Sswallace src_step = src_channels[channel].area.step / 8; 19111295Sswallace dst_step = dst_channels[channel].area.step / 8; 19210907Sbde frames1 = frames; 19310907Sbde while (frames1-- > 0) { 19410907Sbde signed short sample = ulaw2linear(*src); 19510907Sbde cvt_s16_to_native(data, dst, sample); 19610907Sbde src += src_step; 19710907Sbde dst += dst_step; 19810907Sbde } 19910907Sbde } 20010907Sbde} 20110907Sbde 20210907Sbdestatic inline signed short cvt_native_to_s16(struct mulaw_priv *data, 20310907Sbde unsigned char *src) 20411295Sswallace{ 20514220Speter u16 sample = 0; 20614220Speter memcpy((char *)&sample + data->copy_ofs, src + data->native_ofs, 20714220Speter data->copy_bytes); 20810907Sbde if (data->cvt_endian) 20910907Sbde sample = swab16(sample); 21010907Sbde sample ^= data->flip; 21110907Sbde return (signed short)sample; 2121541Srgrimes} 21310907Sbde 21410907Sbdestatic void mulaw_encode(struct snd_pcm_plugin *plugin, 21511295Sswallace const struct snd_pcm_plugin_channel *src_channels, 21611295Sswallace struct snd_pcm_plugin_channel *dst_channels, 2171541Srgrimes snd_pcm_uframes_t frames) 21810907Sbde{ 21910907Sbde struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; 22010907Sbde int channel; 22110907Sbde int nchannels = plugin->src_format.channels; 2221541Srgrimes for (channel = 0; channel < nchannels; ++channel) { 22310907Sbde char *src; 22410907Sbde char *dst; 22510907Sbde int src_step, dst_step; 22610907Sbde snd_pcm_uframes_t frames1; 22710907Sbde if (!src_channels[channel].enabled) { 22810907Sbde if (dst_channels[channel].wanted) 22910907Sbde snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format); 23010907Sbde dst_channels[channel].enabled = 0; 23111295Sswallace continue; 23210907Sbde } 23310907Sbde dst_channels[channel].enabled = 1; 23410907Sbde src = src_channels[channel].area.addr + src_channels[channel].area.first / 8; 23510907Sbde dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8; 23610907Sbde src_step = src_channels[channel].area.step / 8; 23710907Sbde dst_step = dst_channels[channel].area.step / 8; 23810907Sbde frames1 = frames; 23910907Sbde while (frames1-- > 0) { 24018398Sphk signed short sample = cvt_native_to_s16(data, src); 24122521Sdyson *dst = linear2ulaw(sample); 24210907Sbde src += src_step; 24310907Sbde dst += dst_step; 24410907Sbde } 24510907Sbde } 24610907Sbde} 24710907Sbde 24810907Sbdestatic snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin, 24910907Sbde const struct snd_pcm_plugin_channel *src_channels, 25010907Sbde struct snd_pcm_plugin_channel *dst_channels, 25110907Sbde snd_pcm_uframes_t frames) 25210907Sbde{ 25310907Sbde struct mulaw_priv *data; 25410907Sbde 25512865Speter if (snd_BUG_ON(!plugin || !src_channels || !dst_channels)) 25612865Speter return -ENXIO; 25712865Speter if (frames == 0) 25812865Speter return 0; 25912865Speter#ifdef CONFIG_SND_DEBUG 26012865Speter { 26112865Speter unsigned int channel; 26212865Speter for (channel = 0; channel < plugin->src_format.channels; channel++) { 26312865Speter if (snd_BUG_ON(src_channels[channel].area.first % 8 || 26412865Speter src_channels[channel].area.step % 8)) 26512865Speter return -ENXIO; 26612865Speter if (snd_BUG_ON(dst_channels[channel].area.first % 8 || 26714220Speter dst_channels[channel].area.step % 8)) 26814220Speter return -ENXIO; 26914220Speter } 27014220Speter } 27114220Speter#endif 27214220Speter if (frames > dst_channels[0].frames) 27314220Speter frames = dst_channels[0].frames; 27414220Speter data = (struct mulaw_priv *)plugin->extra_data; 27514220Speter data->func(plugin, src_channels, dst_channels, frames); 27614220Speter return frames; 27714220Speter} 27814220Speter 27914220Speterstatic void init_data(struct mulaw_priv *data, snd_pcm_format_t format) 28014220Speter{ 28114220Speter#ifdef SNDRV_LITTLE_ENDIAN 28214220Speter data->cvt_endian = snd_pcm_format_big_endian(format) > 0; 28314220Speter#else 28414220Speter data->cvt_endian = snd_pcm_format_little_endian(format) > 0; 28514220Speter#endif 28614220Speter if (!snd_pcm_format_signed(format)) 2871541Srgrimes data->flip = 0x8000; 288 data->native_bytes = snd_pcm_format_physical_width(format) / 8; 289 data->copy_bytes = data->native_bytes < 2 ? 1 : 2; 290 if (snd_pcm_format_little_endian(format)) { 291 data->native_ofs = data->native_bytes - data->copy_bytes; 292 data->copy_ofs = 2 - data->copy_bytes; 293 } else { 294 /* S24 in 4bytes need an 1 byte offset */ 295 data->native_ofs = data->native_bytes - 296 snd_pcm_format_width(format) / 8; 297 } 298} 299 300int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug, 301 struct snd_pcm_plugin_format *src_format, 302 struct snd_pcm_plugin_format *dst_format, 303 struct snd_pcm_plugin **r_plugin) 304{ 305 int err; 306 struct mulaw_priv *data; 307 struct snd_pcm_plugin *plugin; 308 struct snd_pcm_plugin_format *format; 309 mulaw_f func; 310 311 if (snd_BUG_ON(!r_plugin)) 312 return -ENXIO; 313 *r_plugin = NULL; 314 315 if (snd_BUG_ON(src_format->rate != dst_format->rate)) 316 return -ENXIO; 317 if (snd_BUG_ON(src_format->channels != dst_format->channels)) 318 return -ENXIO; 319 320 if (dst_format->format == SNDRV_PCM_FORMAT_MU_LAW) { 321 format = src_format; 322 func = mulaw_encode; 323 } 324 else if (src_format->format == SNDRV_PCM_FORMAT_MU_LAW) { 325 format = dst_format; 326 func = mulaw_decode; 327 } 328 else { 329 snd_BUG(); 330 return -EINVAL; 331 } 332 if (!snd_pcm_format_linear(format->format)) 333 return -EINVAL; 334 335 err = snd_pcm_plugin_build(plug, "Mu-Law<->linear conversion", 336 src_format, dst_format, 337 sizeof(struct mulaw_priv), &plugin); 338 if (err < 0) 339 return err; 340 data = (struct mulaw_priv *)plugin->extra_data; 341 data->func = func; 342 init_data(data, format->format); 343 plugin->transfer = mulaw_transfer; 344 *r_plugin = plugin; 345 return 0; 346} 347