/* January 10, 1995
   The first version of the infocom sound file format converter
   is completed.

   For complete information on the sound format please see the
   included file infocom.info

   Caveat: The header byte swapping routines have not been
           tested and the Amiga format has not been tested.

*/


/*
 * July 5, 1991
 * Copyright 1991 Lance Norskog And Sundry Contributors
 * This source code is freely redistributable and may be used for
 * any purpose.  This copyright notice must be maintained. 
 * Lance Norskog And Sundry Contributors are not responsible for 
 * the consequences of using this software.
 */

/*
 * Sound Tools Infocom format driver.  (Macintosh Format Version)
                                
    Amiga version has signed character data;
 */

#include "st.h"

/* Private data for Infocom file */
#define HEADERSIZE 24
#define INFOCOM_DEBUG 0
#define INFOCOM_MAXLENGTH 65536

typedef struct skelstuff {
	unsigned short Header;
	unsigned char RepeatsToPlay;
	unsigned char BaseNote;
	unsigned short SampleFreq;
	unsigned short Unused;
	unsigned short DataLength;
} *Infocom_t;

void EndianSwap(int buflen, char * buf);

/*
 * Do anything required before you start reading samples.
 * Read file header. 
 *	Find out sampling rate, 
 *	size and style of samples, 
 *	mono/stereo/quad.
 */
Infocomstartread(ft) 
ft_t ft;
{
	int sbseek;
	Infocom_t inf = (Infocom_t) ft->priv;
	int littlendian = 0;
	char *endptr;

	endptr = (char *) &littlendian;
	*endptr = 1;
	if (littlendian == 1)
		ft->swap = 1;

	/* If you need to seek around the input file. */
	if (! ft->seekable)
		fail("Infocom input file must be a file, not a pipe");

	/* Read Header */

	inf->Header = rshort(ft);
	fread(&inf->RepeatsToPlay,1, sizeof(inf->RepeatsToPlay),ft->fp );
	fread(&inf->BaseNote,1, sizeof(inf->BaseNote),ft->fp);
	inf->SampleFreq = rshort(ft);
	inf->Unused = rshort(ft);
	inf->DataLength = rshort(ft);

	if(inf->Header == 22) 
	  fail("Input file has no sound!");

	/* Debugging Info for posterity */
	if(INFOCOM_DEBUG) {
	  fprintf(stderr,"Sizeof Header = %i\t\tHeader = %i\n", sizeof(inf->Header), inf->Header);
	  
	  fprintf(stderr,"Sizeof RepeatsToPlay = %i\tRepeatsToPlay = %i\n", 
		  sizeof(inf->RepeatsToPlay), inf->RepeatsToPlay);
	  
	  fprintf(stderr,"Sizeof BaseNote = %i\t\tBaseNote = %i\n", 
		  sizeof(inf->BaseNote), inf->BaseNote);
	  
	  fprintf(stderr,"Sizeof SampleFreq = %i\t\tSampleFreq = %i\n", 
		  sizeof(inf->SampleFreq), inf->SampleFreq);
	  
	  fprintf(stderr,"Sizeof Unused = %i\t\tUnused = %i\n", 
		  sizeof(inf->Unused), inf->Unused);
	  
	  
	  
	  fprintf(stderr,"Sizeof DataLength = %i\t\tDataLength = %i\n", 
		  sizeof(inf->DataLength), inf->DataLength);
	}
	/*
	 * If your format specifies or your file header contains
	 * any of the following information. 
	 */

	ft->info.rate = inf->SampleFreq;
	ft->info.size = BYTE;
	ft->info.style = UNSIGNED;
	ft->info.channels = 1;
}

/*
 * Read up to len samples from file.
 * Convert to signed longs.
 * Place in buf[].
 * Return number of samples read.
 */

Infocomread(ft, buf, len) 
ft_t ft;
long *buf, len;
{

	Infocom_t inf = (Infocom_t) ft->priv;
	int abs;
	float amp;
	int done = 0;
	
	char c;
	unsigned char uc;
	short s;
	unsigned short us;
	long l;
	unsigned long ul;
	float f;
	double d;

	if(INFOCOM_DEBUG) fprintf(stderr,"len = %i\n", len);

	for(; done < len; done++) {
	  if ( (l = getc(ft->fp)) == EOF) {
	    break;
	  }
	  /* Convert to Signed number */
	  l ^= 0x80;  /* assumes longs are 32 bits */
	  *buf++ = LEFT(l, 24);
	}
	if(INFOCOM_DEBUG) fprintf(stderr,"Able to read %i bytes of data.\n", done);
	return done;
}

InfocomreadAmiga(ft, buf, len) 
ft_t ft;
long *buf, len;
{

	Infocom_t inf = (Infocom_t) ft->priv;
	int abs;
	float amp;
	int done = 0;
	
	char c;
	unsigned char uc;
	short s;
	unsigned short us;
	long l;
	unsigned long ul;
	float f;
	double d;

	if(INFOCOM_DEBUG) fprintf(stderr,"len = %i\n", len);

	for(; done < len; done++) {
	  if ( (l = getc(ft->fp)) == EOF) {
	    break;
	  }
	  *buf++ = LEFT(l, 24);
	}
	if(INFOCOM_DEBUG) fprintf(stderr,"Able to read %i bytes of data.\n", done);
	return done;
}

/*
 * Do anything required when you stop reading samples.  
 * Don't close input file! 
 */
Infocomstopread(ft) 
ft_t ft;
{
}

Infocomstartwrite(ft) 
ft_t ft;
{

	Infocom_t inf = (Infocom_t) ft->priv;
	int littlendian = 0;
	char *endptr;

	endptr = (char *) &littlendian;
	*endptr = 1;
	if (littlendian == 1)
		ft->swap = 1;

	/* If you have to seek around the output file */
	if (! ft->seekable)
		fail("Output Infocom file must be a file, not a pipe");

	/* If your format specifies any of the following info. */
	ft->info.size = BYTE;
	ft->info.style = UNSIGNED;
	ft->info.channels = 1;
	/* Write file header, if any */

	inf->Header = 22;
	inf->RepeatsToPlay = 1;
	inf->BaseNote = 60;
	inf->SampleFreq = ft->info.rate;
	inf->Unused = 0;
	inf->DataLength = 0;
	
	if(INFOCOM_DEBUG) {
	  fprintf(stderr,"Sizeof Header = %i\t\tHeader = %i\n", sizeof(inf->Header), inf->Header);
	  
	  fprintf(stderr,"Sizeof RepeatsToPlay = %i\tRepeatsToPlay = %i\n", 
		  sizeof(inf->RepeatsToPlay), inf->RepeatsToPlay);
	  
	  fprintf(stderr,"Sizeof BaseNote = %i\t\tBaseNote = %i\n", 
		  sizeof(inf->BaseNote), inf->BaseNote);
	  
	  fprintf(stderr,"Sizeof SampleFreq = %i\t\tSampleFreq = %i\n", 
		  sizeof(inf->SampleFreq), inf->SampleFreq);
	  
	  fprintf(stderr,"Sizeof Unused = %i\t\tUnused = %i\n", 
		  sizeof(inf->Unused), inf->Unused);
	  
	  
	  
	  fprintf(stderr,"Sizeof DataLength = %i\t\tDataLength = %i\n", 
		  sizeof(inf->DataLength), inf->DataLength);
	  if(ft->swap) fprintf(stderr,"Byte Swapping Header\n");
	}	  

	/* Write header */
	wshort(ft, inf->Header);

	fwrite(&inf->RepeatsToPlay,1, sizeof(inf->RepeatsToPlay),ft->fp );
	fwrite(&inf->BaseNote,1, sizeof(inf->BaseNote),ft->fp);

	wshort(ft,inf->SampleFreq);
	wshort(ft,inf->Unused);
	wshort(ft,inf->DataLength );

	/* Write comment field, if any */
}

Infocomwrite(ft, buf, len) 
ft_t ft;
long *buf, len;
{
	Infocom_t inf = (Infocom_t) ft->priv;
	register int datum;
	int abs;
	int done = 0;

	if(inf->DataLength + len > INFOCOM_MAXLENGTH) {
	  len = INFOCOM_MAXLENGTH - inf->DataLength;
	  fprintf(stderr,"File Conversion will clip file to %i samples.\n",
		  INFOCOM_MAXLENGTH);
	}

	inf->DataLength += len;
	inf->Header += len;
	while(len--){
		putc((*buf++ >> 24) ^ 0x80, ft->fp);
	      }
}

InfocomwriteAmiga(ft, buf, len) 
ft_t ft;
long *buf, len;
{
	Infocom_t inf = (Infocom_t) ft->priv;
	register int datum;
	int abs;
	int done = 0;

	if(inf->DataLength + len > INFOCOM_MAXLENGTH) {
	  len = INFOCOM_MAXLENGTH - inf->DataLength;
	  fprintf(stderr,"File Conversion will clip file to %i samples.\n",
		  INFOCOM_MAXLENGTH);
	}

	inf->DataLength += len;
	inf->Header += len;
	while(len--){
		putc((*buf++ >> 24), ft->fp);
	      }
}

Infocomstopwrite(ft) 
ft_t ft;
{
  Infocom_t inf = (Infocom_t) ft->priv;


  /* All samples are already written out. */
  /* If file header needs fixing up, for example it needs the */
  /* the number of samples in a field, seek back and write them here. */
  /* Update header in file */

  fseek(ft->fp, 0, SEEK_SET);

  /* Rewrite header */
  wshort(ft, inf->Header);

  fwrite(&inf->RepeatsToPlay,1, sizeof(inf->RepeatsToPlay),ft->fp );
  fwrite(&inf->BaseNote,1, sizeof(inf->BaseNote),ft->fp);

  wshort(ft,inf->SampleFreq);
  wshort(ft,inf->Unused);
  wshort(ft,inf->DataLength );

}

