1 // SPDX-License-Identifier: LGPL-2.0+ 2 /* 3 * Mu-Law conversion Plug-In Interface 4 * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> 5 * Uros Bizjak <uros@kss-loka.si> 6 * 7 * Based on reference implementation by Sun Microsystems, Inc. 8 */ 9 10 #include <linux/time.h> 11 #include <sound/core.h> 12 #include <sound/pcm.h> 13 #include "pcm_plugin.h" 14 15 #define SIGN_BIT (0x80) /* Sign bit for a u-law byte. */ 16 #define QUANT_MASK (0xf) /* Quantization field mask. */ 17 #define NSEGS (8) /* Number of u-law segments. */ 18 #define SEG_SHIFT (4) /* Left shift for segment number. */ 19 #define SEG_MASK (0x70) /* Segment field mask. */ 20 21 static inline int val_seg(int val) 22 { 23 int r = 0; 24 val >>= 7; 25 if (val & 0xf0) { 26 val >>= 4; 27 r += 4; 28 } 29 if (val & 0x0c) { 30 val >>= 2; 31 r += 2; 32 } 33 if (val & 0x02) 34 r += 1; 35 return r; 36 } 37 38 #define BIAS (0x84) /* Bias for linear code. */ 39 40 /* 41 * linear2ulaw() - Convert a linear PCM value to u-law 42 * 43 * In order to simplify the encoding process, the original linear magnitude 44 * is biased by adding 33 which shifts the encoding range from (0 - 8158) to 45 * (33 - 8191). The result can be seen in the following encoding table: 46 * 47 * Biased Linear Input Code Compressed Code 48 * ------------------------ --------------- 49 * 00000001wxyza 000wxyz 50 * 0000001wxyzab 001wxyz 51 * 000001wxyzabc 010wxyz 52 * 00001wxyzabcd 011wxyz 53 * 0001wxyzabcde 100wxyz 54 * 001wxyzabcdef 101wxyz 55 * 01wxyzabcdefg 110wxyz 56 * 1wxyzabcdefgh 111wxyz 57 * 58 * Each biased linear code has a leading 1 which identifies the segment 59 * number. The value of the segment number is equal to 7 minus the number 60 * of leading 0's. The quantization interval is directly available as the 61 * four bits wxyz. * The trailing bits (a - h) are ignored. 62 * 63 * Ordinarily the complement of the resulting code word is used for 64 * transmission, and so the code word is complemented before it is returned. 65 * 66 * For further information see John C. Bellamy's Digital Telephony, 1982, 67 * John Wiley & Sons, pps 98-111 and 472-476. 68 */ 69 static unsigned char linear2ulaw(int pcm_val) /* 2's complement (16-bit range) */ 70 { 71 int mask; 72 int seg; 73 unsigned char uval; 74 75 /* Get the sign and the magnitude of the value. */ 76 if (pcm_val < 0) { 77 pcm_val = BIAS - pcm_val; 78 mask = 0x7F; 79 } else { 80 pcm_val += BIAS; 81 mask = 0xFF; 82 } 83 if (pcm_val > 0x7FFF) 84 pcm_val = 0x7FFF; 85 86 /* Convert the scaled magnitude to segment number. */ 87 seg = val_seg(pcm_val); 88 89 /* 90 * Combine the sign, segment, quantization bits; 91 * and complement the code word. 92 */ 93 uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF); 94 return uval ^ mask; 95 } 96 97 /* 98 * ulaw2linear() - Convert a u-law value to 16-bit linear PCM 99 * 100 * First, a biased linear code is derived from the code word. An unbiased 101 * output can then be obtained by subtracting 33 from the biased code. 102 * 103 * Note that this function expects to be passed the complement of the 104 * original code word. This is in keeping with ISDN conventions. 105 */ 106 static int ulaw2linear(unsigned char u_val) 107 { 108 int t; 109 110 /* Complement to obtain normal u-law value. */ 111 u_val = ~u_val; 112 113 /* 114 * Extract and bias the quantization bits. Then 115 * shift up by the segment number and subtract out the bias. 116 */ 117 t = ((u_val & QUANT_MASK) << 3) + BIAS; 118 t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; 119 120 return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); 121 } 122 123 /* 124 * Basic Mu-Law plugin 125 */ 126 127 typedef void (*mulaw_f)(struct snd_pcm_plugin *plugin, 128 const struct snd_pcm_plugin_channel *src_channels, 129 struct snd_pcm_plugin_channel *dst_channels, 130 snd_pcm_uframes_t frames); 131 132 struct mulaw_priv { 133 mulaw_f func; 134 int cvt_endian; /* need endian conversion? */ 135 unsigned int native_ofs; /* byte offset in native format */ 136 unsigned int copy_ofs; /* byte offset in s16 format */ 137 unsigned int native_bytes; /* byte size of the native format */ 138 unsigned int copy_bytes; /* bytes to copy per conversion */ 139 u16 flip; /* MSB flip for signedness, done after endian conversion */ 140 }; 141 142 static inline void cvt_s16_to_native(struct mulaw_priv *data, 143 unsigned char *dst, u16 sample) 144 { 145 sample ^= data->flip; 146 if (data->cvt_endian) 147 sample = swab16(sample); 148 if (data->native_bytes > data->copy_bytes) 149 memset(dst, 0, data->native_bytes); 150 memcpy(dst + data->native_ofs, (char *)&sample + data->copy_ofs, 151 data->copy_bytes); 152 } 153 154 static void mulaw_decode(struct snd_pcm_plugin *plugin, 155 const struct snd_pcm_plugin_channel *src_channels, 156 struct snd_pcm_plugin_channel *dst_channels, 157 snd_pcm_uframes_t frames) 158 { 159 struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; 160 int channel; 161 int nchannels = plugin->src_format.channels; 162 for (channel = 0; channel < nchannels; ++channel) { 163 char *src; 164 char *dst; 165 int src_step, dst_step; 166 snd_pcm_uframes_t frames1; 167 if (!src_channels[channel].enabled) { 168 if (dst_channels[channel].wanted) 169 snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format); 170 dst_channels[channel].enabled = 0; 171 continue; 172 } 173 dst_channels[channel].enabled = 1; 174 src = src_channels[channel].area.addr + src_channels[channel].area.first / 8; 175 dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8; 176 src_step = src_channels[channel].area.step / 8; 177 dst_step = dst_channels[channel].area.step / 8; 178 frames1 = frames; 179 while (frames1-- > 0) { 180 signed short sample = ulaw2linear(*src); 181 cvt_s16_to_native(data, dst, sample); 182 src += src_step; 183 dst += dst_step; 184 } 185 } 186 } 187 188 static inline signed short cvt_native_to_s16(struct mulaw_priv *data, 189 unsigned char *src) 190 { 191 u16 sample = 0; 192 memcpy((char *)&sample + data->copy_ofs, src + data->native_ofs, 193 data->copy_bytes); 194 if (data->cvt_endian) 195 sample = swab16(sample); 196 sample ^= data->flip; 197 return (signed short)sample; 198 } 199 200 static void mulaw_encode(struct snd_pcm_plugin *plugin, 201 const struct snd_pcm_plugin_channel *src_channels, 202 struct snd_pcm_plugin_channel *dst_channels, 203 snd_pcm_uframes_t frames) 204 { 205 struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; 206 int channel; 207 int nchannels = plugin->src_format.channels; 208 for (channel = 0; channel < nchannels; ++channel) { 209 char *src; 210 char *dst; 211 int src_step, dst_step; 212 snd_pcm_uframes_t frames1; 213 if (!src_channels[channel].enabled) { 214 if (dst_channels[channel].wanted) 215 snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format); 216 dst_channels[channel].enabled = 0; 217 continue; 218 } 219 dst_channels[channel].enabled = 1; 220 src = src_channels[channel].area.addr + src_channels[channel].area.first / 8; 221 dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8; 222 src_step = src_channels[channel].area.step / 8; 223 dst_step = dst_channels[channel].area.step / 8; 224 frames1 = frames; 225 while (frames1-- > 0) { 226 signed short sample = cvt_native_to_s16(data, src); 227 *dst = linear2ulaw(sample); 228 src += src_step; 229 dst += dst_step; 230 } 231 } 232 } 233 234 static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin, 235 const struct snd_pcm_plugin_channel *src_channels, 236 struct snd_pcm_plugin_channel *dst_channels, 237 snd_pcm_uframes_t frames) 238 { 239 struct mulaw_priv *data; 240 241 if (snd_BUG_ON(!plugin || !src_channels || !dst_channels)) 242 return -ENXIO; 243 if (frames == 0) 244 return 0; 245 #ifdef CONFIG_SND_DEBUG 246 { 247 unsigned int channel; 248 for (channel = 0; channel < plugin->src_format.channels; channel++) { 249 if (snd_BUG_ON(src_channels[channel].area.first % 8 || 250 src_channels[channel].area.step % 8)) 251 return -ENXIO; 252 if (snd_BUG_ON(dst_channels[channel].area.first % 8 || 253 dst_channels[channel].area.step % 8)) 254 return -ENXIO; 255 } 256 } 257 #endif 258 if (frames > dst_channels[0].frames) 259 frames = dst_channels[0].frames; 260 data = (struct mulaw_priv *)plugin->extra_data; 261 data->func(plugin, src_channels, dst_channels, frames); 262 return frames; 263 } 264 265 static void init_data(struct mulaw_priv *data, snd_pcm_format_t format) 266 { 267 #ifdef SNDRV_LITTLE_ENDIAN 268 data->cvt_endian = snd_pcm_format_big_endian(format) > 0; 269 #else 270 data->cvt_endian = snd_pcm_format_little_endian(format) > 0; 271 #endif 272 if (!snd_pcm_format_signed(format)) 273 data->flip = 0x8000; 274 data->native_bytes = snd_pcm_format_physical_width(format) / 8; 275 data->copy_bytes = data->native_bytes < 2 ? 1 : 2; 276 if (snd_pcm_format_little_endian(format)) { 277 data->native_ofs = data->native_bytes - data->copy_bytes; 278 data->copy_ofs = 2 - data->copy_bytes; 279 } else { 280 /* S24 in 4bytes need an 1 byte offset */ 281 data->native_ofs = data->native_bytes - 282 snd_pcm_format_width(format) / 8; 283 } 284 } 285 286 int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug, 287 struct snd_pcm_plugin_format *src_format, 288 struct snd_pcm_plugin_format *dst_format, 289 struct snd_pcm_plugin **r_plugin) 290 { 291 int err; 292 struct mulaw_priv *data; 293 struct snd_pcm_plugin *plugin; 294 struct snd_pcm_plugin_format *format; 295 mulaw_f func; 296 297 if (snd_BUG_ON(!r_plugin)) 298 return -ENXIO; 299 *r_plugin = NULL; 300 301 if (snd_BUG_ON(src_format->rate != dst_format->rate)) 302 return -ENXIO; 303 if (snd_BUG_ON(src_format->channels != dst_format->channels)) 304 return -ENXIO; 305 306 if (dst_format->format == SNDRV_PCM_FORMAT_MU_LAW) { 307 format = src_format; 308 func = mulaw_encode; 309 } 310 else if (src_format->format == SNDRV_PCM_FORMAT_MU_LAW) { 311 format = dst_format; 312 func = mulaw_decode; 313 } 314 else { 315 snd_BUG(); 316 return -EINVAL; 317 } 318 if (!snd_pcm_format_linear(format->format)) 319 return -EINVAL; 320 321 err = snd_pcm_plugin_build(plug, "Mu-Law<->linear conversion", 322 src_format, dst_format, 323 sizeof(struct mulaw_priv), &plugin); 324 if (err < 0) 325 return err; 326 data = (struct mulaw_priv *)plugin->extra_data; 327 data->func = func; 328 init_data(data, format->format); 329 plugin->transfer = mulaw_transfer; 330 *r_plugin = plugin; 331 return 0; 332 } 333