Thu Apr 28 2011 16:56:46

Asterisk developer's documentation


codec_adpcm.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Based on frompcm.c and topcm.c from the Emiliano MIPL browser/
00005  * interpreter.  See http://www.bsdtelephony.com.mx
00006  *
00007  * Copyright (c) 2001 - 2005 Digium, Inc.
00008  * All rights reserved.
00009  *
00010  * Karl Sackett <krs@linux-support.net>, 2001-03-21
00011  *
00012  * See http://www.asterisk.org for more information about
00013  * the Asterisk project. Please do not directly contact
00014  * any of the maintainers of this project for assistance;
00015  * the project provides a web site, mailing lists and IRC
00016  * channels for your use.
00017  *
00018  * This program is free software, distributed under the terms of
00019  * the GNU General Public License Version 2. See the LICENSE file
00020  * at the top of the source tree.
00021  */
00022 
00023 /*! \file
00024  *
00025  * \brief codec_adpcm.c - translate between signed linear and Dialogic ADPCM
00026  * 
00027  * \ingroup codecs
00028  */
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 267507 $")
00033 
00034 #include "asterisk/lock.h"
00035 #include "asterisk/linkedlists.h"
00036 #include "asterisk/module.h"
00037 #include "asterisk/config.h"
00038 #include "asterisk/translate.h"
00039 #include "asterisk/utils.h"
00040 
00041 /* define NOT_BLI to use a faster but not bit-level identical version */
00042 /* #define NOT_BLI */
00043 
00044 #define BUFFER_SAMPLES   8096 /* size for the translation buffers */
00045 
00046 /* Sample frame data */
00047 #include "asterisk/slin.h"
00048 #include "ex_adpcm.h"
00049 
00050 /*
00051  * Step size index shift table 
00052  */
00053 
00054 static int indsft[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
00055 
00056 /*
00057  * Step size table, where stpsz[i]=floor[16*(11/10)^i]
00058  */
00059 
00060 static int stpsz[49] = {
00061   16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73,
00062   80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279,
00063   307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963,
00064   1060, 1166, 1282, 1411, 1552
00065 };
00066 
00067 /*
00068  * Decoder/Encoder state
00069  *   States for both encoder and decoder are synchronized
00070  */
00071 struct adpcm_state {
00072    int ssindex;
00073    int signal;
00074    int zero_count;
00075    int next_flag;
00076 };
00077 
00078 /*
00079  * Decode(encoded)
00080  *  Decodes the encoded nibble from the adpcm file.
00081  *
00082  * Results:
00083  *  Returns the encoded difference.
00084  *
00085  * Side effects:
00086  *  Sets the index to the step size table for the next encode.
00087  */
00088 
00089 static inline short decode(int encoded, struct adpcm_state *state)
00090 {
00091    int diff;
00092    int step;
00093    int sign;
00094 
00095    step = stpsz[state->ssindex];
00096 
00097    sign = encoded & 0x08;
00098    encoded &= 0x07;
00099 #ifdef NOT_BLI
00100    diff = (((encoded << 1) + 1) * step) >> 3;
00101 #else /* BLI code */
00102    diff = step >> 3;
00103    if (encoded & 4)
00104       diff += step;
00105    if (encoded & 2)
00106       diff += step >> 1;
00107    if (encoded & 1)
00108       diff += step >> 2;
00109    if ((encoded >> 1) & step & 0x1)
00110       diff++;
00111 #endif
00112    if (sign)
00113       diff = -diff;
00114 
00115    if (state->next_flag & 0x1)
00116       state->signal -= 8;
00117    else if (state->next_flag & 0x2)
00118       state->signal += 8;
00119 
00120    state->signal += diff;
00121 
00122    if (state->signal > 2047)
00123       state->signal = 2047;
00124    else if (state->signal < -2047)
00125       state->signal = -2047;
00126 
00127    state->next_flag = 0;
00128 
00129 #ifdef AUTO_RETURN
00130    if (encoded)
00131       state->zero_count = 0;
00132    else if (++(state->zero_count) == 24) {
00133       state->zero_count = 0;
00134       if (state->signal > 0)
00135          state->next_flag = 0x1;
00136       else if (state->signal < 0)
00137          state->next_flag = 0x2;
00138    }
00139 #endif
00140 
00141    state->ssindex += indsft[encoded];
00142    if (state->ssindex < 0)
00143       state->ssindex = 0;
00144    else if (state->ssindex > 48)
00145       state->ssindex = 48;
00146 
00147    return state->signal << 4;
00148 }
00149 
00150 /*
00151  * Adpcm
00152  *  Takes a signed linear signal and encodes it as ADPCM
00153  *  For more information see http://support.dialogic.com/appnotes/adpcm.pdf
00154  *
00155  * Results:
00156  *  Foo.
00157  *
00158  * Side effects:
00159  *  signal gets updated with each pass.
00160  */
00161 
00162 static inline int adpcm(short csig, struct adpcm_state *state)
00163 {
00164    int diff;
00165    int step;
00166    int encoded;
00167 
00168    /* 
00169     * Clip csig if too large or too small
00170     */
00171    csig >>= 4;
00172 
00173    step = stpsz[state->ssindex];
00174    diff = csig - state->signal;
00175 
00176 #ifdef NOT_BLI
00177    if (diff < 0) {
00178       encoded = (-diff << 2) / step;
00179       if (encoded > 7)
00180          encoded = 7;
00181       encoded |= 0x08;
00182    } else {
00183       encoded = (diff << 2) / step;
00184       if (encoded > 7)
00185          encoded = 7;
00186    }
00187 #else /* BLI code */
00188    if (diff < 0) {
00189       encoded = 8;
00190       diff = -diff;
00191    } else
00192       encoded = 0;
00193    if (diff >= step) {
00194       encoded |= 4;
00195       diff -= step;
00196    }
00197    step >>= 1;
00198    if (diff >= step) {
00199       encoded |= 2;
00200       diff -= step;
00201    }
00202    step >>= 1;
00203    if (diff >= step)
00204       encoded |= 1;
00205 #endif /* NOT_BLI */
00206 
00207    /* feedback to state */
00208    decode(encoded, state);
00209    
00210    return encoded;
00211 }
00212 
00213 /*----------------- Asterisk-codec glue ------------*/
00214 
00215 /*! \brief Workspace for translating signed linear signals to ADPCM. */
00216 struct adpcm_encoder_pvt {
00217    struct adpcm_state state;
00218    int16_t inbuf[BUFFER_SAMPLES];   /* Unencoded signed linear values */
00219 };
00220 
00221 /*! \brief Workspace for translating ADPCM signals to signed linear. */
00222 struct adpcm_decoder_pvt {
00223    struct adpcm_state state;
00224 };
00225 
00226 /*! \brief decode 4-bit adpcm frame data and store in output buffer */
00227 static int adpcmtolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00228 {
00229    struct adpcm_decoder_pvt *tmp = pvt->pvt;
00230    int x = f->datalen;
00231    unsigned char *src = f->data.ptr;
00232    int16_t *dst = pvt->outbuf.i16 + pvt->samples;
00233 
00234    while (x--) {
00235       *dst++ = decode((*src >> 4) & 0xf, &tmp->state);
00236       *dst++ = decode(*src++ & 0x0f, &tmp->state);
00237    }
00238    pvt->samples += f->samples;
00239    pvt->datalen += 2*f->samples;
00240    return 0;
00241 }
00242 
00243 /*! \brief fill input buffer with 16-bit signed linear PCM values. */
00244 static int lintoadpcm_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00245 {
00246    struct adpcm_encoder_pvt *tmp = pvt->pvt;
00247 
00248    memcpy(&tmp->inbuf[pvt->samples], f->data.ptr, f->datalen);
00249    pvt->samples += f->samples;
00250    return 0;
00251 }
00252 
00253 /*! \brief convert inbuf and store into frame */
00254 static struct ast_frame *lintoadpcm_frameout(struct ast_trans_pvt *pvt)
00255 {
00256    struct adpcm_encoder_pvt *tmp = pvt->pvt;
00257    struct ast_frame *f;
00258    int i;
00259    int samples = pvt->samples;   /* save original number */
00260   
00261    if (samples < 2)
00262       return NULL;
00263 
00264    pvt->samples &= ~1; /* atomic size is 2 samples */
00265 
00266    for (i = 0; i < pvt->samples; i += 2) {
00267       pvt->outbuf.c[i/2] =
00268          (adpcm(tmp->inbuf[i  ], &tmp->state) << 4) |
00269          (adpcm(tmp->inbuf[i+1], &tmp->state)     );
00270    };
00271 
00272    f = ast_trans_frameout(pvt, pvt->samples/2, 0);
00273 
00274    /*
00275     * If there is a left over sample, move it to the beginning
00276     * of the input buffer.
00277     */
00278 
00279    if (samples & 1) {   /* move the leftover sample at beginning */
00280       tmp->inbuf[0] = tmp->inbuf[samples - 1];
00281       pvt->samples = 1;
00282    }
00283    return f;
00284 }
00285 
00286 
00287 static struct ast_translator adpcmtolin = {
00288    .name = "adpcmtolin",
00289    .srcfmt = AST_FORMAT_ADPCM,
00290    .dstfmt = AST_FORMAT_SLINEAR,
00291    .framein = adpcmtolin_framein,
00292    .sample = adpcm_sample,
00293    .desc_size = sizeof(struct adpcm_decoder_pvt),
00294    .buffer_samples = BUFFER_SAMPLES,
00295    .buf_size = BUFFER_SAMPLES * 2,
00296 };
00297 
00298 static struct ast_translator lintoadpcm = {
00299    .name = "lintoadpcm",
00300    .srcfmt = AST_FORMAT_SLINEAR,
00301    .dstfmt = AST_FORMAT_ADPCM,
00302    .framein = lintoadpcm_framein,
00303    .frameout = lintoadpcm_frameout,
00304    .sample = slin8_sample,
00305    .desc_size = sizeof (struct adpcm_encoder_pvt),
00306    .buffer_samples = BUFFER_SAMPLES,
00307    .buf_size = BUFFER_SAMPLES/ 2,   /* 2 samples per byte */
00308 };
00309 
00310 /*! \brief standard module glue */
00311 static int reload(void)
00312 {
00313    return AST_MODULE_LOAD_SUCCESS;
00314 }
00315 
00316 static int unload_module(void)
00317 {
00318    int res;
00319 
00320    res = ast_unregister_translator(&lintoadpcm);
00321    res |= ast_unregister_translator(&adpcmtolin);
00322 
00323    return res;
00324 }
00325 
00326 static int load_module(void)
00327 {
00328    int res;
00329 
00330    res = ast_register_translator(&adpcmtolin);
00331    if (!res)
00332       res = ast_register_translator(&lintoadpcm);
00333    else
00334       ast_unregister_translator(&adpcmtolin);
00335    if (res)
00336       return AST_MODULE_LOAD_FAILURE;
00337    return AST_MODULE_LOAD_SUCCESS;
00338 }
00339 
00340 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Adaptive Differential PCM Coder/Decoder",
00341       .load = load_module,
00342       .unload = unload_module,
00343       .reload = reload,
00344           );