On Mon, 3 Apr 2000, Plunkett, Dennis wrote: > > -----Original Message----- > > From: Scott Dattalo [SMTP:scott@DATTALO.COM] > > Sent: Sunday, 2 April 2000 8:00 > > To: PICLIST@MITVMA.MIT.EDU > > Subject: Re: A-law or mu-law to linear conversion. > > > > On Fri, 31 Mar 2000, Terry wrote: > > > > > Anyone know of a method to convert 8 bit A or mu-law to 16 bit linear > > fast > > > and compact using a 16c72? > > > Is a lookup table the only way? > > > > I don't know the specifics on mu-law other than it involves logarithmic > > compression. A quick search on the web led me to: > > > > http://www-s.ti.com/sc/psheets/spra267/spra267.pdf > > > > From which I copied this table: > > > > 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 > > > > Is this correct? > > > I don't think so 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. It's always easier to say what isn't than what is. 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. Now, the pic code I posted yesterday only implements a very small portion. But that's easy to fix. A couple of observations first: 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 There, that should be better. Scott