/*
===========================================================================

Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. 

This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (RTCW MP Source Code).  

RTCW MP Source Code 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 3 of the License, or
(at your option) any later version.

RTCW MP Source Code 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 RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

===========================================================================
*/


/*****************************************************************************
 * name:		snd_wavelet.c
 *
 * desc:
 *
 *
 *****************************************************************************/

#include "snd_local.h"

long myftol( float f );

#define C0 0.4829629131445341
#define C1 0.8365163037378079
#define C2 0.2241438680420134
#define C3 -0.1294095225512604

void daub4( float b[], unsigned long n, int isign ) {
	float wksp[4097];
	float   *a = b - 1;                     // numerical recipies so a[1] = b[0]

	unsigned long nh,nh1,i,j;

	if ( n < 4 ) {
		return;
	}

	nh1 = ( nh = n >> 1 ) + 1;
	if ( isign >= 0 ) {
		for ( i = 1, j = 1; j <= n - 3; j += 2, i++ ) {
			wksp[i]    = C0 * a[j] + C1 * a[j + 1] + C2 * a[j + 2] + C3 * a[j + 3];
			wksp[i + nh] = C3 * a[j] - C2 * a[j + 1] + C1 * a[j + 2] - C0 * a[j + 3];
		}
		wksp[i   ] = C0 * a[n - 1] + C1 * a[n] + C2 * a[1] + C3 * a[2];
		wksp[i + nh] = C3 * a[n - 1] - C2 * a[n] + C1 * a[1] - C0 * a[2];
	} else {
		wksp[1] = C2 * a[nh] + C1 * a[n] + C0 * a[1] + C3 * a[nh1];
		wksp[2] = C3 * a[nh] - C0 * a[n] + C1 * a[1] - C2 * a[nh1];
		for ( i = 1, j = 3; i < nh; i++ ) {
			wksp[j++] = C2 * a[i] + C1 * a[i + nh] + C0 * a[i + 1] + C3 * a[i + nh1];
			wksp[j++] = C3 * a[i] - C0 * a[i + nh] + C1 * a[i + 1] - C2 * a[i + nh1];
		}
	}
	for ( i = 1; i <= n; i++ ) {
		a[i] = wksp[i];
	}
}

void wt1( float a[], unsigned long n, int isign ) {
	unsigned long nn;
	int inverseStartLength = n / 4;
	if ( n < inverseStartLength ) {
		return;
	}
	if ( isign >= 0 ) {
		for ( nn = n; nn >= inverseStartLength; nn >>= 1 ) daub4( a,nn,isign );
	} else {
		for ( nn = inverseStartLength; nn <= n; nn <<= 1 ) daub4( a,nn,isign );
	}
}

/* The number of bits required by each value */
static unsigned char numBits[] = {
	0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,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,
	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,
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
};

byte MuLawEncode( short s ) {
	unsigned long adjusted;
	byte sign, exponent, mantissa;

	sign = ( s < 0 ) ? 0 : 0x80;

	if ( s < 0 ) {
		s = -s;
	}
	adjusted = (long)s << ( 16 - sizeof( short ) * 8 );
	adjusted += 128L + 4L;
	if ( adjusted > 32767 ) {
		adjusted = 32767;
	}
	exponent = numBits[( adjusted >> 7 ) & 0xff] - 1;
	mantissa = ( adjusted >> ( exponent + 3 ) ) & 0xf;
	return ~( sign | ( exponent << 4 ) | mantissa );
}

short MuLawDecode( byte uLaw ) {
	signed long adjusted;
	byte exponent, mantissa;

	uLaw = ~uLaw;
	exponent = ( uLaw >> 4 ) & 0x7;
	mantissa = ( uLaw & 0xf ) + 16;
	adjusted = ( mantissa << ( exponent + 3 ) ) - 128 - 4;

	return ( uLaw & 0x80 ) ? adjusted : -adjusted;
}

short mulawToShort[256];
static qboolean madeTable = qfalse;

static int NXStreamCount;

void NXPutc( NXStream *stream, char out ) {
	stream[NXStreamCount++] = out;
}


void encodeWavelet( sfx_t *sfx, short *packets ) {
	float wksp[4097], temp;
	int i, samples, size;
	sndBuffer       *newchunk, *chunk;
	byte            *out;

	if ( !madeTable ) {
		for ( i = 0; i < 256; i++ ) {
			mulawToShort[i] = (float)MuLawDecode( (byte)i );
		}
		madeTable = qtrue;
	}
	chunk = NULL;

	samples = sfx->soundLength;
	while ( samples > 0 ) {
		size = samples;
		if ( size > ( SND_CHUNK_SIZE * 2 ) ) {
			size = ( SND_CHUNK_SIZE * 2 );
		}

		if ( size < 4 ) {
			size = 4;
		}

		newchunk = SND_malloc();
		if ( sfx->soundData == NULL ) {
			sfx->soundData = newchunk;
		} else {
			chunk->next = newchunk;
		}
		chunk = newchunk;
		for ( i = 0; i < size; i++ ) {
			wksp[i] = *packets;
			packets++;
		}
		wt1( wksp, size, 1 );
		out = (byte *)chunk->sndChunk;

		for ( i = 0; i < size; i++ ) {
			temp = wksp[i];
			if ( temp > 32767 ) {
				temp = 32767;
			} else if ( temp < -32768 )     {
				temp = -32768;
			}
			out[i] = MuLawEncode( (short)temp );
		}

		chunk->size = size;
		samples -= size;
	}
}

void decodeWavelet( sndBuffer *chunk, short *to ) {
	float wksp[4097];
	int i;
	byte            *out;

	int size = chunk->size;

	out = (byte *)chunk->sndChunk;
	for ( i = 0; i < size; i++ ) {
		wksp[i] = mulawToShort[out[i]];
	}

	wt1( wksp, size, -1 );

	if ( !to ) {
		return;
	}

	for ( i = 0; i < size; i++ ) {
		to[i] = wksp[i];
	}
}


void encodeMuLaw( sfx_t *sfx, short *packets ) {
	int i, samples, size, grade, poop;
	sndBuffer       *newchunk, *chunk;
	byte            *out;

	if ( !madeTable ) {
		for ( i = 0; i < 256; i++ ) {
			mulawToShort[i] = (float)MuLawDecode( (byte)i );
		}
		madeTable = qtrue;
	}

	chunk = NULL;
	samples = sfx->soundLength;
	grade = 0;

	while ( samples > 0 ) {
		size = samples;
		if ( size > ( SND_CHUNK_SIZE * 2 ) ) {
			size = ( SND_CHUNK_SIZE * 2 );
		}

		newchunk = SND_malloc();
		if ( sfx->soundData == NULL ) {
			sfx->soundData = newchunk;
		} else {
			chunk->next = newchunk;
		}
		chunk = newchunk;
		out = (byte *)chunk->sndChunk;
		for ( i = 0; i < size; i++ ) {
			poop = packets[0] + grade;
			if ( poop > 32767 ) {
				poop = 32767;
			} else if ( poop < -32768 ) {
				poop = -32768;
			}
			out[i] = MuLawEncode( (short)poop );
			grade = poop - mulawToShort[out[i]];
			packets++;
		}
		chunk->size = size;
		samples -= size;
	}
}

void decodeMuLaw( sndBuffer *chunk, short *to ) {
	int i;
	byte            *out;

	int size = chunk->size;

	out = (byte *)chunk->sndChunk;
	for ( i = 0; i < size; i++ ) {
		to[i] = mulawToShort[out[i]];
	}
}


