flightgear/3rdparty/iaxclient/lib/codec_alaw.c
2022-10-20 20:29:11 +08:00

160 lines
3.1 KiB
C

/*
* iaxclient: a cross-platform IAX softphone library
*
* Copyrights:
* Copyright (C) 2004 Cyril VELTER
*
* Contributors:
* Cyril VELTER <cyril.velter@metadys.com>
*
* This program is free software, distributed under the terms of
* the GNU Lesser (Library) General Public License.
*/
#include "codec_alaw.h"
#include "iaxclient_lib.h"
#if defined(_MSC_VER)
#define INLINE __inline
#else
#define INLINE inline
#endif
struct state {
plc_state_t plc;
};
static INLINE short int alawdecode (unsigned char alaw)
{
int value;
int segment;
/* Mask value */
alaw ^= 0x55;
/* Extract and scale value */
value = (alaw & 0x0f) << 4;
/* Extract segment number */
segment = (alaw & 0x70) >> 4;
/* Compute value */
switch (segment) {
case 0:
break;
case 1:
value += 0x100;
break;
default:
value += 0x100;
value <<= segment - 1;
}
/* Extract sign */
return (alaw & 0x80) ? value : -value;
}
static INLINE unsigned char alawencode (short int linear)
{
int mask = 0x55;
int segment;
unsigned char alaw;
static int segments[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
if (linear >= 0)
{
/* Sign (7th) bit = 1 */
mask |= 0x80;
}
else
{
/* Sign (7th) bit = 0 */
linear = -linear;
}
/* Find the segment */
for (segment = 0;segment < 8;segment++)
if (linear <= segments[segment])
break;
/* Combine the sign, segment, and quantization bits. */
if (segment < 8)
{
if (segment < 2)
alaw = (linear >> 4) & 0x0F;
else
alaw = (linear >> (segment + 3)) & 0x0F;
return ((alaw | (segment << 4)) ^ mask);
}
else
/* out of range, return maximum value. */
return (0x7F ^ mask);
}
static int decode ( struct iaxc_audio_codec *c,
int *inlen, unsigned char *in, int *outlen, short *out ) {
struct state *state = (struct state *)(c->decstate);
short *orig_out = out;
short sample;
if(*inlen == 0) {
int interp_len = 160;
if(*outlen < interp_len) interp_len = *outlen;
plc_fillin(&state->plc,out,interp_len);
*outlen -= interp_len;
return 0;
}
while ((*inlen > 0) && (*outlen > 0)) {
sample = alawdecode((unsigned char)*(in++));
*(out++) = sample;
(*inlen)--; (*outlen)--;
}
plc_rx(&state->plc, orig_out, (int)(out - orig_out));
return 0;
}
static int encode ( struct iaxc_audio_codec *c,
int *inlen, short *in, int *outlen, unsigned char *out ) {
while ((*inlen > 0) && (*outlen > 0)) {
*(out++) = alawencode(*(in++));
(*inlen)--; (*outlen)--;
}
return 0;
}
static void destroy ( struct iaxc_audio_codec *c) {
free(c);
}
struct iaxc_audio_codec *codec_audio_alaw_new() {
struct iaxc_audio_codec *c = (struct iaxc_audio_codec *)calloc(1, sizeof(struct iaxc_audio_codec));
if(!c) return c;
strcpy(c->name,"alaw");
c->format = IAXC_FORMAT_ALAW;
c->encode = encode;
c->decode = decode;
c->destroy = destroy;
/* really, we can use less, but don't want to */
c->minimum_frame_size = 160;
/* decoder state, used for interpolation */
c->decstate = calloc(sizeof(struct state),1);
plc_init(&((struct state *)c->decstate)->plc);
return c;
}