#include <stdio.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

typedef unsigned long ID;

#define FormID 'FORM' 		/* ckID for Form Chunk */
#define CommonID 'COMM' 		/* ckID for Common Chunk */
#define SoundDataID 'SSND' 	/* ckID for Sound Data Chunk */
#define formTypear 'AIFF'  	/* form type for AIFF */

int writelong (unsigned char outbyte);
int writeshort (unsigned char outbyte);

#pragma pack(1)
typedef struct { 
	ID 	ckID;
	unsigned long 	ckSize;
	ID 	formType;
} Chunk;

typedef struct {
	ID 	ckID;
	unsigned int 	ckSize;
	unsigned short 	numChannels;
	unsigned int numSampleFrames;
	unsigned short 	sampleSize;
	unsigned char sampleRate[10];
} CommonChunk;

typedef struct {
	ID 	ckID;
	unsigned int ckSize;
	unsigned int offset;
	unsigned int blockSize;
} SoundDataChunk;
#pragma pack()

/* sample rate */
long RATE = 8000;
char onebit = 63;
char zerobit = -63;
long HIFREQ = 2000;
long LOFREQ = 1000;

FILE *infile;
int outfile;
int i;
int j,k;
int length;

main (int argc, char **argv)
{

	Chunk chunk;
	CommonChunk commonchunk;
	SoundDataChunk sounddatachunk;
	int workadr;
	int bytecount;
	char string[256];
	char *out;
        unsigned char outbyte;
        
        
	if (argc != 3) {
		printf ("wrong number of arguments - %d provided - must be  two: input file, output file\n", argc-1);
		exit(-1);
	}
	infile=fopen(argv[1], "r");
	if (infile == NULL) {
		printf("error opening input file %s\n",argv[1]);
		exit(-1);
	}
	outfile=open(argv[2],O_CREAT | O_RDWR | O_TRUNC);
	if (outfile == -1) {
		printf("error opening output file %s\n",outfile);
		exit(-1);
	}
        
	/* write headers */
	chunk.ckID = FormID;
	chunk.ckSize = sizeof (chunk) - 8 + sizeof (commonchunk) + sizeof(sounddatachunk);
	chunk.formType = formTypear;
	i = write (outfile, &chunk, sizeof(chunk));

	commonchunk.ckID = CommonID;
	commonchunk.ckSize = sizeof(commonchunk) - 8;
	commonchunk.numChannels = 1;
	commonchunk.numSampleFrames = 0;
	commonchunk.sampleSize = 8;
	makeextended (commonchunk.sampleRate);

	i = write (outfile, &commonchunk, sizeof(commonchunk));

	sounddatachunk.ckID=SoundDataID;
	sounddatachunk.ckSize=sizeof(sounddatachunk) - 8;
	sounddatachunk.offset= 0;
	sounddatachunk.blockSize = 0;

	i = write (outfile, &sounddatachunk, sizeof(sounddatachunk));

        length = 0;

	printf ("write preamble");
        /* add a little pad of zeros (leader) */
        for (i = 0; i<8; i++) {
            outbyte=0x0;
            writelong(outbyte);
            writelong(outbyte);
        }
        
	/* write ten second preamble */

	for (i = 0; i<(RATE*10); i++) {
            if (i % (RATE/HIFREQ) == 0) {
                togglebit(&outbyte);
            }
            length++;
            write (outfile, &outbyte, 1);
	}
        
        /* finish preamble */
        while (i++ % (RATE/HIFREQ) != 0) {
            printf ("extra write %d",i);
            length++;
            write (outfile, &outbyte, 1);
	}

        /* write start bit */
        length +=2;
        togglebit(&outbyte);
        write (outfile, &outbyte, 1);
        write (outfile, &outbyte, 1);
        togglebit(&outbyte);
        writelong(outbyte);
        
        bytecount = 0;
	while (fscanf(infile,"%s ", string) != EOF) {
		for (i = 0; i<8; i++) {
			if (fscanf(infile,"%x",&j) != EOF) {
                                bytecount +=1;
                                printf(" %2.2x",j);
                                for (k = 0; k<8; k++) {
                                    togglebit(&outbyte);
                                    if (j & 0x80) {
                                        writelong(outbyte);
                                        togglebit(&outbyte);
                                        writelong(outbyte);
                                    } else {
                                        writeshort(outbyte);
                                        togglebit(&outbyte);
                                        writeshort(outbyte);
                                    }
                                    j=j<<1;
                                }
                        }
		}
        }	

/* finish last bit */
          togglebit(&outbyte);
          writelong(outbyte);
          
/* and add a little pad of zeros*/
        for (i = 0; i<8; i++) {
            outbyte=0x0;
            writelong(outbyte);
            writelong(outbyte);
        }
        
        printf ("\nlength: %d   bytecount: %d\n", length,bytecount);

        /* adjust lengths in headers  and rewrite */
        i = lseek (outfile, 0, SEEK_SET);
        printf ("lseek on file %d result %d/n",outfile, i);
        
        chunk.ckSize = sizeof (chunk) - 8 + sizeof (commonchunk) + sizeof(sounddatachunk) + length;
	i = write (outfile, &chunk, sizeof(chunk));

	commonchunk.numSampleFrames = length;
	i = write (outfile, &commonchunk, sizeof(commonchunk));

	sounddatachunk.ckSize=sizeof(sounddatachunk) - 8 + length;
	i = write (outfile, &sounddatachunk, sizeof(sounddatachunk));
        
        
	fclose(infile);
	close(outfile);
	printf ("\ndone\n");
}

togglebit (unsigned char *outbyte)
{
    if (*outbyte == onebit)
        *outbyte = zerobit;
    else
        *outbyte = onebit;
    return;
}

int writelong (unsigned char outbyte)
{
    int result;
    
    result = writeshort (outbyte);
    if (result != -1) {
        result = writeshort (outbyte);
    }
    return (result);
}

int writeshort (unsigned char outbyte)
{
    int result;
    length +=2;
    result  = write (outfile, &outbyte, 1);
    if (result != -1) {
        result = write (outfile, &outbyte, 1);
    }
    return (result);
}

makeextended (unsigned char *extended)
{
	extended[0]=0x40;
	extended[1]=0x0b;
	extended[2]=0xfa;
	extended[3]=0x00;
        extended[4]=0x00;
	extended[5]=0x00;
	extended[6]=0x00;
	extended[7]=0x00;
	extended[8]=0x00;
	extended[9]=0x00;

    return;
}
            
