512 lines
14 KiB
C
512 lines
14 KiB
C
/*
|
|
* 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 ------------------------------------------------------------*/
|