/* AudioTools.c                        */

#include <exec/types.h>
#include <exec/memory.h>
#include <stdio.h>
#include <libraries/dos.h>
#include <devices/audio.h>
#include "AudioTools.h"

#define OPEN_ERROR		0
#define READ_ERROR		1
#define DEVICE_ERROR	2
#define PORT_ERROR		3
#define IOA_ERROR		4
#define PLAY_ERROR		5
#define IFF_ERROR		6

struct IOAudio finish,s[4];
extern struct MsgPort *CreatePort();
UBYTE sunit=0x0f;

typedef LONG Fixed;

#define Unity 0x10000L
#define sCmpNone		0
#define sCmpFibDelta	1

typedef struct {
	ULONG	oneShotHiSamples,	/* # samples in the high octave 1-shot part */
			repeatHiSamples,	/* # samples in the high octave repeat part */
			samplesPerHiCycle;	/* # samples/cycle in high octave, else 0   */
	UWORD	samplesPerSec;		/* data sampling rate */
	UBYTE	ctOctave,			/* number of octaves of waveforms */
			sCompression;		/* data compression technique used */
	Fixed	volume;				/* playback volume from 0 to Unity */

	} Voice8Header;

UBYTE whichannel[] = {1,2,4,8};

ULONG SizeIFF(Filename)
char *Filename;		/* File to open */
/* returns size of sample or 0 if error. */
{
	FILE *fp;
	char *ckname = "    ";
	char dummy;
	Voice8Header Header;

	if (fp = fopen(Filename,"r"))
	{
		fread(ckname,4,1,fp);
		if (strcmp(ckname,"FORM")==0)
		{
			fread(ckname,4,1,fp);	/* not a mistake! */
			fread(ckname,4,1,fp);
			if (strcmp(ckname,"8SVX")==0)
			{
				get_to("VHDR",fp);
				fread(&dummy,sizeof(LONG),1,fp);
				fread((char *)&Header,sizeof(Header),1,fp);
				fclose(fp);
				return(Header.oneShotHiSamples+
					   Header.repeatHiSamples);
			}
			else
			{
				fclose(fp);
				return(0);		
			}
		}
		else
		{
			fclose(fp);
			return(0);		
		}
	}
	else
	{
		return(0);
	}
}

UWORD ReadIFF(Filename,IFFBuf0)
char *Filename;		/* File to read */
BYTE *IFFBuf0;			/* Buffer to read sample into */
/* returns the record rate */
{
	FILE *fp;
	char *ckname = "    ";
	char dummy;
	Voice8Header Header;

	if (fp = fopen(Filename,"r"))
	{
		fread(ckname,4,1,fp);
		if (strcmp(ckname,"FORM")==0)
		{
			fread(ckname,4,1,fp);	/* not a mistake! */
			fread(ckname,4,1,fp);
			if (strcmp(ckname,"8SVX")==0)
			{
				get_to("VHDR",fp);
				fread(&dummy,sizeof(LONG),1,fp);
				fread((char *)&Header,sizeof(Header),1,fp);
				get_to("BODY",fp);
				fread(&dummy,sizeof(LONG),1,fp);							
				fread(IFFBuf0,Header.oneShotHiSamples+
					  Header.repeatHiSamples,1,fp);
				fclose(fp);
				return(Header.samplesPerSec);
			}
			else
			{
				fclose(fp);
				return(IFF_ERROR);		
			}
		}
		else
		{
			fclose(fp);
			return(IFF_ERROR);		
		}
	}
	else
	{
		return(OPEN_ERROR);
	}
} 

/* this routine walks through the iff file looking for chunks */
get_to(ckname,fp)
char *ckname;
FILE *fp;
{
	char *ckcheck = "    ";
	int  skip,i;
   char dummy;

	while(!feof(fp))
	{
		fread(ckcheck,4,1,fp);
		if (strcmp(ckname,ckcheck)==0)
		{
			return(1);
		}
		fread((char *)&skip,sizeof(LONG),1,fp);
		for (i=0; i<skip; i++)
		{
			fread(&dummy,1,1,fp);
		}
	}
}


UWORD LoadSound(filename,buffer)			/* Read SoundFile */
char *filename,*buffer;
{
	FILE *fp;								/* File Pointer */
	ULONG len;								/* Data Length */
	UWORD rec_rate;							/* Record Rate (kHz) */

	/* Is it an IFF File? */
	if(len=SizeIFF(filename))
	{
		/* Yes, then read in IFF format */
      return(ReadIFF(filename,buffer));
      
	}
	else
	{
		/* No, then read in FutureSound format */

		/* Open file for reading */
		if((fp = fopen(filename,"r")) == 0)
		{
			return(OPEN_ERROR);
		}

		/* Read length of data */
		if(fread((char *)&len,sizeof(len),1,fp) == 0)
		{
			fclose(fp);
			return(READ_ERROR);
		}

		/* Read record rate */
		if(fread((char *)&rec_rate,sizeof(rec_rate),1,fp) == 0)
		{
			fclose(fp);
			return(READ_ERROR);
		}

		/* Read data into buffer */
		if(fread(buffer,len,1,fp) == 0)
		{
			fclose(fp);
			return(READ_ERROR);
		}

		/* Close file */
		fclose(fp);

		/* Return record rate if file was successfully read */
		/* Old FutureSound format saved in kHz              */
		if(rec_rate < 100)
		{
		  rec_rate *= 1000;
		}
      printf ("%d",rec_rate);
		return(rec_rate);
	}
}

ULONG GetSize(filename)
char *filename;
{
	FILE *fp;								/* File Pointer */
	ULONG len;								/* Data Length */

	/* Is it an IFF File? */
	if((len = SizeIFF(filename)) == 0)
	{
		/* No, then open for FutureSound format */
		if((fp = fopen(filename,"r")) == 0)
		{
			return((ULONG) OPEN_ERROR);
		}
		/* Read Data Length */
		if(fread((char *)&len,sizeof(len),1,fp) == 0)
		{
			fclose(fp);
			return((ULONG) READ_ERROR);
		}
		/* Close File */
		fclose(fp);
	}
	/* Return Data Length */
	return(len);
}


void LoadSample (fn,s)

char *fn;
Sample *s;
{
      s->repeat=1;
		s->volume=64;
		if(s->buflen = GetSize(fn))
		{
			/* Allocate Buffer */
			s->buffer=(BYTE *)AllocMem(s->buflen,MEMF_CHIP|MEMF_CLEAR);

			/* If Allocation successful ... */
			if(s->buffer)
			{
				/* Load Wave, return value is rec rate */
				s->period = LoadSound(fn,s->buffer);

				/* Load Failed */
				if(s->period == 0)
				{
					/* Free Sound Buffer */
					FreeMem(s->buffer,s->buflen);
					s->buffer = 0;
				}
				else
				/* Load Succeeded */
				{
		        s->period=3579545/s->period;
				}
			}
			else
			/* Allocation Failed */
			{
         }
		}
		else
		/* GetSize Failed */
		{
		}

}

void FreeSample (s)

Sample *s;

{
   if (s->buffer)
     {
      FreeMem (s->buffer,s->buflen);
      s->buffer=NULL;
      s->buflen=0;
     }
}


void setup(finish)
struct IOAudio *finish;
{
   if((finish->ioa_Request.io_Message.mn_ReplyPort=CreatePort("p0",0))==NULL)
     exit(FALSE);

   finish->ioa_Request.io_Message.mn_Node.ln_Pri=10;
   finish->ioa_Data=&sunit;
   finish->ioa_Length=(ULONG)sizeof(sunit);
   
   if((OpenDevice(AUDIONAME,0L,finish,0L))!=NULL)
   {  printf("Can't open Audio Device\n");
      exit (FALSE);
   }
   
   finish->ioa_Request.io_Flags=NULL; /* IOF_QUICK; */
   finish->ioa_Request.io_Command=ADCMD_ALLOCATE;
}

void grab_channel(snd,control,name)
struct IOAudio *snd,*control;
char *name;
{
   if ((snd->ioa_Request.io_Message.mn_ReplyPort=CreatePort(name,0))==NULL)
     *snd=*control;
}

void GrabAllChannels ()

{
   setup(&finish);
   
   s[0]=finish;
   s[0].ioa_Request.io_Unit=whichannel[0];
   
   s[1]=finish;
   s[1].ioa_Request.io_Unit=whichannel[1];
   
   s[2]=finish;
   s[2].ioa_Request.io_Unit=whichannel[2];
   
   s[3]=finish;
   s[3].ioa_Request.io_Unit=whichannel[3];
   
   grab_channel(&s[0],&finish,"Ch0");
   grab_channel(&s[1],&finish,"Ch1");
   grab_channel(&s[2],&finish,"Ch2");
   grab_channel(&s[3],&finish,"Ch3");
   
   finish.ioa_Request.io_Command=ADCMD_FINISH;
}

  
void StopChannel (channel)
int channel;
{
   s[channel].ioa_Request.io_Command=ADCMD_FINISH;
   s[channel].ioa_Request.io_Flags=ADIOF_PERVOL | IOF_QUICK;
   BeginIO(&s[channel]);
}

void PlaySample (channel,sample)
int channel;
Sample *sample;
{
   if (sample->buffer)
   {
     s[channel].ioa_Request.io_Command=ADCMD_FINISH;
     s[channel].ioa_Request.io_Flags=ADIOF_PERVOL | IOF_QUICK;
     BeginIO(&s[channel]);

     s[channel].ioa_Request.io_Command=CMD_WRITE;
     s[channel].ioa_Request.io_Flags=ADIOF_PERVOL | IOF_QUICK;
     s[channel].ioa_Data=sample->buffer;
     s[channel].ioa_Cycles=sample->repeat;
     s[channel].ioa_Length=sample->buflen;
     s[channel].ioa_Period=sample->period;
     s[channel].ioa_Volume=sample->volume;
     BeginIO(&s[channel]);
   }
} 

void FreeAllChannels()
{
 finish.ioa_Request.io_Unit=whichannel[0];
 BeginIO(&finish);
 WaitIO(&finish);

 finish.ioa_Request.io_Unit=whichannel[1];
 BeginIO(&finish);
 WaitIO(&finish);
 
 finish.ioa_Request.io_Unit=whichannel[2];
 BeginIO(&finish);
 WaitIO(&finish);
 
 finish.ioa_Request.io_Unit=whichannel[3];
 BeginIO(&finish);
 WaitIO(&finish);
 
 DeletePort (s[0].ioa_Request.io_Message.mn_ReplyPort); 
 DeletePort (s[1].ioa_Request.io_Message.mn_ReplyPort); 
 DeletePort (s[2].ioa_Request.io_Message.mn_ReplyPort); 
 DeletePort (s[3].ioa_Request.io_Message.mn_ReplyPort);
 DeletePort (finish.ioa_Request.io_Message.mn_ReplyPort);
 
 CloseDevice (&finish);
}

