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
Questions: