Mercurial > hg > audiostuff
diff spandsp-0.0.6pre17/src/gsm0610_decode.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 15:50:58 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spandsp-0.0.6pre17/src/gsm0610_decode.c Fri Jun 25 15:50:58 2010 +0200 @@ -0,0 +1,354 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * gsm0610_decode.c - GSM 06.10 full rate speech codec. + * + * Written by Steve Underwood <steveu@coppice.org> + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the widely used GSM 06.10 code available from + * http://kbs.cs.tu-berlin.de/~jutta/toast.html + * + * $Id: gsm0610_decode.c,v 1.25 2009/02/03 16:28:39 steveu Exp $ + */ + +/*! \file */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include <assert.h> +#include <inttypes.h> +#if defined(HAVE_TGMATH_H) +#include <tgmath.h> +#endif +#if defined(HAVE_MATH_H) +#include <math.h> +#endif +#include "floating_fudge.h" +#include <stdlib.h> +#include <memory.h> + +#include "spandsp/telephony.h" +#include "spandsp/fast_convert.h" +#include "spandsp/bitstream.h" +#include "spandsp/saturated.h" +#include "spandsp/gsm0610.h" + +#include "gsm0610_local.h" + +/* 4.3 FIXED POINT IMPLEMENTATION OF THE RPE-LTP DECODER */ + +static void postprocessing(gsm0610_state_t *s, int16_t amp[]) +{ + int k; + int16_t msr; + int16_t tmp; + + msr = s->msr; + for (k = 0; k < GSM0610_FRAME_LEN; k++) + { + tmp = gsm_mult_r(msr, 28180); + /* De-emphasis */ + msr = saturated_add16(amp[k], tmp); + /* Truncation & upscaling */ + amp[k] = (int16_t) (saturated_add16(msr, msr) & 0xFFF8); + } + /*endfor*/ + s->msr = msr; +} +/*- End of function --------------------------------------------------------*/ + +static void decode_a_frame(gsm0610_state_t *s, + int16_t amp[GSM0610_FRAME_LEN], + gsm0610_frame_t *f) +{ + int j; + int k; + int16_t erp[40]; + int16_t wt[GSM0610_FRAME_LEN]; + int16_t *drp; + + drp = s->dp0 + 120; + for (j = 0; j < 4; j++) + { + gsm0610_rpe_decoding(s, f->xmaxc[j], f->Mc[j], f->xMc[j], erp); + gsm0610_long_term_synthesis_filtering(s, f->Nc[j], f->bc[j], erp, drp); + for (k = 0; k < 40; k++) + wt[j*40 + k] = drp[k]; + /*endfor*/ + } + /*endfor*/ + + gsm0610_short_term_synthesis_filter(s, f->LARc, wt, amp); + postprocessing(s, amp); +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) gsm0610_unpack_none(gsm0610_frame_t *s, const uint8_t c[]) +{ + int i; + int j; + int k; + + i = 0; + for (j = 0; j < 8; j++) + s->LARc[j] = c[i++]; + for (j = 0; j < 4; j++) + { + s->Nc[j] = c[i++]; + s->bc[j] = c[i++]; + s->Mc[j] = c[i++]; + s->xmaxc[j] = c[i++]; + for (k = 0; k < 13; k++) + s->xMc[j][k] = c[i++]; + } + return 76; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) gsm0610_unpack_wav49(gsm0610_frame_t *s, const uint8_t c[]) +{ + uint16_t sr; + int i; + + sr = *c++; + s->LARc[0] = sr & 0x3F; + sr >>= 6; + sr |= (uint16_t) *c++ << 2; + s->LARc[1] = sr & 0x3F; + sr >>= 6; + sr |= (uint16_t) *c++ << 4; + s->LARc[2] = sr & 0x1F; + sr >>= 5; + s->LARc[3] = sr & 0x1F; + sr >>= 5; + sr |= (uint16_t) *c++ << 2; + s->LARc[4] = sr & 0xF; + sr >>= 4; + s->LARc[5] = sr & 0xF; + sr >>= 4; + sr |= (uint16_t) *c++ << 2; + s->LARc[6] = sr & 0x7; + sr >>= 3; + s->LARc[7] = sr & 0x7; + sr >>= 3; + + for (i = 0; i < 4; i++) + { + sr |= (uint16_t) *c++ << 4; + s->Nc[i] = sr & 0x7F; + sr >>= 7; + s->bc[i] = sr & 0x3; + sr >>= 2; + s->Mc[i] = sr & 0x3; + sr >>= 2; + sr |= (uint16_t) *c++ << 1; + s->xmaxc[i] = sr & 0x3F; + sr >>= 6; + s->xMc[i][0] = sr & 0x7; + sr >>= 3; + sr = *c++; + s->xMc[i][1] = sr & 0x7; + sr >>= 3; + s->xMc[i][2] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 2; + s->xMc[i][3] = sr & 0x7; + sr >>= 3; + s->xMc[i][4] = sr & 0x7; + sr >>= 3; + s->xMc[i][5] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 1; + s->xMc[i][6] = sr & 0x7; + sr >>= 3; + s->xMc[i][7] = sr & 0x7; + sr >>= 3; + s->xMc[i][8] = sr & 0x7; + sr >>= 3; + sr = *c++; + s->xMc[i][9] = sr & 0x7; + sr >>= 3; + s->xMc[i][10] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 2; + s->xMc[i][11] = sr & 0x7; + sr >>= 3; + s->xMc[i][12] = sr & 0x7; + sr >>= 3; + } + + s++; + sr |= (uint16_t) *c++ << 4; + s->LARc[0] = sr & 0x3F; + sr >>= 6; + s->LARc[1] = sr & 0x3F; + sr >>= 6; + sr = *c++; + s->LARc[2] = sr & 0x1F; + sr >>= 5; + sr |= (uint16_t) *c++ << 3; + s->LARc[3] = sr & 0x1F; + sr >>= 5; + s->LARc[4] = sr & 0xF; + sr >>= 4; + sr |= (uint16_t) *c++ << 2; + s->LARc[5] = sr & 0xF; + sr >>= 4; + s->LARc[6] = sr & 0x7; + sr >>= 3; + s->LARc[7] = sr & 0x7; + sr >>= 3; + + for (i = 0; i < 4; i++) + { + sr = *c++; + s->Nc[i] = sr & 0x7F; + sr >>= 7; + sr |= (uint16_t) *c++ << 1; + s->bc[i] = sr & 0x3; + sr >>= 2; + s->Mc[i] = sr & 0x3; + sr >>= 2; + sr |= (uint16_t) *c++ << 5; + s->xmaxc[i] = sr & 0x3F; + sr >>= 6; + s->xMc[i][0] = sr & 0x7; + sr >>= 3; + s->xMc[i][1] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 1; + s->xMc[i][2] = sr & 0x7; + sr >>= 3; + s->xMc[i][3] = sr & 0x7; + sr >>= 3; + s->xMc[i][4] = sr & 0x7; + sr >>= 3; + sr = *c++; + s->xMc[i][5] = sr & 0x7; + sr >>= 3; + s->xMc[i][6] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 2; + s->xMc[i][7] = sr & 0x7; + sr >>= 3; + s->xMc[i][8] = sr & 0x7; + sr >>= 3; + s->xMc[i][9] = sr & 0x7; + sr >>= 3; + sr |= (uint16_t) *c++ << 1; + s->xMc[i][10] = sr & 0x7; + sr >>= 3; + s->xMc[i][11] = sr & 0x7; + sr >>= 3; + s->xMc[i][12] = sr & 0x7; + sr >>= 3; + } + return 65; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) gsm0610_unpack_voip(gsm0610_frame_t *s, const uint8_t c[33]) +{ + int i; + + s->LARc[0] = (*c++ & 0xF) << 2; + s->LARc[0] |= (*c >> 6) & 0x3; + s->LARc[1] = *c++ & 0x3F; + s->LARc[2] = (*c >> 3) & 0x1F; + s->LARc[3] = (*c++ & 0x7) << 2; + s->LARc[3] |= (*c >> 6) & 0x3; + s->LARc[4] = (*c >> 2) & 0xF; + s->LARc[5] = (*c++ & 0x3) << 2; + s->LARc[5] |= (*c >> 6) & 0x3; + s->LARc[6] = (*c >> 3) & 0x7; + s->LARc[7] = *c++ & 0x7; + + for (i = 0; i < 4; i++) + { + s->Nc[i] = (*c >> 1) & 0x7F; + s->bc[i] = (*c++ & 0x1) << 1; + s->bc[i] |= (*c >> 7) & 0x1; + s->Mc[i] = (*c >> 5) & 0x3; + s->xmaxc[i] = (*c++ & 0x1F) << 1; + s->xmaxc[i] |= (*c >> 7) & 0x1; + s->xMc[i][0] = (*c >> 4) & 0x7; + s->xMc[i][1] = (*c >> 1) & 0x7; + s->xMc[i][2] = (*c++ & 0x1) << 2; + s->xMc[i][2] |= (*c >> 6) & 0x3; + s->xMc[i][3] = (*c >> 3) & 0x7; + s->xMc[i][4] = *c++ & 0x7; + s->xMc[i][5] = (*c >> 5) & 0x7; + s->xMc[i][6] = (*c >> 2) & 0x7; + s->xMc[i][7] = (*c++ & 0x3) << 1; + s->xMc[i][7] |= (*c >> 7) & 0x1; + s->xMc[i][8] = (*c >> 4) & 0x7; + s->xMc[i][9] = (*c >> 1) & 0x7; + s->xMc[i][10] = (*c++ & 0x1) << 2; + s->xMc[i][10] |= (*c >> 6) & 0x3; + s->xMc[i][11] = (*c >> 3) & 0x7; + s->xMc[i][12] = *c++ & 0x7; + } + return 33; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) gsm0610_decode(gsm0610_state_t *s, int16_t amp[], const uint8_t code[], int len) +{ + gsm0610_frame_t frame[2]; + int bytes; + int samples; + int i; + + samples = 0; + for (i = 0; i < len; i += bytes) + { + switch (s->packing) + { + default: + case GSM0610_PACKING_NONE: + if ((bytes = gsm0610_unpack_none(frame, &code[i])) < 0) + return 0; + decode_a_frame(s, &[samples], frame); + samples += GSM0610_FRAME_LEN; + break; + case GSM0610_PACKING_WAV49: + if ((bytes = gsm0610_unpack_wav49(frame, &code[i])) < 0) + return 0; + decode_a_frame(s, &[samples], frame); + samples += GSM0610_FRAME_LEN; + decode_a_frame(s, &[samples], frame + 1); + samples += GSM0610_FRAME_LEN; + break; + case GSM0610_PACKING_VOIP: + if ((bytes = gsm0610_unpack_voip(frame, &code[i])) < 0) + return 0; + decode_a_frame(s, &[samples], frame); + samples += GSM0610_FRAME_LEN; + break; + } + /*endswitch*/ + } + /*endfor*/ + return samples; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/