Main Page | Class Hierarchy | Compound List | File List | Compound Members | File Members | Related Pages

alaw.cpp

Go to the documentation of this file.
00001 /*
00002  *  A-Law conversion Plug-In Interface
00003  *  Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
00004  *                        Uros Bizjak <uros@kss-loka.si>
00005  *
00006  *  Based on reference implementation by Sun Microsystems, Inc.
00007  *
00008  *   This library is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU Library General Public License as
00010  *   published by the Free Software Foundation; either version 2 of
00011  *   the License, or (at your option) any later version.
00012  *
00013  *   This program is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU Library General Public License for more details.
00017  *
00018  *   You should have received a copy of the GNU Library General Public
00019  *   License along with this library; if not, write to the Free Software
00020  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021  *
00022  */
00023   
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <unistd.h>
00033 #include <string.h>
00034 #include <errno.h>
00035 //#include <endian.h>
00036 //#include <byteswap.h>
00037 //#include "../pcm_local.h"
00038 
00039 #include "alaw.h"
00040 
00041 #define SIGN_BIT        (0x80)          /* Sign bit for a A-law byte. */
00042 #define QUANT_MASK      (0xf)           /* Quantization field mask. */
00043 #define NSEGS           (8)             /* Number of A-law segments. */
00044 #define SEG_SHIFT       (4)             /* Left shift for segment number. */
00045 #define SEG_MASK        (0x70)          /* Segment field mask. */
00046 
00047 static const short alaw_seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
00048                                 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
00049 
00050 inline int Alaw::search(int val, const short *table, int size)
00051 {
00052         int i;
00053 
00054         for (i = 0; i < size; i++) {
00055                 if (val <= *table++)
00056                         return (i);
00057         }
00058         return (size);
00059 }
00060 
00061 /*
00062  * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
00063  *
00064  * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
00065  *
00066  *              Linear Input Code       Compressed Code
00067  *      ------------------------        ---------------
00068  *      0000000wxyza                    000wxyz
00069  *      0000001wxyza                    001wxyz
00070  *      000001wxyzab                    010wxyz
00071  *      00001wxyzabc                    011wxyz
00072  *      0001wxyzabcd                    100wxyz
00073  *      001wxyzabcde                    101wxyz
00074  *      01wxyzabcdef                    110wxyz
00075  *      1wxyzabcdefg                    111wxyz
00076  *
00077  * For further information see John C. Bellamy's Digital Telephony, 1982,
00078  * John Wiley & Sons, pps 98-111 and 472-476.
00079  */
00080 inline unsigned char Alaw::linear2alaw(int pcm_val)     /* 2's complement (16-bit range) */
00081 {
00082         int             mask;
00083         int             seg;
00084         unsigned char   aval;
00085 
00086         if (pcm_val >= 0) {
00087                 mask = 0xD5;            /* sign (7th) bit = 1 */
00088         } else {
00089                 mask = 0x55;            /* sign bit = 0 */
00090                 pcm_val = -pcm_val - 8;
00091         }
00092 
00093         /* Convert the scaled magnitude to segment number. */
00094         seg = search(pcm_val, alaw_seg_end, NSEGS);
00095 
00096         /* Combine the sign, segment, and quantization bits. */
00097 
00098         if (seg >= 8)           /* out of range, return maximum value. */
00099                 return (unsigned char)(0x7F ^ mask);
00100         else {
00101                 aval = (unsigned char)(seg << SEG_SHIFT);
00102                 if (seg < 2)
00103                         aval |= (pcm_val >> 4) & QUANT_MASK;
00104                 else
00105                         aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
00106                 return (unsigned char)(aval ^ mask);
00107         }
00108 }
00109 
00110 /*
00111  * alaw2linear() - Convert an A-law value to 16-bit linear PCM
00112  *
00113  */
00114 /*
00115 static inline int alaw2linear(unsigned char a_val)
00116 {
00117         int             t;
00118         int             seg;
00119 
00120         a_val ^= 0x55;
00121 
00122         t = (a_val & QUANT_MASK) << 4;
00123         seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
00124         switch (seg) {
00125         case 0:
00126                 t += 8;
00127                 break;
00128         case 1:
00129                 t += 0x108;
00130                 break;
00131         default:
00132                 t += 0x108;
00133                 t <<= seg - 1;
00134         }
00135         return ((a_val & SIGN_BIT) ? t : -t);
00136 }
00137 */
00138 
00139 /*
00140  *  Basic A-Law plugin
00141  */
00142 
00143 typedef enum {
00144         _S8_ALAW,
00145         _U8_ALAW,
00146         _S16LE_ALAW,
00147         _U16LE_ALAW,
00148         _S16BE_ALAW,
00149         _U16BE_ALAW,
00150         _ALAW_S8,
00151         _ALAW_U8,
00152         _ALAW_S16LE,
00153         _ALAW_U16LE,
00154         _ALAW_S16BE,
00155         _ALAW_U16BE
00156 } combination_t; 
00157  
00158 struct alaw_private_data {
00159         combination_t cmd;
00160 };
00161 
00162 void Alaw::conv_u8bit_alaw(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
00163 {
00164         unsigned int pcm;
00165 
00166         while (size-- > 0) {
00167                 pcm = ((*src_ptr++) ^ 0x80) << 8;
00168                 *dst_ptr++ = linear2alaw((signed short)(pcm));
00169         }
00170 }
00171 
00172 void Alaw::conv_s8bit_alaw(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
00173 {
00174         unsigned int pcm;
00175 
00176         while (size-- > 0) {
00177                 pcm = *src_ptr++ << 8;
00178                 *dst_ptr++ = Alaw::linear2alaw((signed short)(pcm));
00179         }
00180 }
00181 
00182 void Alaw::conv_s16bit_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
00183 {
00184         while (size-- > 0)
00185                 *dst_ptr++ = Alaw::linear2alaw((signed short)(*src_ptr++));
00186 }
00187 
00188 /*
00189 static void alaw_conv_s16bit_swap_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
00190 {
00191         while (size-- > 0)
00192                 *dst_ptr++ = linear2alaw((signed short)(bswap_16(*src_ptr++)));
00193 }
00194 */
00195 
00196 void Alaw::conv_u16bit_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
00197 {
00198         while (size-- > 0)
00199                 *dst_ptr++ = Alaw::linear2alaw((signed short)((*src_ptr++) ^ 0x8000));
00200 }
00201 
00202 /*
00203 static void alaw_conv_u16bit_swap_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
00204 {
00205         while (size-- > 0)
00206                 *dst_ptr++ = linear2alaw((signed short)(bswap_16(*src_ptr++) ^ 0x8000));
00207 }
00208 */
00209 
00210 /*
00211 static void alaw_conv_alaw_u8bit(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
00212 {
00213         while (size-- > 0)
00214                 *dst_ptr++ = (alaw2linear(*src_ptr++) >> 8) ^ 0x80;
00215 }
00216 
00217 static void alaw_conv_alaw_s8bit(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
00218 {
00219         while (size-- > 0)
00220                 *dst_ptr++ = alaw2linear(*src_ptr++) >> 8;
00221 }
00222 
00223 static void alaw_conv_alaw_s16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
00224 {
00225         while (size-- > 0)
00226                 *dst_ptr++ = alaw2linear(*src_ptr++);
00227 }
00228 
00229 static void alaw_conv_alaw_swap_s16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
00230 {
00231         while (size-- > 0)
00232                 *dst_ptr++ = bswap_16(alaw2linear(*src_ptr++));
00233 }
00234 
00235 static void alaw_conv_alaw_u16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
00236 {
00237         while (size-- > 0)
00238                 *dst_ptr++ = alaw2linear(*src_ptr++) ^ 0x8000;
00239 }
00240 */
00241 
00242 /*
00243 static void alaw_conv_alaw_swap_u16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
00244 {
00245         while (size-- > 0)
00246                 *dst_ptr++ = bswap_16(alaw2linear(*src_ptr++) ^ 0x8000);
00247 }
00248 */
00249 
00250 /*
00251 static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin,
00252                               char *src_ptr, size_t src_size,
00253                               char *dst_ptr, size_t dst_size)
00254 {
00255         struct alaw_private_data *data;
00256 
00257         if (plugin == NULL || src_ptr == NULL || dst_ptr == NULL)
00258                 return -EINVAL;
00259         if (src_size == 0)
00260                 return 0;
00261         data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
00262         if (data == NULL)
00263                 return -EINVAL;
00264         switch (data->cmd) {
00265         case _U8_ALAW:
00266                 if (dst_size < src_size)
00267                         return -EINVAL;
00268                 alaw_conv_u8bit_alaw(src_ptr, dst_ptr, src_size);
00269                 return src_size;
00270         case _S8_ALAW:
00271                 if (dst_size < src_size)
00272                         return -EINVAL;
00273                 alaw_conv_s8bit_alaw(src_ptr, dst_ptr, src_size);
00274                 return src_size;
00275         case _S16LE_ALAW:
00276                 if ((dst_size << 1) < src_size)
00277                         return -EINVAL;
00278 #ifdef SND_LITTLE_ENDIAN
00279                 alaw_conv_s16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
00280 #else
00281                 alaw_conv_s16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
00282 #endif
00283                 return src_size >> 1;
00284         case _U16LE_ALAW:
00285                 if ((dst_size << 1) < src_size)
00286                         return -EINVAL;
00287 #ifdef SND_LITTLE_ENDIAN
00288                 alaw_conv_u16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
00289 #else
00290                 alaw_conv_u16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
00291 #endif
00292                 return src_size >> 1;
00293         case _S16BE_ALAW:
00294                 if ((dst_size << 1) < src_size)
00295                         return -EINVAL;
00296 #ifdef SND_LITTLE_ENDIAN
00297                 alaw_conv_s16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
00298 #else
00299                 alaw_conv_s16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
00300 #endif
00301                 return src_size >> 1;
00302         case _U16BE_ALAW:
00303                 if ((dst_size << 1) < src_size)
00304                         return -EINVAL;
00305 #ifdef SND_LITTLE_ENDIAN
00306                 alaw_conv_u16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
00307 #else
00308                 alaw_conv_u16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
00309 #endif
00310                 return src_size >> 1;
00311         case _ALAW_U8:
00312                 if (dst_size < src_size)
00313                         return -EINVAL;
00314                 alaw_conv_alaw_u8bit(src_ptr, dst_ptr, src_size);
00315                 return src_size;
00316         case _ALAW_S8:
00317                 if (dst_size < src_size)
00318                         return -EINVAL;
00319                 alaw_conv_alaw_s8bit(src_ptr, dst_ptr, src_size);
00320                 return src_size;
00321         case _ALAW_S16LE:
00322                 if ((dst_size >> 1) < src_size)
00323                         return -EINVAL;
00324 #ifdef SND_LITTLE_ENDIAN
00325                 alaw_conv_alaw_s16bit(src_ptr, (short *)dst_ptr, src_size);
00326 #else
00327                 alaw_conv_alaw_swap_s16bit(src_ptr, (short *)dst_ptr, src_size);
00328 #endif
00329                 return src_size << 1;
00330         case _ALAW_U16LE:
00331                 if ((dst_size >> 1) < src_size)
00332                         return -EINVAL;
00333 #ifdef SND_LITTLE_ENDIAN
00334                 alaw_conv_alaw_u16bit(src_ptr, (short *)dst_ptr, src_size);
00335 #else
00336                 alaw_conv_alaw_swap_u16bit(src_ptr, (short *)dst_ptr, src_size);
00337 #endif
00338                 return src_size << 1;
00339         case _ALAW_S16BE:
00340                 if ((dst_size >> 1) < src_size)
00341                         return -EINVAL;
00342 #ifdef SND_LITTLE_ENDIAN
00343                 alaw_conv_alaw_swap_s16bit(src_ptr, (short *)dst_ptr, src_size);
00344 #else
00345                 alaw_conv_alaw_s16bit(src_ptr, (short *)dst_ptr, src_size);
00346 #endif
00347                 return src_size << 1;
00348         case _ALAW_U16BE:
00349                 if ((dst_size >> 1) < src_size)
00350                         return -EINVAL;
00351 #ifdef SND_LITTLE_ENDIAN
00352                 alaw_conv_alaw_swap_u16bit(src_ptr, (short *)dst_ptr, src_size);
00353 #else
00354                 alaw_conv_alaw_u16bit(src_ptr, (short *)dst_ptr, src_size);
00355 #endif
00356                 return src_size << 1;
00357         default:
00358                 return -EIO;
00359         }
00360 }
00361 */
00362 /*
00363 static ssize_t alaw_src_size(snd_pcm_plugin_t *plugin, size_t size)
00364 {
00365         struct alaw_private_data *data;
00366 
00367         if (!plugin || size <= 0)
00368                 return -EINVAL;
00369         data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
00370         switch (data->cmd) {
00371         case _U8_ALAW:
00372         case _S8_ALAW:
00373         case _ALAW_U8:
00374         case _ALAW_S8:
00375                 return size;
00376         case _U16LE_ALAW:
00377         case _S16LE_ALAW:
00378         case _U16BE_ALAW:
00379         case _S16BE_ALAW:
00380                 return size * 2;
00381         case _ALAW_U16LE:
00382         case _ALAW_S16LE:
00383         case _ALAW_U16BE:
00384         case _ALAW_S16BE:
00385                 return size / 2;
00386         default:
00387                 return -EIO;
00388         }
00389 }
00390 */
00391 /*
00392 static ssize_t alaw_dst_size(snd_pcm_plugin_t *plugin, size_t size)
00393 {
00394         struct alaw_private_data *data;
00395 
00396         if (!plugin || size <= 0)
00397                 return -EINVAL;
00398         data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
00399         switch (data->cmd) {
00400         case _U8_ALAW:
00401         case _S8_ALAW:
00402         case _ALAW_U8:
00403         case _ALAW_S8:
00404                 return size;
00405         case _U16LE_ALAW:
00406         case _S16LE_ALAW:
00407         case _U16BE_ALAW:
00408         case _S16BE_ALAW:
00409                 return size / 2;
00410         case _ALAW_U16LE:
00411         case _ALAW_S16LE:
00412         case _ALAW_U16BE:
00413         case _ALAW_S16BE:
00414                 return size * 2;
00415         default:
00416                 return -EIO;
00417         }
00418 }
00419 */
00420 /*
00421 int snd_pcm_plugin_build_alaw(snd_pcm_format_t *src_format,
00422                               snd_pcm_format_t *dst_format,
00423                               snd_pcm_plugin_t **r_plugin)
00424 {
00425         struct alaw_private_data *data;
00426         snd_pcm_plugin_t *plugin;
00427         combination_t cmd;
00428 
00429         if (!r_plugin)
00430                 return -EINVAL;
00431         *r_plugin = NULL;
00432 
00433         if (src_format->interleave != dst_format->interleave && 
00434             src_format->voices > 1)
00435                 return -EINVAL;
00436         if (src_format->rate != dst_format->rate)
00437                 return -EINVAL;
00438         if (src_format->voices != dst_format->voices)
00439                 return -EINVAL;
00440 
00441         if (dst_format->format == SND_PCM_SFMT_A_LAW) {
00442                 switch (src_format->format) {
00443                 case SND_PCM_SFMT_U8:           cmd = _U8_ALAW;         break;
00444                 case SND_PCM_SFMT_S8:           cmd = _S8_ALAW;         break;
00445                 case SND_PCM_SFMT_U16_LE:       cmd = _U16LE_ALAW;      break;
00446                 case SND_PCM_SFMT_S16_LE:       cmd = _S16LE_ALAW;      break;
00447                 case SND_PCM_SFMT_U16_BE:       cmd = _U16BE_ALAW;      break;
00448                 case SND_PCM_SFMT_S16_BE:       cmd = _S16BE_ALAW;      break;
00449                 default:
00450                         return -EINVAL;
00451                 }
00452         } else if (src_format->format == SND_PCM_SFMT_A_LAW) {
00453                 switch (dst_format->format) {
00454                 case SND_PCM_SFMT_U8:           cmd = _ALAW_U8;         break;
00455                 case SND_PCM_SFMT_S8:           cmd = _ALAW_S8;         break;
00456                 case SND_PCM_SFMT_U16_LE:       cmd = _ALAW_U16LE;      break;
00457                 case SND_PCM_SFMT_S16_LE:       cmd = _ALAW_S16LE;      break;
00458                 case SND_PCM_SFMT_U16_BE:       cmd = _ALAW_U16BE;      break;
00459                 case SND_PCM_SFMT_S16_BE:       cmd = _ALAW_S16BE;      break;
00460                 default:
00461                         return -EINVAL;
00462                 }
00463         } else {
00464                 return -EINVAL;
00465         }
00466         plugin = snd_pcm_plugin_build("A-Law<->linear conversion",
00467                                       sizeof(struct alaw_private_data));
00468         if (plugin == NULL)
00469                 return -ENOMEM;
00470         data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
00471         data->cmd = cmd;
00472         plugin->transfer = alaw_transfer;
00473         plugin->src_size = alaw_src_size;
00474         plugin->dst_size = alaw_dst_size;
00475         *r_plugin = plugin;
00476         return 0;
00477 }
00478 */

Generated on Tue Feb 8 04:07:16 2005 for E32frodo by doxygen 1.3.3