/*---------------------------------------------------------------------------*\

	FILE....: mu-alaw.c
	AUTHOR..: David Rowe
	DATE....: 16/10/97
	AUTHOR..: Ben Kramer
	DATE....: 29/11/2005

	A/Mu-law compression functions.
	Adapted from library for use in new driver by Ben Kramer.


         Voicetronix Voice Processing Board (VPB) Software

         Copyright (C) 1999-2007 Voicetronix www.voicetronix.com.au

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
	MA  02110-1301  USA

\*---------------------------------------------------------------------------*/


/* A/Mu-law constants */

#define	LSIGN	0x8000		/* linear sign bit 15 = 1 if negative	   */
#define	AMUSIGN	0x80		/* a/mu-law sign bit 7 = 1 if negative	   */
#define	AMUMAX	0x1fff		/* max a/mu-law value in linear form	   */
#define	AMUMAG	0x7f		/* a/mu-law magnitude bits 		   */
#define	BIAS	33		/* converts seg end points to powers of 2  */
#define	LINEAR	0xf		/* masks of linear portion of magnitude	   */

#define MULAW_SCALE     2       /* scales linear to mulaw       */
#define ALAW_SCALE      3       /* scales linear to alaw        */


/*--------------------------------------------------------------------------*\

	FUNCTION.: mulaw_encode
	AUTHOR...: David Rowe
	DATE.....: 14/10/97
	AUTHOR...: Ben Kramer
	DATE.....: 29/11/2005

	Encodes a vector of linear samples to mu-law equivalents.  The linear
	samples are assumed to be in Q15 format.

	Reference: TI databook
		   "Theory, Alogorithms, and Implementations Vol 1", p171

	Mu-law format: psssqqqq

		       p is the sign
		       s is the segment
		       q if the quantisation bin number

	Adapted from library for use in new driver by Ben Kramer.

\*--------------------------------------------------------------------------*/

char mulaw_encode(short linear)
{
	short y,mag;
	char p,s,q,b;
	unsigned long  acc;
	char mulaw;

	acc = linear >> MULAW_SCALE;

	/* separate sign and bias */

	if (acc & LSIGN) {
		p = AMUSIGN;
		mag = -acc;
	}
	else {
		p = 0;
		mag = acc;
	}
	mag += BIAS;

	/* encode magnitude */
	if (mag > AMUMAX)
		y = p + AMUMAG;
	else {
		/* determine left most bit and therefore segment */
		b = 0;
		acc = mag >> 1;
		while(acc) {
			b++;
			acc >>= 1;
		}
		s = b - 5;

		/* extract quantisation bin */

		q = mag >> (b-4);
		q &= LINEAR;
		y = p + (s<<4) + q;
	}

	mulaw = ~y & 0xff;
	return mulaw;
}

/*--------------------------------------------------------------------------*\

	FUNCTION.: mulaw_decode
	AUTHOR...: David Rowe
	DATE.....: 14/10/97
	AUTHOR...: Ben Kramer
	DATE.....: 29/11/2005

	Decodes a vector of mu-law samples to linear equivalents.  The linear
	samples are normalised to Q15.

	Reference: TI databook
		   "Theory, Alogorithms, and Implementations Vol 1", p171

	Adapted from library for use in new driver by Ben Kramer.

\*--------------------------------------------------------------------------*/

short mulaw_decode(char mulaw)
{
	unsigned long  acc,p,s,q;
	short linear;

	acc = ~mulaw & 0xff;

	/* extract sign */
	if (acc & AMUSIGN)
		p = LSIGN;
	else
		p = 0;
	acc &= AMUMAG;

	/* extract q and s */
	q = acc & 0xf;
	s = acc >> 4;

	/* remove bias and form linear sample */
	acc = 2*q+BIAS;
	acc <<= s;
	acc -= BIAS;
	acc <<= MULAW_SCALE;
	if (p)
		linear = -acc;
	else
		linear = acc;

	return linear;
}


/*--------------------------------------------------------------------------*\

	AUTHOR...: Ben Kramer
	DATE.....: 29/11/2005

	Encodes a vector of linear samples to A-law equivalents.  The linear
	samples are assumed to be in Q15 format.

	Reference: TI databook
		   "Theory, Alogorithms, and Implementations Vol 1", p171

	A-law format: psssqqqq

		       p is the sign
		       s is the segment
		       q if the quantisation bin number

	Taken from the vpbhp driver.

\*--------------------------------------------------------------------------*/

char alaw_encode(short sample)
{
	unsigned short y,mag;
	unsigned short p,s,q,b;
	unsigned long  acc;
	short alawbyte;
	acc = (sample >> 3) & 0xffff;

	/* separate sign */
	if (acc & 0x8000) {
		p = 0x80;
		mag = -(short)acc;
	}
	else {
		p = 0;
		mag = (short)acc;
	}

	/* encode magnitude */
	if (mag > 0x0fff) 
	{
		y = p + 0x7f;
	}
	else {
		/* determine left most bit and therefore segment */
		b = 0;
		acc = mag >> 1;
		while(acc) {
			b++;
			acc >>= 1;
		}

		if (b > 4) {
			s = b - 4;
			q = mag >> (b-4);
			q &= 0xf;
		}
		else {
			s = 0;
			q = mag >> 1;
		}

		y = p + (s<<4) + q;
	}

	alawbyte= y^0x55;               /* even bit inversion */
	return((char)alawbyte);
}

/*--------------------------------------------------------------------------*\

	FUNCTION.: alaw_decode
	AUTHOR...: David Rowe
	DATE.....: 14/10/97
	AUTHOR...: Ben Kramer
	DATE.....: 29/11/2005

	Decodes a vector of A-law samples to linear equivalents.  The linear
	samples are in Q15 format.

	Reference: TI databook
		   "Theory, Alogorithms, and Implementations Vol 1", p171

	Adapted from library for use in new driver by Ben Kramer.

\*--------------------------------------------------------------------------*/

short alaw_decode(char alaw)
{
	unsigned long  acc,p,s,q;
	short linear;

	/* even bit inversion */
	acc = alaw ^ 0x55;

	/* extract sign */
	if (acc & AMUSIGN)
		p = LSIGN;
	else
		p = 0;
	acc &= AMUMAG;

	/* extract q and s */
	q = acc & 0xf;
	s = acc >> 4;

	/* form linear sample */
	if (s != 0) {
		acc = 2*q+BIAS;
		acc <<= (s-1);
	}
	else
		acc = 2*q+1;

	acc <<= ALAW_SCALE;
	if (p)
		linear = -(short)acc;
	else
		linear = (short)acc;

	return linear;
}

