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