This change set fixes bug 8126 in trunk. It is implemented via compile time options, activated via the menuselect stuff, which defaults to the old way. non-zero sample data added. Translate tables expressed in microseconds instead of milliseconds, with 5-digit data now instead of 3, giving 2 more digits of precision.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@80113 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Steve Murphy
2007-08-20 22:53:48 +00:00
parent c9ab65a3bf
commit 337c44236d
8 changed files with 421 additions and 55 deletions

View File

@@ -20,6 +20,19 @@
</member>
<member name="LOW_MEMORY" displayname="Optimize for Low Memory Usage">
</member>
<member name="G711_NEW_ALGORITHM" displayname="Use the NEW ulaw/alaw codecs (slower, but cleaner)">
<defaultenabled>no</defaultenabled>
</member>
<member name="G711_REDUCED_BRANCHING" displayname="New ulaw/alaw codec, reduced branching (might help it run faster in some architectures)">
<defaultenabled>yes</defaultenabled>
<depend>G711_NEW_ALGORITHM</depend>
</member>
<member name="TEST_CODING_TABLES" displayname="New ulaw/alaw codec, turn on table tests on init">
<depend>G711_NEW_ALGORITHM</depend>
</member>
<member name="TEST_TANDEM_TRANSCODING" displayname="New ulaw/alaw codec, turn on transcoding tests on init">
<depend>G711_NEW_ALGORITHM</depend>
</member>
<member name="MALLOC_DEBUG" displayname="Keep Track of Memory Allocations">
</member>
<member name="MTX_PROFILE" displayname="Enable Code Profiling Using TSC Counters">

View File

@@ -12,14 +12,14 @@
*/
static signed short slin_ulaw_ex[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
0xcac0, 0xcdeb, 0xd116, 0xd441, 0xd76c, 0xda97, 0xddc2, 0xe0ed,
0x0000, 0x032b, 0x0656, 0x0981, 0x0cac, 0x0fd7, 0x1302, 0x162d,
0x1958, 0x1c83, 0x1fae, 0x22d9, 0x2604, 0x292f, 0x2c5a, 0x2f85,
0x32b0, 0x35db, 0x3906, 0x3c31, 0x3f5c, 0x4287, 0x45b2, 0x48dd,
0xb168, 0xb493, 0xb7be, 0xbae9, 0xbe14, 0xc13f, 0xc46a, 0xc795,
0xe418, 0xe743, 0xea6e, 0xed99, 0xf0c4, 0xf3ef, 0xf71a, 0xfa45,
0x9810, 0x9b3b, 0x9e66, 0xa191, 0xa4bc, 0xa7e7, 0xab12, 0xae3d,
0x4c08, 0x4f33, 0x525e, 0x5589, 0x58b4, 0x5bdf, 0x5f0a, 0x6235,
0x6560, 0x688b, 0x6bb6, 0x6ee1, 0x720c, 0x7537, 0x7862, 0x7b8d,
0x7eb8, 0x81e3, 0x850e, 0x8839, 0x8b64, 0x8e8f, 0x91ba, 0x94e5,
};

View File

@@ -12,14 +12,14 @@
*/
static unsigned char ulaw_slin_ex[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15,
0x10, 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a,
0x20, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f,
0x30, 0x42, 0x45, 0x48, 0x4b, 0x4e, 0x51, 0x54,
0x40, 0x57, 0x5a, 0x5d, 0x60, 0x63, 0x66, 0x69,
0x50, 0x6c, 0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e,
0x60, 0x81, 0x84, 0x87, 0x8a, 0x8d, 0x90, 0x93,
0x70, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8,
0x80, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd,
0x90, 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2
};

View File

@@ -23,21 +23,67 @@
#ifndef _ASTERISK_ALAW_H
#define _ASTERISK_ALAW_H
/*! Init the ulaw conversion stuff */
/*!
* To init the ulaw to slinear conversion stuff, this needs to be run.
* To init the alaw to slinear conversion stuff, this needs to be run.
*/
void ast_alaw_init(void);
/*! converts signed linear to mulaw */
#define AST_ALAW_BIT_LOSS 4
#define AST_ALAW_STEP (1 << AST_ALAW_BIT_LOSS)
#define AST_ALAW_TAB_SIZE (32768 / AST_ALAW_STEP + 1)
#define AST_ALAW_SIGN_BIT 0x80
#define AST_ALAW_AMI_MASK 0x55
/*! converts signed linear to alaw */
/*!
*/
*/
#ifndef G711_NEW_ALGORITHM
extern unsigned char __ast_lin2a[8192];
#else
extern unsigned char __ast_lin2a[AST_ALAW_TAB_SIZE];
#endif
/*! help */
extern short __ast_alaw[256];
#ifndef G711_NEW_ALGORITHM
#define AST_LIN2A(a) (__ast_lin2a[((unsigned short)(a)) >> 3])
#else
#define AST_LIN2A_LOOKUP(mag) \
__ast_lin2a[(mag) >> AST_ALAW_BIT_LOSS]
/*! convert signed linear sample to sign-magnitude pair for a-Law */
static inline void ast_alaw_get_sign_mag(short sample, unsigned *sign, unsigned *mag)
{
/* It may look illogical to retrive the sign this way in both cases,
* but this helps gcc eliminate the branch below and produces
* faster code */
*sign = ((unsigned short)sample >> 8) & AST_ALAW_SIGN_BIT;
#if defined(G711_REDUCED_BRANCHING)
{
unsigned dual_mag = (-sample << 16) | (unsigned short)sample;
*mag = (dual_mag >> (*sign >> 3)) & 0xffffU;
}
#else
if (sample < 0)
*mag = -sample;
else
*mag = sample;
#endif /* G711_REDUCED_BRANCHING */
*sign ^= AST_ALAW_SIGN_BIT;
}
static inline unsigned char AST_LIN2A(short sample)
{
unsigned mag, sign;
ast_alaw_get_sign_mag(sample, &sign, &mag);
return (sign | AST_LIN2A_LOOKUP(mag)) ^ AST_ALAW_AMI_MASK;
}
#endif
#define AST_ALAW(a) (__ast_alaw[(int)(a)])
#endif /* _ASTERISK_ALAW_H */

View File

@@ -23,21 +23,68 @@
#ifndef _ASTERISK_ULAW_H
#define _ASTERISK_ULAW_H
/*! Init the ulaw conversion stuff */
/*!
* To init the ulaw to slinear conversion stuff, this needs to be run.
*/
void ast_ulaw_init(void);
#define AST_ULAW_BIT_LOSS 3
#define AST_ULAW_STEP (1 << AST_ULAW_BIT_LOSS)
#define AST_ULAW_TAB_SIZE (32768 / AST_ULAW_STEP + 1)
#define AST_ULAW_SIGN_BIT 0x80
/*! converts signed linear to mulaw */
/*!
*/
#ifndef G711_NEW_ALGORITHM
extern unsigned char __ast_lin2mu[16384];
#else
extern unsigned char __ast_lin2mu[AST_ULAW_TAB_SIZE];
#endif
/*! help */
extern short __ast_mulaw[256];
#ifndef G711_NEW_ALGORITHM
#define AST_LIN2MU(a) (__ast_lin2mu[((unsigned short)(a)) >> 2])
#else
#define AST_LIN2MU_LOOKUP(mag) \
__ast_lin2mu[((mag) + AST_ULAW_STEP / 2) >> AST_ULAW_BIT_LOSS]
/*! convert signed linear sample to sign-magnitude pair for u-Law */
static inline void ast_ulaw_get_sign_mag(short sample, unsigned *sign, unsigned *mag)
{
/* It may look illogical to retrive the sign this way in both cases,
* but this helps gcc eliminate the branch below and produces
* faster code */
*sign = ((unsigned short)sample >> 8) & AST_ULAW_SIGN_BIT;
#if defined(G711_REDUCED_BRANCHING)
{
unsigned dual_mag = (-sample << 16) | (unsigned short)sample;
*mag = (dual_mag >> (*sign >> 3)) & 0xffffU;
}
#else
if (sample < 0)
*mag = -sample;
else
*mag = sample;
#endif /* G711_REDUCED_BRANCHING */
}
static inline unsigned char AST_LIN2MU(short sample)
{
unsigned mag, sign;
ast_ulaw_get_sign_mag(sample, &sign, &mag);
return ~(sign | AST_LIN2MU_LOOKUP(mag));
}
#endif
#define AST_MULAW(a) (__ast_mulaw[(a)])
#endif /* _ASTERISK_ULAW_H */

View File

@@ -18,7 +18,7 @@
/*! \file
*
* \brief u-Law to Signed linear conversion
* \brief a-Law to Signed linear conversion
*
* \author Mark Spencer <markster@digium.com>
*/
@@ -28,18 +28,20 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/alaw.h"
#include "asterisk/logger.h"
#ifndef G711_NEW_ALGORITHM
#define AMI_MASK 0x55
static inline unsigned char linear2alaw (short int linear)
static inline unsigned char linear2alaw(short int linear)
{
int mask;
int seg;
int pcm_val;
static int seg_end[8] =
{
0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
};
{
0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
};
pcm_val = linear;
if (pcm_val >= 0) {
@@ -50,7 +52,7 @@ static inline unsigned char linear2alaw (short int linear)
mask = AMI_MASK;
pcm_val = -pcm_val;
}
/* Convert the scaled magnitude to segment number. */
for (seg = 0; seg < 8; seg++) {
if (pcm_val <= seg_end[seg])
@@ -59,13 +61,56 @@ static inline unsigned char linear2alaw (short int linear)
/* Combine the sign, segment, and quantization bits. */
return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask;
}
/*- End of function --------------------------------------------------------*/
#else
static unsigned char linear2alaw(short sample, int full_coding)
{
static const unsigned exp_lut[128] = {
1,1,2,2,3,3,3,3,
4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7 };
unsigned sign, exponent, mantissa, mag;
unsigned char alawbyte;
ast_alaw_get_sign_mag(sample, &sign, &mag);
if (mag > 32767)
mag = 32767; /* clip the magnitude for -32768 */
exponent = exp_lut[(mag >> 8) & 0x7f];
mantissa = (mag >> (exponent + 3)) & 0x0f;
if (mag < 0x100)
exponent = 0;
if (full_coding) {
/* full encoding, with sign and xform */
alawbyte = (unsigned char)(sign | (exponent << 4) | mantissa);
alawbyte ^= AST_ALAW_AMI_MASK;
} else {
/* half-cooked coding -- mantissa+exponent only (for lookup tab) */
alawbyte = (exponent << 4) | mantissa;
}
return alawbyte;
}
#endif
#ifndef G711_NEW_ALGORITHM
static inline short int alaw2linear (unsigned char alaw)
{
int i;
int seg;
alaw ^= AMI_MASK;
i = ((alaw & 0x0F) << 4);
seg = (((int) alaw & 0x70) >> 4);
@@ -73,8 +118,31 @@ static inline short int alaw2linear (unsigned char alaw)
i = (i + 0x100) << (seg - 1);
return (short int) ((alaw & 0x80) ? i : -i);
}
#else
static inline short alaw2linear(unsigned char alawbyte)
{
unsigned exponent, mantissa;
short sample;
alawbyte ^= AST_ALAW_AMI_MASK;
exponent = (alawbyte & 0x70) >> 4;
mantissa = alawbyte & 0x0f;
sample = (mantissa << 4) + 8 /* rounding error */;
if (exponent)
sample = (sample + 0x100) << (exponent - 1);
if (!(alawbyte & 0x80))
sample = -sample;
return sample;
}
#endif
#ifndef G711_NEW_ALGORITHM
unsigned char __ast_lin2a[8192];
#else
unsigned char __ast_lin2a[AST_ALAW_TAB_SIZE];
#endif
short __ast_alaw[256];
void ast_alaw_init(void)
@@ -82,14 +150,62 @@ void ast_alaw_init(void)
int i;
/*
* Set up mu-law conversion table
*/
*/
#ifndef G711_NEW_ALGORITHM
for (i = 0; i < 256; i++) {
__ast_alaw[i] = alaw2linear(i);
__ast_alaw[i] = alaw2linear(i);
}
/* set up the reverse (mu-law) conversion table */
for (i = -32768; i < 32768; i++) {
__ast_lin2a[((unsigned short)i) >> 3] = linear2alaw(i);
}
#else
for (i = 0; i < 256; i++) {
__ast_alaw[i] = alaw2linear(i);
}
/* set up the reverse (a-law) conversion table */
for (i = 0; i <= 32768; i += AST_ALAW_STEP) {
AST_LIN2A_LOOKUP(i) = linear2alaw(i, 0 /* half-cooked */);
}
#endif
#ifdef TEST_CODING_TABLES
for (i = -32768; i < 32768; ++i) {
#ifndef G711_NEW_ALGORITHM
unsigned char e1 = linear2alaw(i);
#else
unsigned char e1 = linear2alaw(i, 1);
#endif
short d1 = alaw2linear(e1);
unsigned char e2 = AST_LIN2A(i);
short d2 = alaw2linear(e2);
short d3 = AST_ALAW(e1);
if (e1 != e2 || d1 != d3 || d2 != d3) {
ast_log(LOG_WARNING, "a-Law coding tables test failed on %d: e1=%u, e2=%u, d1=%d, d2=%d\n",
i, (unsigned)e1, (unsigned)e2, (int)d1, (int)d2);
}
}
ast_log(LOG_NOTICE, "a-Law coding tables test complete.\n");
#endif /* TEST_CODING_TABLES */
#ifdef TEST_TANDEM_TRANSCODING
/* tandem transcoding test */
for (i = -32768; i < 32768; ++i) {
unsigned char e1 = AST_LIN2A(i);
short d1 = AST_ALAW(e1);
unsigned char e2 = AST_LIN2A(d1);
short d2 = AST_ALAW(e2);
unsigned char e3 = AST_LIN2A(d2);
short d3 = AST_ALAW(e3);
if (e1 != e2 || e2 != e3 || d1 != d2 || d2 != d3) {
ast_log(LOG_WARNING, "a-Law tandem transcoding test failed on %d: e1=%u, e2=%u, d1=%d, d2=%d, d3=%d\n",
i, (unsigned)e1, (unsigned)e2, (int)d1, (int)d2, (int)d3);
}
}
ast_log(LOG_NOTICE, "a-Law tandem transcoding test complete.\n");
#endif /* TEST_TANDEM_TRANSCODING */
}

View File

@@ -46,7 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cli.h"
#include "asterisk/term.h"
#define MAX_RECALC 200 /* max sample recalc */
#define MAX_RECALC 1000 /* max sample recalc */
/*! \brief the list of translators */
static AST_RWLIST_HEAD_STATIC(translators, ast_translator);
@@ -371,6 +371,7 @@ static void calc_cost(struct ast_translator *t, int seconds)
int sofar=0;
struct ast_trans_pvt *pvt;
struct timeval start;
struct timeval end;
int cost;
if (!seconds)
@@ -379,13 +380,13 @@ static void calc_cost(struct ast_translator *t, int seconds)
/* If they don't make samples, give them a terrible score */
if (!t->sample) {
ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
t->cost = 99999;
t->cost = 999999;
return;
}
pvt = newpvt(t);
if (!pvt) {
ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
t->cost = 99999;
t->cost = 999999;
return;
}
start = ast_tvnow();
@@ -395,7 +396,7 @@ static void calc_cost(struct ast_translator *t, int seconds)
if (!f) {
ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
destroy(pvt);
t->cost = 99999;
t->cost = 999999;
return;
}
framein(pvt, f);
@@ -405,7 +406,8 @@ static void calc_cost(struct ast_translator *t, int seconds)
ast_frfree(f);
}
}
cost = ast_tvdiff_ms(ast_tvnow(), start);
end = ast_tvnow();
cost = ((end.tv_sec - start.tv_sec)*1000000) + end.tv_usec - start.tv_usec;
destroy(pvt);
t->cost = cost / seconds;
if (!t->cost)
@@ -516,7 +518,7 @@ static int show_translation(int fd, int argc, char *argv[])
AST_RWLIST_RDLOCK(&translators);
ast_cli(fd, " Translation times between formats (in milliseconds) for one second of data\n");
ast_cli(fd, " Translation times between formats (in microseconds) for one second of data\n");
ast_cli(fd, " Source Format (Rows) Destination Format (Columns)\n\n");
/* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
for (x = 0; x < SHOW_TRANS; x++) {
@@ -530,12 +532,13 @@ static int show_translation(int fd, int argc, char *argv[])
ast_str_set(&out, -1, " ");
for (y = -1; y < SHOW_TRANS; y++) {
curlen = strlen(ast_getformatname(1 << (y)));
if (curlen < 5)
curlen = 5;
if (x >= 0 && y >= 0 && tr_matrix[x][y].step) {
/* XXX 999 is a little hackish
/* XXX 99999 is a little hackish
We don't want this number being larger than the shortest (or current) codec
For now, that is "gsm" */
ast_str_append(&out, -1, "%*d", curlen + 1, tr_matrix[x][y].cost > 999 ? 0 : tr_matrix[x][y].cost);
ast_str_append(&out, -1, "%*d", curlen + 1, tr_matrix[x][y].cost > 99999 ? 0 : tr_matrix[x][y].cost);
} else if (x == -1 && y >= 0) {
/* Top row - use a dynamic size */
ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(1 << (x + y + 1)) );

View File

@@ -28,15 +28,25 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/ulaw.h"
#include "asterisk/logger.h"
#if 0
/* ZEROTRAP is the military recommendation to improve the encryption
* of u-Law traffic. It is irrelevant with modern encryption systems
* like AES, and will simply degrade the signal quality.
* ZEROTRAP is not implemented in AST_LIN2MU and so the coding table
* tests will fail if you use it */
#define ZEROTRAP /*!< turn on the trap as per the MIL-STD */
#endif
#define BIAS 0x84 /*!< define the add-in bias for 16 bit samples */
#define CLIP 32635
#ifndef G711_NEW_ALGORITHM
unsigned char __ast_lin2mu[16384];
short __ast_mulaw[256];
static unsigned char linear2ulaw(short sample)
{
static int exp_lut[256] = {
@@ -58,26 +68,102 @@ static unsigned char linear2ulaw(short sample)
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 };
int sign, exponent, mantissa;
unsigned char ulawbyte;
/* Get the sample into sign-magnitude. */
sign = (sample >> 8) & 0x80; /* set aside the sign */
if (sign != 0)
if (sign != 0)
sample = -sample; /* get magnitude */
if (sample > CLIP)
sample = CLIP; /* clip the magnitude */
/* Convert from 16 bit linear to ulaw. */
sample = sample + BIAS;
exponent = exp_lut[(sample >> 7) & 0xFF];
mantissa = (sample >> (exponent + 3)) & 0x0F;
ulawbyte = ~(sign | (exponent << 4) | mantissa);
#ifdef ZEROTRAP
if (ulawbyte == 0)
ulawbyte = 0x02; /* optional CCITT trap */
#endif
return ulawbyte;
}
#else
unsigned char __ast_lin2mu[AST_ULAW_TAB_SIZE];
short __ast_mulaw[256];
static unsigned char linear2ulaw(short sample, int full_coding)
{
static const unsigned exp_lut[256] = {
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 };
unsigned sign, exponent, mantissa, mag;
unsigned char ulawbyte;
/* Get the sample into sign-magnitude. */
ast_ulaw_get_sign_mag(sample, &sign, &mag);
if (mag > CLIP)
mag = CLIP; /* clip the magnitude */
sign = (sample >> 8) & 0x80; /* set aside the sign */
if (sign != 0)
sample = -sample; /* get magnitude */
if (sample > CLIP)
sample = CLIP; /* clip the magnitude */
/* Convert from 16 bit linear to ulaw. */
mag += BIAS;
exponent = exp_lut[(mag >> 7) & 0xFF];
mantissa = (mag >> (exponent + 3)) & 0x0F;
if (full_coding) {
/* full encoding, with sign and xform */
ulawbyte = ~(sign | (exponent << 4) | mantissa);
#ifdef ZEROTRAP
if (ulawbyte == 0)
ulawbyte = 0x02; /* optional CCITT trap */
#endif
} else {
/* half-cooked coding -- mantissa+exponent only (for lookup tab) */
ulawbyte = (exponent << 4) | mantissa;
}
return ulawbyte;
}
static inline short ulaw2linear(unsigned char ulawbyte)
{
unsigned exponent, mantissa;
short sample;
static const short etab[]={0,132,396,924,1980,4092,8316,16764};
ulawbyte = ~ulawbyte;
exponent = (ulawbyte & 0x70) >> 4;
mantissa = ulawbyte & 0x0f;
sample = mantissa << (exponent + 3);
sample += etab[exponent];
if (ulawbyte & 0x80)
sample = -sample;
return sample;
}
#endif
/*!
* \brief Set up mu-law conversion table
@@ -85,22 +171,77 @@ static unsigned char linear2ulaw(short sample)
void ast_ulaw_init(void)
{
int i;
for (i = 0; i < 256; i++) {
short mu, e, f, y;
static short etab[] = {0,132,396,924,1980,4092,8316,16764};
mu = 255 - i;
e = (mu & 0x70) / 16;
/*
* Set up mu-law conversion table
*/
#ifndef G711_NEW_ALGORITHM
for (i = 0;i < 256;i++) {
short mu,e,f,y;
static short etab[]={0,132,396,924,1980,4092,8316,16764};
mu = 255-i;
e = (mu & 0x70)/16;
f = mu & 0x0f;
y = f * (1 << (e + 3));
y += etab[e];
if (mu & 0x80)
y = -y;
if (mu & 0x80) y = -y;
__ast_mulaw[i] = y;
}
/* set up the reverse (mu-law) conversion table */
for (i = -32768; i < 32768; i++) {
__ast_lin2mu[((unsigned short)i) >> 2] = linear2ulaw(i);
}
#else
for (i = 0; i < 256; i++) {
__ast_mulaw[i] = ulaw2linear(i);
}
/* set up the reverse (mu-law) conversion table */
for (i = 0; i <= 32768; i += AST_ULAW_STEP) {
AST_LIN2MU_LOOKUP(i) = linear2ulaw(i, 0 /* half-cooked */);
}
#endif
#ifdef TEST_CODING_TABLES
for (i = -32768; i < 32768; ++i) {
#ifndef G711_NEW_ALGORITHM
unsigned char e1 = linear2ulaw(i);
#else
unsigned char e1 = linear2ulaw(i, 1);
#endif
short d1 = ulaw2linear(e1);
unsigned char e2 = AST_LIN2MU(i);
short d2 = ulaw2linear(e2);
short d3 = AST_MULAW(e1);
if (e1 != e2 || d1 != d3 || d2 != d3) {
ast_log(LOG_WARNING, "u-Law coding tables test failed on %d: e1=%u, e2=%u, d1=%d, d2=%d\n",
i, (unsigned)e1, (unsigned)e2, (int)d1, (int)d2);
}
}
ast_log(LOG_NOTICE, "u-Law coding table test complete.\n");
#endif /* TEST_CODING_TABLES */
#ifdef TEST_TANDEM_TRANSCODING
/* tandem transcoding test */
for (i = -32768; i < 32768; ++i) {
unsigned char e1 = AST_LIN2MU(i);
short d1 = AST_MULAW(e1);
unsigned char e2 = AST_LIN2MU(d1);
short d2 = AST_MULAW(e2);
unsigned char e3 = AST_LIN2MU(d2);
short d3 = AST_MULAW(e3);
if (i < 0 && e1 == 0x7f && e2 == 0xff && e3 == 0xff)
continue; /* known and normal negative 0 case */
if (e1 != e2 || e2 != e3 || d1 != d2 || d2 != d3) {
ast_log(LOG_WARNING, "u-Law tandem transcoding test failed on %d: e1=%u, e2=%u, d1=%d, d2=%d, d3=%d\n",
i, (unsigned)e1, (unsigned)e2, (int)d1, (int)d2, (int)d3);
}
}
ast_log(LOG_NOTICE, "u-Law tandem transcoding test complete.\n");
#endif /* TEST_TANDEM_TRANSCODING */
}