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: swapf ulawbyte,w andlw 0x07 ; Get the exponent addwf pcl,f goto ulaw_exp0 goto ulaw_exp1 goto ulaw_exp2 goto ulaw_exp3 goto ulaw_exp4 goto ulaw_exp5 goto ulaw_exp6 ulaw_exp7 rlf ulawbyte,w andlw 0x1e movwf ulaw_linhi addwf ulaw_linhi,f movlw LOW(127*132) movwf ulaw_linlo movlw HIGH(127*132) addwf ulaw_linhi,f goto ulaw_sign ulaw_exp6 rlf ulawbyte,w andlw 0x1e movwf ulaw_linhi movlw LOW(63*132) movwf ulaw_linlo movlw HIGH(63*132) addwf ulaw_linhi,f goto ulaw_sign ulaw_exp5 movf ulawbyte,w andlw 0x0f movwf ulaw_linhi movlw LOW(31*132) movwf ulaw_linlo movlw HIGH(31*132) addwf ulaw_linhi,f goto ulaw_sign ulaw_exp4 rrf ulawbyte,w andlw 0x07 movwf ulaw_linhi rrf known_zero,w movwf ulaw_linlo movlw LOW(15*132) addwf ulaw_linlo movlw HIGH(15*132) skpnc incf ulaw_linhi,f addwf ulaw_linhi,f goto ulaw_sign ulaw_exp3 rrf ulawbyte,w andlw 0x07 movwf ulaw_linhi rrf known_zero,w movwf ulaw_linlo rrf ulaw_linhi,f rrf ulaw_linlo,f movlw LOW(7*132) addwf ulaw_linlo,f movlw HIGH(7*132) skpnc incf ulaw_linhi,f addwf ulaw_linhi,f goto ulaw_sign ulaw_exp2 swapf ulawbyte,w andlw 0xf0 movwf ulaw_linlo addwf ulaw_linlo,f rlf known_zero,w movwf ulaw_linhi movlw LOW(3*132) addwf ulaw_linlo,f movlw HIGH(3*132) skpnc incf ulaw_linhi,f addwf ulaw_linhi,f goto ulaw_sign ulaw_exp0 swapf ulawbyte,w movwf ulaw_linlo rrf ulaw_linlo,w andlw 0x78 clrf ulaw_linhi goto ulaw_sign ulaw_exp1 swapf ulawbyte,w andlw 0xf0 movwf ulaw_linlo clrf ulaw_linhi movlw LOW(1*132) addwf ulaw_linlo,f movlw HIGH(1*132) skpnc incf ulaw_linhi,f addwf ulaw_linhi,f ulaw_sign btfss ulawbyte,7 return comf ulaw_linhi,f comf ulaw_linlo,f incf ulaw_linhi,f incfsz ulaw_linlo,f decf ulaw_linhi,f return
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
rlf ulawbyte,w ;w = xyzabcd? carry = s andlw 0x1e ;w = 000abcd0 addlw 0x21 ;w = 001abcd1 carry=0 movwf ulaw_linlo clrf ulaw_linhi btfsc ulawbyte,4 rlf ulaw_linlo,f ;01abcd10 btfss ulawbyte,5 goto L1 ;If bit 4 and bit 5 are set then rlf ulaw_linlo,f ; 1abcd100 rlf ulaw_linlo,f ; abcd1000 rlf ulaw_linhi,f ; 00000001 btfss ulawbyte,6 goto L2 swapf ulaw_linhi,f swapf ulaw_linlo,f ;shift left four positions movf ulaw_linlo,w andlw 0x0f iorwf ulaw_linhi ;;; xorwf ulaw_linlo,f ;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 movlw -33 addwf ulaw_linlo,f skpc decf ulaw_linhi,f btfss ulawbyte,7 goto L4 comf ulaw_linhi,f comf ulaw_linlo,f incf ulaw_linhi,f incfsz ulaw_linlo,f decf ulaw_linhi,f L4 rlf lin_lo,f ;Final shift rlf lin_hi,f return