Mercurial > hg > audiostuff
diff spandsp-0.0.6pre17/src/ima_adpcm.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/ima_adpcm.c Fri Jun 25 15:50:58 2010 +0200 @@ -0,0 +1,511 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * ima_adpcm.c - Conversion routines between linear 16 bit PCM data and + * IMA/DVI/Intel ADPCM format. + * + * Written by Steve Underwood <steveu@coppice.org> + * + * Copyright (C) 2001, 2004 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. + * + * $Id: ima_adpcm.c,v 1.36 2009/04/11 18:11:19 steveu Exp $ + */ + +/*! \file */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include <stdlib.h> +#include <inttypes.h> +#include <string.h> +#if defined(HAVE_TGMATH_H) +#include <tgmath.h> +#endif +#if defined(HAVE_MATH_H) +#include <math.h> +#endif +#include "floating_fudge.h" + +#include "spandsp/telephony.h" +#include "spandsp/fast_convert.h" +#include "spandsp/saturated.h" +#include "spandsp/ima_adpcm.h" +#include "spandsp/private/ima_adpcm.h" + +/* + * Intel/DVI ADPCM coder/decoder. + * + * The algorithm for this coder was taken from the IMA Compatability Project + * proceedings, Vol 2, Number 2; May 1992. + * + * The RTP payload specs. reference a variant of DVI, called VDVI. This attempts to + * further compress, in a variable bit rate manner, by expressing the 4 bit codes + * from the DVI codec as: + * + * 0 00 + * 1 010 + * 2 1100 + * 3 11100 + * 4 111100 + * 5 1111100 + * 6 11111100 + * 7 11111110 + * 8 10 + * 9 011 + * 10 1101 + * 11 11101 + * 12 111101 + * 13 1111101 + * 14 11111101 + * 15 11111111 + * + * Any left over bits in the last octet of an encoded burst are set to one. + */ + +/* + DVI4 uses an adaptive delta pulse code modulation (ADPCM) encoding + scheme that was specified by the Interactive Multimedia Association + (IMA) as the "IMA ADPCM wave type". However, the encoding defined + here as DVI4 differs in three respects from the IMA specification: + + o The RTP DVI4 header contains the predicted value rather than the + first sample value contained the IMA ADPCM block header. + + o IMA ADPCM blocks contain an odd number of samples, since the first + sample of a block is contained just in the header (uncompressed), + followed by an even number of compressed samples. DVI4 has an + even number of compressed samples only, using the `predict' word + from the header to decode the first sample. + + o For DVI4, the 4-bit samples are packed with the first sample in + the four most significant bits and the second sample in the four + least significant bits. In the IMA ADPCM codec, the samples are + packed in the opposite order. + + Each packet contains a single DVI block. This profile only defines + the 4-bit-per-sample version, while IMA also specified a 3-bit-per- + sample encoding. + + The "header" word for each channel has the following structure: + + int16 predict; // predicted value of first sample + // from the previous block (L16 format) + u_int8 index; // current index into stepsize table + u_int8 reserved; // set to zero by sender, ignored by receiver + + Each octet following the header contains two 4-bit samples, thus the + number of samples per packet MUST be even because there is no means + to indicate a partially filled last octet. +*/ + +/*! The number of ADPCM step sizes */ +#define STEP_MAX 88 + +/* Intel ADPCM step variation table */ +static const int step_size[STEP_MAX + 1] = +{ + 7, 8, 9, 10, 11, 12, 13, 14, + 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, + 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, + 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, + 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, + 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767 +}; + +static const int step_adjustment[8] = +{ + -1, -1, -1, -1, 2, 4, 6, 8 +}; + +static const struct +{ + uint8_t code; + uint8_t bits; +} vdvi_encode[] = +{ + {0x00, 2}, + {0x02, 3}, + {0x0C, 4}, + {0x1C, 5}, + {0x3C, 6}, + {0x7C, 7}, + {0xFC, 8}, + {0xFE, 8}, + {0x02, 2}, + {0x03, 3}, + {0x0D, 4}, + {0x1D, 5}, + {0x3D, 6}, + {0x7D, 7}, + {0xFD, 8}, + {0xFF, 8} +}; + +static const struct +{ + uint16_t code; + uint16_t mask; + uint8_t bits; +} vdvi_decode[] = +{ + {0x0000, 0xC000, 2}, + {0x4000, 0xE000, 3}, + {0xC000, 0xF000, 4}, + {0xE000, 0xF800, 5}, + {0xF000, 0xFC00, 6}, + {0xF800, 0xFE00, 7}, + {0xFC00, 0xFF00, 8}, + {0xFE00, 0xFF00, 8}, + {0x8000, 0xC000, 2}, + {0x6000, 0xE000, 3}, + {0xD000, 0xF000, 4}, + {0xE800, 0xF800, 5}, + {0xF400, 0xFC00, 6}, + {0xFA00, 0xFE00, 7}, + {0xFD00, 0xFF00, 8}, + {0xFF00, 0xFF00, 8} +}; + +static int16_t decode(ima_adpcm_state_t *s, uint8_t adpcm) +{ + int e; + int ss; + int16_t linear; + + /* e = (adpcm+0.5)*step/4 */ + ss = step_size[s->step_index]; + e = ss >> 3; + if (adpcm & 0x01) + e += (ss >> 2); + /*endif*/ + if (adpcm & 0x02) + e += (ss >> 1); + /*endif*/ + if (adpcm & 0x04) + e += ss; + /*endif*/ + if (adpcm & 0x08) + e = -e; + /*endif*/ + linear = saturate(s->last + e); + s->last = linear; + s->step_index += step_adjustment[adpcm & 0x07]; + if (s->step_index < 0) + s->step_index = 0; + else if (s->step_index > STEP_MAX) + s->step_index = STEP_MAX; + /*endif*/ + return linear; +} +/*- End of function --------------------------------------------------------*/ + +static uint8_t encode(ima_adpcm_state_t *s, int16_t linear) +{ + int e; + int ss; + int adpcm; + int diff; + int initial_e; + + ss = step_size[s->step_index]; + initial_e = + e = linear - s->last; + diff = ss >> 3; + adpcm = (uint8_t) 0x00; + if (e < 0) + { + adpcm = (uint8_t) 0x08; + e = -e; + } + /*endif*/ + if (e >= ss) + { + adpcm |= (uint8_t) 0x04; + e -= ss; + } + /*endif*/ + ss >>= 1; + if (e >= ss) + { + adpcm |= (uint8_t) 0x02; + e -= ss; + } + /*endif*/ + ss >>= 1; + if (e >= ss) + { + adpcm |= (uint8_t) 0x01; + e -= ss; + } + /*endif*/ + + if (initial_e < 0) + diff = -(diff - initial_e - e); + else + diff = diff + initial_e - e; + /*endif*/ + s->last = saturate(diff + s->last); + s->step_index += step_adjustment[adpcm & 0x07]; + if (s->step_index < 0) + s->step_index = 0; + else if (s->step_index > STEP_MAX) + s->step_index = STEP_MAX; + /*endif*/ + return (uint8_t) adpcm; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(ima_adpcm_state_t *) ima_adpcm_init(ima_adpcm_state_t *s, + int variant, + int chunk_size) +{ + if (s == NULL) + { + if ((s = (ima_adpcm_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + /*endif*/ + memset(s, 0, sizeof(*s)); + s->variant = variant; + s->chunk_size = chunk_size; + return s; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) ima_adpcm_release(ima_adpcm_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) ima_adpcm_free(ima_adpcm_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) ima_adpcm_decode(ima_adpcm_state_t *s, + int16_t amp[], + const uint8_t ima_data[], + int ima_bytes) +{ + int i; + int j; + int samples; + uint16_t code; + + samples = 0; + switch (s->variant) + { + case IMA_ADPCM_IMA4: + i = 0; + if (s->chunk_size == 0) + { + amp[samples++] = (ima_data[1] << 8) | ima_data[0]; + s->step_index = ima_data[2]; + s->last = amp[0]; + i = 4; + } + /*endif*/ + for ( ; i < ima_bytes; i++) + { + amp[samples++] = decode(s, ima_data[i] & 0xF); + amp[samples++] = decode(s, (ima_data[i] >> 4) & 0xF); + } + /*endfor*/ + break; + case IMA_ADPCM_DVI4: + i = 0; + if (s->chunk_size == 0) + { + s->last = (int16_t) ((ima_data[0] << 8) | ima_data[1]); + s->step_index = ima_data[2]; + i = 4; + } + /*endif*/ + for ( ; i < ima_bytes; i++) + { + amp[samples++] = decode(s, (ima_data[i] >> 4) & 0xF); + amp[samples++] = decode(s, ima_data[i] & 0xF); + } + /*endfor*/ + break; + case IMA_ADPCM_VDVI: + i = 0; + if (s->chunk_size == 0) + { + s->last = (int16_t) ((ima_data[0] << 8) | ima_data[1]); + s->step_index = ima_data[2]; + i = 4; + } + /*endif*/ + code = 0; + s->bits = 0; + for (;;) + { + if (s->bits <= 8) + { + if (i >= ima_bytes) + break; + /*endif*/ + code |= ((uint16_t) ima_data[i++] << (8 - s->bits)); + s->bits += 8; + } + /*endif*/ + for (j = 0; j < 8; j++) + { + if ((vdvi_decode[j].mask & code) == vdvi_decode[j].code) + break; + if ((vdvi_decode[j + 8].mask & code) == vdvi_decode[j + 8].code) + { + j += 8; + break; + } + /*endif*/ + } + /*endfor*/ + amp[samples++] = decode(s, (uint8_t) j); + code <<= vdvi_decode[j].bits; + s->bits -= vdvi_decode[j].bits; + } + /*endfor*/ + /* Use up the remanents of the last octet */ + while (s->bits > 0) + { + for (j = 0; j < 8; j++) + { + if ((vdvi_decode[j].mask & code) == vdvi_decode[j].code) + break; + /*endif*/ + if ((vdvi_decode[j + 8].mask & code) == vdvi_decode[j + 8].code) + { + j += 8; + break; + } + /*endif*/ + } + /*endfor*/ + if (vdvi_decode[j].bits > s->bits) + break; + /*endif*/ + amp[samples++] = decode(s, (uint8_t) j); + code <<= vdvi_decode[j].bits; + s->bits -= vdvi_decode[j].bits; + } + /*endwhile*/ + break; + } + /*endswitch*/ + return samples; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) ima_adpcm_encode(ima_adpcm_state_t *s, + uint8_t ima_data[], + const int16_t amp[], + int len) +{ + int i; + int bytes; + uint8_t code; + + bytes = 0; + switch (s->variant) + { + case IMA_ADPCM_IMA4: + i = 0; + if (s->chunk_size == 0) + { + ima_data[bytes++] = (uint8_t) amp[0]; + ima_data[bytes++] = (uint8_t) (amp[0] >> 8); + ima_data[bytes++] = (uint8_t) s->step_index; + ima_data[bytes++] = 0; + s->last = amp[0]; + s->bits = 0; + i = 1; + } + /*endif*/ + for ( ; i < len; i++) + { + s->ima_byte = (uint8_t) ((s->ima_byte >> 4) | (encode(s, amp[i]) << 4)); + if ((s->bits++ & 1)) + ima_data[bytes++] = (uint8_t) s->ima_byte; + /*endif*/ + } + /*endfor*/ + break; + case IMA_ADPCM_DVI4: + if (s->chunk_size == 0) + { + ima_data[bytes++] = (uint8_t) (s->last >> 8); + ima_data[bytes++] = (uint8_t) s->last; + ima_data[bytes++] = (uint8_t) s->step_index; + ima_data[bytes++] = 0; + } + /*endif*/ + for (i = 0; i < len; i++) + { + s->ima_byte = (uint8_t) ((s->ima_byte << 4) | encode(s, amp[i])); + if ((s->bits++ & 1)) + ima_data[bytes++] = (uint8_t) s->ima_byte; + /*endif*/ + } + /*endfor*/ + break; + case IMA_ADPCM_VDVI: + if (s->chunk_size == 0) + { + ima_data[bytes++] = (uint8_t) (s->last >> 8); + ima_data[bytes++] = (uint8_t) s->last; + ima_data[bytes++] = (uint8_t) s->step_index; + ima_data[bytes++] = 0; + } + /*endif*/ + s->bits = 0; + for (i = 0; i < len; i++) + { + code = encode(s, amp[i]); + s->ima_byte = (s->ima_byte << vdvi_encode[code].bits) | vdvi_encode[code].code; + s->bits += vdvi_encode[code].bits; + if (s->bits >= 8) + { + s->bits -= 8; + ima_data[bytes++] = (uint8_t) (s->ima_byte >> s->bits); + } + /*endif*/ + } + /*endfor*/ + if (s->bits) + ima_data[bytes++] = (uint8_t) (((s->ima_byte << 8) | 0xFF) >> s->bits); + /*endif*/ + break; + } + /*endswitch*/ + return bytes; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/