/****************************************************************/
/*                                                              */
/*             Digitized Voice Programmer's Toolkit             */
/*             ------------------------------------             */
/*                                                              */
/*                  Simple Mu-Law File Encoder                  */
/*                                                              */
/*            Copyright (c) 1991, Farpoint Software             */
/*                                                              */
/****************************************************************/

/* This source file is not commented, but it is relatively easy */
/* to follow. The program reads a voice data file and writes an */
/* output file which has been compressed 2:1 by encoding each   */
/* sample (byte) into a nybble extracted from a lookup table.   */
/* The lookup table approximates a highly quantized version of  */
/* the standard Mu-Law curve widely used in telephone communi-  */
/* cations.                                                     */


#include <stdlib.h>
#include <fcntl.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <stdio.h>
#include <stddef.h>
#include <malloc.h>

/*-------------------------------------------------------------------*/

char logo[] = "Simple Mu-Law File Encoder\r\n"
 "Copyright(c) 1991, Farpoint Software\r\n";

unsigned char *s_buffer;
unsigned char *d_buffer;
int s_handle,d_handle;
long histogram[256];

int ctable[256] =
    {
// 33 slots
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
// 48 slots
	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
// 24 slots
	2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
// 12 slots
	3,3,3,3,3,3,3,3,3,3,3,3,
// 6 slots
	4,4,4,4,4,4,
// 3 slots
	5,5,5,
// 1 slots
	6,
// 1 slots
	7,
// 1 slots
	8,
// 1 slots
	9,
// 3 slots
	10,10,10,
// 6 slots
	11,11,11,11,11,11,
// 12 slots
	12,12,12,12,12,12,12,12,12,12,12,12,
// 24 slots
	13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
	13,13,13,13,
// 48 slots
	14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
	14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
	14,14,14,14,14,14,14,14,
// 33 slots
	15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
	15,15,15,15,15,15,15,15,15,15,15,15,15
    };

char errmsg1[] = "File read error.";
char errmsg2[] = "File write error.";
char errmsg3[] = "Unable to allocate memory.";

/*-------------------------------------------------------------------*/

void main(argc,argv)
int argc;
char **argv;

{
long s_len;
unsigned int blocks, oddblock;
unsigned int i, j;
int adjustment;
long histmax1, histmax2;
unsigned int index1, index2;
int tempvar;

puts(logo);

for ( i = 0 ; i < 256 ; i++ )
	histogram[i] = 0L;

if (argc != 3)
	{
	puts("\nCommand line:");
	puts(" ULAW <source file> <dest file>\n");
	exit(1);
	}

argv++;
s_handle = open(*argv,O_BINARY|O_RDONLY);
if (s_handle == -1)
	{
	puts(errmsg1);
	exit(1);
	}
argv++;
d_handle = open(*argv,O_BINARY|O_RDWR|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE);
if (d_handle == -1)
	{
	close(s_handle);
	puts(errmsg2);
	exit(1);
	}

s_buffer = (unsigned char *)malloc(32768U);
if (s_buffer == NULL)
	{
	puts(errmsg3);
	close(s_handle);
	close(d_handle);
	exit(1);
	}

d_buffer = (unsigned char *)malloc(16384U);
if (d_buffer == NULL)
	{
	puts(errmsg3);
	free(s_buffer);
	close(s_handle);
	close(d_handle);
	exit(1);
	}

s_len = filelength(s_handle);

blocks = (unsigned int)(s_len >> 15);
oddblock = (unsigned int)(s_len & 0x7FFF);

for ( i = 0 ; i < blocks ; i++ )
	{
	if ( read(s_handle, s_buffer, 32768U) != 32768U )
		{
		close(s_handle);
		close(d_handle);
		free(s_buffer);
		free(d_buffer);
		puts(errmsg1);
		exit(1);
		}
	for ( j = 0 ; j < 32768U ; j++ )
		histogram[s_buffer[j]]++;
	}
if ( oddblock )
	{
	if ( (unsigned int)read(s_handle, s_buffer, oddblock) != oddblock )
		{
		close(s_handle);
		close(d_handle);
		free(s_buffer);
		free(d_buffer);
		puts(errmsg1);
		exit(1);
		}
	for ( j = 0 ; j < oddblock ; j++ )
		histogram[s_buffer[j]]++;
	}

lseek(s_handle, 0L, SEEK_SET);

histmax1 = 0L;
histmax2 = 0L;
index1 = 0;
index2 = 0;
for ( i = 0 ; i < 256 ; i++ )
	{
	if ( histmax1 < histogram[i] )
		{
		histmax1 = histogram[i];
		index1 = i;
		}
	}
for ( i = 0 ; i < 256 ; i++ )
	{
	if ( i != index1 )
		{
		if ( histmax2 < histogram[i] )
			{
			histmax2 = histogram[i];
			index2 = i;
			}
		}
	}
if ( abs(index1 - index2) > 8 )
	adjustment = 0;
else
	adjustment = 0x7F - ((int)(index1 + index2) / 2);

for ( i = 0 ; i < blocks ; i++ )
	{
	if ( read(s_handle, s_buffer, 32768U) != 32768U )
		{
		close(s_handle);
		close(d_handle);
		free(s_buffer);
		free(d_buffer);
		puts(errmsg1);
		exit(1);
		}
	for ( j = 0 ; j < 32768U ; j++ )
		{
		tempvar = s_buffer[j] + adjustment;
		if ( tempvar < 0 )
			tempvar = 0;
		else if ( tempvar > 255 )
			tempvar = 255;
		s_buffer[j] = (unsigned char)tempvar;
		}
	for ( j = 0 ; j < 16384 ; j++ )
		d_buffer[j] = (unsigned char)(ctable[s_buffer[2*j]] |
			(ctable[s_buffer[2*j+1]] << 4) );
	if ( write(d_handle, d_buffer, 16384U) != 16384U )
		{
		close(s_handle);
		close(d_handle);
		free(s_buffer);
		free(d_buffer);
		puts(errmsg2);
		exit(1);
		}
	}
if ( oddblock )
	{
	if ( (unsigned int)read(s_handle, s_buffer, oddblock) != oddblock )
		{
		close(s_handle);
		close(d_handle);
		free(s_buffer);
		free(d_buffer);
		puts(errmsg1);
		exit(1);
		}
	for ( j = 0 ; j < oddblock ; j++ )
		{
		tempvar = s_buffer[j] + adjustment;
		if ( tempvar < 0 )
			tempvar = 0;
		else if ( tempvar > 255 )
			tempvar = 255;
		s_buffer[j] = (unsigned char)tempvar;
		}
	for ( j = 0 ; j < oddblock / 2 ; j++ )
		d_buffer[j] = (unsigned char)(ctable[s_buffer[2*j]] |
			(ctable[s_buffer[2*j+1]] << 4) );
	if ( (unsigned int)write(d_handle, d_buffer, oddblock / 2) != oddblock / 2 )
		{
		close(s_handle);
		close(d_handle);
		free(s_buffer);
		free(d_buffer);
		puts(errmsg2);
		exit(1);
		}
	}

puts("File compression complete.");
close(s_handle);
close(d_handle);
free(s_buffer);
free(d_buffer);
exit(0);
}
