Newsgroups: comp.dcom.modems
From: on@us.oracle.com (On G. Paradise)
Subject: Re: zyxel adpcm to binary data?
Keywords: adpcm-2 adpcm-3 zyxel voice mu-law
Organization: Oracle Corp., Redwood Shores CA
Date: Wed, 27 Jan 1993 08:05:30 GMT
X-Disclaimer: This message was written by an unauthenticated user
              at Oracle Corporation.  The opinions expressed are those
              of the user and not necessarily those of Oracle.

Wolfgang S. Rupprecht "wolfgang@wsrcc.com" writes:

>Does anyone know how to convert to/from zyxel adpcm-2 or adpcm-3 and
>straight binary data?  I'd like to play/record stuff on the Sun and
>then ship it off to the modem.
...

/*
 * Convert ZyXEL 2-bit, 9600 samples/second ADPCM
 * to 8000 samples/second mu-law suitable for Sun4 /dev/audio.
 */
#include <stdio.h>
#define ETX	03
#define DLE	020
#define I	5	/* 48000 / 9600 */
#define O	6	/* 48000 / 8000 */

static int buf[I * O];
static int *ip = buf;

/*
 * This is not a textbook approach to interpolation,
 * but multiplication is slow on most SPARCs.
 */
ipol(v)
{
	register i;
	register int *op;

	for (i = I; i; i--)
		*ip++ = v;

	if (ip < buf + I * O)
		return;

	ip = buf;
	for (op = buf; op < buf + I * O; ) {
		v = -*op++;	/* hack -- treble boost */
		for (i = O - 2; i; i--)
			v += *op++;
		v -= *op++;
		(void)putchar(st_linear_to_ulaw(v));
	}
}

/*
 * Convert till EOF or ^P^C
 */
conv(fp)
register FILE *fp;
{
	register c, i, val = 0;
	register double delta = 5;

	while ((c = getc(fp)) != EOF) {
		if (c == DLE)
			switch (c = getc(fp)) {
				case DLE:
					break;;
				case ETX:
					return(0);
				case EOF:
					return(c);
				default:
					continue;
			}

		for (i = 0200; i; i >>= 1) {
			register double d;
			register neg = c & i;	/* sign */

			if (c & (i >>= 1)) {	/* magnitude */
				d = delta * 48. / 32 + .5;
				delta *= 43. / 32;
			} else {
				d = delta * 16. / 32 + .5;
				delta *= 28. / 32;
			}
			if (delta < 5)
				delta = 5;
			ipol(val += neg ? -d : d);
		}
	}
	return(c);
}

main(argc, argv)
char **argv;
{
	int i, s = 0;
	FILE *fp;

	if (argc == 1)
		exit(conv(stdin));
	for (i = 1; i < argc; i++) {
		if (!(fp = fopen(argv[i], "r"))) {
			fprintf(stderr, *argv);
			perror(argv[i]);
			s--;
			continue;
		}
		s += conv(fp);
		(void)fclose(fp);
	}
	exit(s);
}

/*
** This routine converts from linear to ulaw.
**
** Craig Reese: IDA/Supercomputing Research Center
** Joe Campbell: Department of Defense
** 29 September 1989
**
** References:
** 1) CCITT Recommendation G.711  (very difficult to follow)
** 2) "A New Digital Technique for Implementation of Any
**     Continuous PCM Companding Law," Villeret, Michel,
**     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
**     1973, pg. 11.12-11.17
** 3) MIL-STD-188-113,"Interoperability and Performance Standards
**     for Analog-to_Digital Conversion Techniques,"
**     17 February 1987
**
** Input: Signed 16 bit linear sample
** Output: 8 bit ulaw sample
*/

#define ZEROTRAP    /* turn on the trap as per the MIL-STD */
#define BIAS 0x84   /* define the add-in bias for 16 bit samples */
#define CLIP 32635

st_linear_to_ulaw( sample )
int sample;
    {
    static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
                               4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
                               5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
                               5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
                               7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
    int sign, exponent, mantissa;
    unsigned char ulawbyte;

    /* Get the sample into sign-magnitude. */
    sign = (sample >> 8) & 0x80;		/* set aside the sign */
    if ( sign != 0 ) sample = -sample;		/* get magnitude */
    if ( sample > CLIP ) sample = CLIP;		/* clip the magnitude */

    /* Convert from 16 bit linear to ulaw. */
    sample = sample + BIAS;
    exponent = exp_lut[( sample >> 7 ) & 0xFF];
    mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
    ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
#ifdef ZEROTRAP
    if ( ulawbyte == 0 ) ulawbyte = 0x02;	/* optional CCITT trap */
#endif

    return ulawbyte;
    }

/*
** 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
st_ulaw_to_linear_slow( 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;
    }
Newsgroups: comp.dcom.modems