From Scott Dattalo
http://www-svr.eng.cam.ac.uk/comp.speech/Section2/Q2.7.html
http://www-s.ti.com/sc/psheets/spra267/spra267.pdf
shows:
> > linear compressed > > 12 11 10 9 8 7 6 5 4 3 2 1 0 | 6 5 4 3 2 1 0 > > ---------------------------------------------------------- > > 0 0 0 0 0 0 0 1 Q3 Q2 Q1 Q0 x 0 0 0 Q3 Q2 Q1 Q0 > > 0 0 0 0 0 0 1 Q3 Q2 Q1 Q0 x x 0 0 1 Q3 Q2 Q1 Q0 > > 0 0 0 0 0 1 Q3 Q2 Q1 Q0 x x x 0 1 0 Q3 Q2 Q1 Q0 > > 0 0 0 0 1 Q3 Q2 Q1 Q0 x x x x 0 1 1 Q3 Q2 Q1 Q0 > > 0 0 0 1 Q3 Q2 Q1 Q0 x x x x x 1 0 0 Q3 Q2 Q1 Q0 > > 0 0 1 Q3 Q2 Q1 Q0 x x x x x x 1 0 1 Q3 Q2 Q1 Q0 > > 0 1 Q3 Q2 Q1 Q0 x x x x x x x 1 1 0 Q3 Q2 Q1 Q0 > > 1 Q3 Q2 Q1 Q0 x x x x x x x x 1 1 1 Q3 Q2 Q1 Q0
Now, A law has alternate bit inversion, and this only seems to have 7 bits compressed. Just remember that in the compressed for each bit is equal to 3dB up to 0dBmO.
Another search yielded a C solution:
http://www-svr.eng.cam.ac.uk/comp.speech/Section2/Q2.7.html
The portion of interest:
/*
** This routine converts from ulaw to 16 bit linear.
**
** Craig Reese: IDA/Supercomputing Research Center
** 29 September 1989
**
** References:
** 1) CCITT Recommendation G.711 (very difficult to follow)
** 2) MIL-STD-188-113,"Interoperability and Performance Standards
** for Analog-to_Digital Conversion Techniques,"
** 17 February 1987
**
** Input: 8 bit ulaw sample
** Output: signed 16 bit linear sample
*/
int
ulaw2linear(ulawbyte)
unsigned char ulawbyte;
{
static int exp_lut[8] = {0,132,396,924,1980,4092,8316,16764};
int sign, exponent, mantissa, sample;
ulawbyte = ~ulawbyte;
sign = (ulawbyte & 0x80);
exponent = (ulawbyte >> 4) & 0x07;
mantissa = ulawbyte & 0x0F;
sample = exp_lut[exponent] + (mantissa << (exponent + 3));
if (sign != 0) sample = -sample;
return(sample);
}
This is ulaw and not A-law.
...
The array exp_lut[8] can be expressed:
exp_lut[i] = 132 *( (2^i) - 1)
You could use a look up table (like in the C code) or you could calculate it. But since there are only 8 cases, I think a table approach is fastest
; ulawbyte contains the u-law encoded byte we wish to convert to it's ; linear form. ; ulaw2linear: mov W, <>ulawbyte and W, #$07 ; Get the exponent add PC, W jmp ulaw_exp0 jmp ulaw_exp1 jmp ulaw_exp2 jmp ulaw_exp3 jmp ulaw_exp4 jmp ulaw_exp5 jmp ulaw_exp6 ulaw_exp7 mov W, <<ulawbyte and W, #$1e mov ulaw_linhi, W add ulaw_linhi, W mov W, #LOW(127*132) mov ulaw_linlo, W mov W, #HIGH(127*132) add ulaw_linhi, W jmp ulaw_sign ulaw_exp6 mov W, <<ulawbyte and W, #$1e mov ulaw_linhi, W mov W, #LOW(63*132) mov ulaw_linlo, W mov W, #HIGH(63*132) add ulaw_linhi, W jmp ulaw_sign ulaw_exp5 mov W, ulawbyte and W, #$0f mov ulaw_linhi, W mov W, #LOW(31*132) mov ulaw_linlo, W mov W, #HIGH(31*132) add ulaw_linhi, W jmp ulaw_sign ulaw_exp4 mov W, >>ulawbyte and W, #$07 mov ulaw_linhi, W mov W, >>known_zero mov ulaw_linlo, W mov W, #LOW(15*132) add ulaw_linlo, W mov W, #HIGH(15*132) snb C inc ulaw_linhi add ulaw_linhi, W jmp ulaw_sign ulaw_exp3 mov W, >>ulawbyte and W, #$07 mov ulaw_linhi, W mov W, >>known_zero mov ulaw_linlo, W rr ulaw_linhi rr ulaw_linlo mov W, #LOW(7*132) add ulaw_linlo, W mov W, #HIGH(7*132) snb C inc ulaw_linhi add ulaw_linhi, W jmp ulaw_sign ulaw_exp2 mov W, <>ulawbyte and W, #$f0 mov ulaw_linlo, W add ulaw_linlo, W mov W, <<known_zero mov ulaw_linhi, W mov W, #LOW(3*132) add ulaw_linlo, W mov W, #HIGH(3*132) snb C inc ulaw_linhi add ulaw_linhi, W jmp ulaw_sign ulaw_exp0 mov W, <>ulawbyte mov ulaw_linlo, W mov W, >>ulaw_linlo and W, #$78 clr ulaw_linhi jmp ulaw_sign ulaw_exp1 mov W, <>ulawbyte and W, #$f0 mov ulaw_linlo, W clr ulaw_linhi mov W, #LOW(1*132) add ulaw_linlo, W mov W, #HIGH(1*132) snb C inc ulaw_linhi add ulaw_linhi, W ulaw_sign sb ulawbyte.7 ret not ulaw_linhi not ulaw_linlo inc ulaw_linhi incsz ulaw_linlo dec ulaw_linhi ret
Now, this is untested and unoptimized, but it's close to being right and as fast as possible. If you want a shorter routine that's somewhat slower, then a slight modification of my last post will work. It takes advantage of the fact that:
132 = 4 * 33
and
(2^n - 1) * X = (X << n) - X
If ulawbyte is formatted:
sxyzabcd s - sign xyz - exponent abcd - mantissa
Then this routine will convert it to the linear form
mov W, <<ulawbyte ;w = xyzabcd? carry = s
and W, #$1e ;w = 000abcd0
addlw 0x21 ;w = 001abcd1 carry=0
mov Hack, W
mov W, #$21 ;w = 001abcd1 carry=0
add W, Hack
mov ulaw_linlo, W
clr ulaw_linhi
snb ulawbyte.4
rl ulaw_linlo ;01abcd10
sb ulawbyte.5
jmp L1
;If bit 4 and bit 5 are set then
rl ulaw_linlo ; 1abcd100
rl ulaw_linlo ; abcd1000
rl ulaw_linhi ; 00000001
sb ulawbyte.6
jmp L2
swap ulaw_linhi
swap ulaw_linlo ;shift left four positions
mov W, ulaw_linlo
and W, #$0f
or ulaw_linhi, W
;;; xor ulaw_linlo, W ;probably unnecessary to clear lsbs
;since they are "don't cares"...
L2:
;; If the sign bit is set, then we need to compute
;; 33 - ulaw_linhi:ulaw_linhi
;; otherwise we need
;; ulaw_linhi:ulaw_linhi - 33
mov W, #-33
add ulaw_linlo, W
sb C
dec ulaw_linhi
sb ulawbyte.7
jmp L4
not ulaw_linhi
not ulaw_linlo
inc ulaw_linhi
incsz ulaw_linlo
dec ulaw_linhi
L4
rl lin_lo ;Final shift
rl lin_hi
ret