diff options
author | murf <murf@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-08-21 16:36:34 +0000 |
---|---|---|
committer | murf <murf@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-08-21 16:36:34 +0000 |
commit | 6bae76f8d4a6ab1ad9833daf06b34c17c116eb58 (patch) | |
tree | 3e0ade76930fc4b63d5181fd5bdbb9d6ccdfdfbc | |
parent | d9e46ad2447f0c348262b101da297e5ace9a4f3a (diff) |
This patch solves problem 1 in 8126; it should not slow down the alaw codec, but should prevent signal degradation via multiple trips thru the codec. Fossil estimates the twice thru this codec will prevent fax from working. 4-6 times thru would result hearable, noticeable, voice degradation.
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@80166 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | include/asterisk/alaw.h | 50 | ||||
-rw-r--r-- | include/asterisk/ulaw.h | 50 | ||||
-rw-r--r-- | main/alaw.c | 2 |
3 files changed, 100 insertions, 2 deletions
diff --git a/include/asterisk/alaw.h b/include/asterisk/alaw.h index 44b3bad86..5f6c9a373 100644 --- a/include/asterisk/alaw.h +++ b/include/asterisk/alaw.h @@ -23,21 +23,69 @@ #ifndef _ASTERISK_ALAW_H #define _ASTERISK_ALAW_H +#define G711_FAST_AND_DIRTY 1 +/* #define G711_REDUCED_BRANCHING */ + /*! Init the ulaw conversion stuff */ /*! * To init the ulaw to slinear conversion stuff, this needs to be run. */ void ast_alaw_init(void); +#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 mulaw */ /*! - */ + */ +#ifdef G711_FAST_AND_DIRTY extern unsigned char __ast_lin2a[8192]; +#else +extern unsigned char __ast_lin2a[AST_ALAW_TAB_SIZE]; +#endif /*! help */ extern short __ast_alaw[256]; +#ifdef G711_FAST_AND_DIRTY #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 */ diff --git a/include/asterisk/ulaw.h b/include/asterisk/ulaw.h index d9ab0d178..2c7940f26 100644 --- a/include/asterisk/ulaw.h +++ b/include/asterisk/ulaw.h @@ -23,21 +23,71 @@ #ifndef _ASTERISK_ULAW_H #define _ASTERISK_ULAW_H +#define G711_FAST_AND_DIRTY 1 + +/* #define G711_REDUCED_BRANCHING */ + /*! 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 */ /*! */ +#ifdef G711_FAST_AND_DIRTY extern unsigned char __ast_lin2mu[16384]; +#else +extern unsigned char __ast_lin2mu[AST_ULAW_TAB_SIZE]; +#endif /*! help */ extern short __ast_mulaw[256]; +#ifdef G711_FAST_AND_DIRTY + #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 */ diff --git a/main/alaw.c b/main/alaw.c index 782419d9e..b94772ea6 100644 --- a/main/alaw.c +++ b/main/alaw.c @@ -71,7 +71,7 @@ static inline short int alaw2linear (unsigned char alaw) int seg; alaw ^= AMI_MASK; - i = ((alaw & 0x0F) << 4); + i = ((alaw & 0x0F) << 4) + 8 /* rounding error */; seg = (((int) alaw & 0x70) >> 4); if (seg) i = (i + 0x100) << (seg - 1); |