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