/*$Author:   DCODY  $*/
/*$Date:   24 Sep 1992 08:59:20  $*/
/*$Header:   X:/sccs/pcmapps/playfile.c_v   1.9   24 Sep 1992 08:59:20   DCODY  $*/
/*$Log:   X:/sccs/pcmapps/playfile.c_v  $
 * 
 *    Rev 1.9   24 Sep 1992 08:59:20   DCODY
 * changed MVGetHardware to mvGetHardware
 * 
 *    Rev 1.8   14 Sep 1992 17:22:38   SHAO_M
 * Put all the text strings used in printf into playtext.h
 * 
 *    Rev 1.0   14 Sep 1992 17:01:30   unknown
 * Initial revision.
 * 
 *    Rev 1.7   13 Aug 1992 08:26:18   DCODY
 * corrected #if/#endif and } placement for TB stuff...
 * 
 *    Rev 1.6   04 Aug 1992 11:39:54   DCODY
 * corrected t&l spelling
 * 
 *    Rev 1.5   28 Jul 1992 14:29:06   DCODY
 * updated for Thunderboard and Thunder&Lightning
 * 
 *    Rev 1.4   20 Jul 1992 11:39:02   DCODY
 * call to mvGetHWVersion now uses active I/O address detection.
 * 
 *    Rev 1.3   13 Jul 1992 18:54:14   DCODY
 * removed initmvsound call
 * 
 *    Rev 1.2   01 Jul 1992 11:55:16   DCODY
 * GaryL: Added OEM compiler flag checking for Welcome()
 * to use the generic board name and to not display the MVI copyright.
 * Note that the copyright is still present, as an imbedded static string.
 * 
 *    Rev 1.1   23 Jun 1992 16:09:50   DCODY
 * pas2 update...
 * 
 *    Rev 1.0   15 Jun 1992 09:26:40   BCRANE
 * Initial revision.
*/
/*$Logfile:   X:/sccs/pcmapps/playfile.c_v  $*/
/*$Modtimes$*/
/*$Revision:   1.9  $*/
/*$Workfile:   playfile.c  $*/


	/*\
	|*|----====< PLAYFILE.C >====----
	|*|
	|*| Play the voice file from disk to the PCM hardware
	|*|
	|*| Copyright (c) 1991, Media Vision, Inc. All rights reserved.
    |*|
    \*/

#ifndef OEM
#define OEM	0	/* OEM compile flag					*/
#endif
#ifndef PROAS
#define PROAS	0	/* Pro Audio Spectrum compile flag					*/
#endif
#ifndef THUNDER
#define THUNDER 0	/* Thunder Board compile flag						*/
#endif

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <signal.h>
#include "playtext.h"

#if PROAS
#include "play.h"
#include "common.h"
#include "pcmio.h"
#endif

#if THUNDER
#include "proto.h"
#include "play.h"
#include "common.h"
#include "pcmio.h"
#include "mvsound.h"
#endif


    /*\
	|*|----====< Global Variables >====----
	\*/

		extern int DMARunning;

		long mvGetHWVersion (int);


	/*\
	|*|----====< Local Variables >====----
	\*/

		static FILE *inf;				/* user input file				*/

		static long SampleRate = 11025L;/* default sample rate			*/
		static int	StereoMono = 0; 	/* default to mono				*/
		static int	Filter	   = -1;	/* filter override #			*/
		static int	Compression= FALSE; /* compressed data				*/

		static int	DMAChannel = -1;	/* default to standard DMA		*/
		static int	IRQChannel = -1;	/* default to standard IRQ		*/

		static int	speed = 100;		/* 100 percent					*/

		static int	UserStereoMono = -1;/* user's override flag = mono  */
		static long UserSampleRate = -1;/* user's override = 11k        */
		static long DataLength	   = -1;/* -1 goes to EOF				*/

		static int	maxsize    = 16;	/* 16k DMA buffer size			*/
		static int	maxdiv	   = 4; 	/* 4k divisions on the DMA		*/
		static int	datasize   = 8; 	/* 8 bit or 16 bit pcm			*/
		static int	dsoverride = FALSE; /* data size override			*/

#define ALLOTHERS	0					/* assume an 8 bit data file	*/
#define WAVEFILE	1					/* wave type of file			*/
#define VOCFILE 	2					/* .voc 8 bit pcm file			*/
		static int	FileType;			/* type of source file			*/

#define BUFFLEN 	4096
		static char vocbuffer[BUFFLEN]; /* 4k worth of data 			*/
		static long VOCBlockLength; 	/* current block length 		*/
		static char VOCBlockType;		/* current block type			*/
		static char VOCPackType;

        int  CommandLine    ( int, char *[] );
        int  DoExit         ( int );
        int  FetchVOCData   ( char * ); /* buffer of PCM data           */
        int  PreProcessFile ( char * );
        int  SetupPlayRate  ( );
        void SetupSound     ( );


	/*\
	|*|----====< Main >====----
	|*|
	|*| Play the voice file out to the PCM hardware
	|*|
	\*/

main(argc,argv)
	int  argc;
	char *argv[];
{
char c;

	/* give the opening welcome & checkout the hardware 				*/

		Welcome();

	/* set the runtime switches 										*/

        CommandLine (argc,argv);

    /* disable the ^C                                                   */

		signal (SIGINT,SIG_IGN);

	/* need a file name to play, exit if not found						*/

		PreProcessFile (argv[1]);

		if (OpenPCMBuffering(DMAChannel,IRQChannel,maxsize,maxdiv)) {
			printf (TXT_MSG1);
			DoExit (-1);
		}

	/* setup how this file sounds										*/

		SetupSound();

    /* Start the DMA & wait till an ESC is typed or data ends           */

		printf (TXT_MSG2);

		if (FileType <= WAVEFILE) {

			/* .WAV & all other files can go out using normal file I/O	*/

            if (StartFileOutput( inf, DataLength )) {

				while (1) {

					/* if all done, then just break 					*/

						if (!ContinueFileOutput())
							break;

					/* if ESC typed, kill the DMA & exit				*/

						if (kbhit()) {

							if ((c = getch()) == 0x1b) {
								StopDMAIO();
								break;
							}
							if (c == ' ') {
								PausePCM();
								printf (TXT_MSG3);
								GetKey();
								printf (TXT_MSG4);
								ResumePCM();
							}
                        }
				}
			}
		}
		else {

			/* if there is data available, play it...					*/

			if (FetchVOCData(vocbuffer)) {

				/* start the output with the first block of data		*/

				if (StartBlockOutput( vocbuffer )) {

					/* fetch the next block of data 					*/

                    FetchVOCData(vocbuffer);

					while (1) {

						/* if the block can be passed, reload it		*/

							if (ContinueBlockOutput(vocbuffer)) {
								if (!FetchVOCData(vocbuffer))
									break;
							}

						/* if ESC typed, kill the DMA & exit			*/

							if (kbhit()) {

								if ((c = getch()) == 0x1b) {
									StopDMAIO();
									DoExit(0);
								}
								if (c == ' ') {
									PausePCM();
									printf (TXT_MSG5);
									GetKey();
									printf (TXT_MSG6);
									ResumePCM();
								}
							}
                    }

					/* wait till the DMA finishes						*/

					while (DMARunning) ;

                }
			}
		}

	/* exit to DOS														*/

		DoExit(0);

}


	/*\
	|*|----====< CommandLine >====----
	|*|
	|*| process the command line switches
	|*|
	\*/
int CommandLine(argc,argv)
	int argc;
	char *argv[];
{
char *s;
int n,temp;
long longtemp;

	/* exit if no additional parameters 								*/

		if (argc < 2) {
			GiveHelps();
			DoExit (-1);
		}

		n = 2;
		while (n < argc) {

			s = argv[n++];

			if (*s == '/') s++;
			if (*s == '-') s++;

			switch (*s & 0x5f) {

#if PROAS
				case '1' & 0x5f:
				case '8' & 0x5f:
					if (*++s == '6')
                        datasize   = 16;
					dsoverride = TRUE;

                    break;

				case 'F':
					Filter = *++s - 0x30;
					if ((Filter > 6) || (Filter < 0))
						Filter = -1;
					break;
#endif

                case 'D':
					temp = *++s - 0x30;
					if ((temp <= 7) && (temp >= 1)) {
						if (temp == 4) temp = 0;
						DMAChannel = temp;
					}
                    break;

				case 'I':
					if (sscanf (++s,"%d",&temp) == 1) {
						if ((1 << temp) & 0x9CBC)
							IRQChannel = temp;
					}
					break;

                case 'M':
					maxsize = 64;
					maxdiv	= 16;
                    break;

                case 'R':
					if (sscanf (++s,"%ld",&longtemp) == 1) {
						if ((longtemp >4000L) && (longtemp < 88200L))
							UserSampleRate = longtemp;
					}
					break;

				case 'S':
					s++;

                    if (*s == '\0')
						UserStereoMono = 1;
					else {
						if (sscanf (s,"%d",&temp) == 1) {
							if ((temp >= 0) && ( temp <= 200))
								speed = temp;
						}
                    }
                    break;

				default:
					break;
			}
		}
}


	/*\
	|*|----====< DoExit() >====----
	|*|
	|*| Exit to DOS
	|*|
	\*/
int DoExit(cc)
	int cc;
{
		ClosePCMBuffering();
		exit (cc);
}


	/*\
	|*|----====< GiveHelps() >====----
	|*|
	|*| print text helps & return
	|*|
	\*/
int GiveHelps()
{

	/* print & return...												*/

#if PROAS
		printf (TXT_MSG7);
		printf (TXT_MSG8);
		printf (TXT_MSG9);
		printf (TXT_MSG10);
		printf (TXT_MSG11);
		printf (TXT_MSG12);
		printf (TXT_MSG13);
        printf (TXT_MSG14);
		printf (TXT_MSG15);
		printf (TXT_MSG16);
		printf (TXT_MSG17);
#endif

#if THUNDER
		printf (TXT_MSG18);
		printf (TXT_MSG19);
		printf (TXT_MSG20);
 #if THUNDER==2
		printf (TXT_MSG21);
		printf (TXT_MSG22);
 #else
		printf (TXT_MSG23);
 #endif
        printf (TXT_MSG24);
		printf (TXT_MSG25);
		printf (TXT_MSG26);
#endif
}


	/*\
	|*|----====< FetchVOCData >====----
	|*|
	|*| Get a new key
	|*|
	\*/
int FetchVOCData(buff)
	char *buff;
{
int loaded = 0, n;
int looping = TRUE;
int remaining = BUFFLEN;

	/* grab the next block of data										*/

		looping = 1;
		while (looping) {

			/* process the header										*/

				switch (VOCBlockType) {

					case TERMINATOR:

                        for (;remaining;remaining--)
							*buff++ = 0x80;
                        remaining = 0;
						looping = 0;		/* this will knock us out	*/
						break;

                    case VOICECONTINUE:
					case VOICEDATA:

						/* load the data, try to span blocks			*/

						if (VOCBlockLength < remaining) {
							remaining -= VOCBlockLength;
							n = fread (buff,1,(size_t)VOCBlockLength,inf);
                            loaded += n;
							buff += n;
							VOCBlockLength = 0;
						}
						else {
							n = fread(buff,1,remaining,inf);
							loaded += n;
							VOCBlockLength -= n;
							looping = remaining = 0;
                        }
						break;

					case SILENCE:

						/* load the data, try to span blocks			*/

						if (VOCBlockLength < remaining) {
							remaining -= VOCBlockLength;
							loaded += VOCBlockLength;
							for (;VOCBlockLength;VOCBlockLength--)
								*buff++ = 0x80;
						}
						else {
							loaded = remaining;
							VOCBlockLength -= remaining;
							for (;remaining;remaining--)
								*buff++ = 0x80;
							looping = remaining = 0;
                        }
						break;

					case MARKER:
					case REPEAT:
					case ENDREPEAT:
					case ASCIITEXT:

						/* all the rest of the header were eaten by the 	*/
						/* "GetNextBlock" routine. We will continue till we */
						/* find data, or the terminating record 			*/

					default:
						break;
				}

				/* span blocks, but exit on EOF 							*/

				if (remaining) {
					if (!GetNextBlock()) {
						for (;remaining;remaining--)
							*buff++ = 0x80;
						looping = FALSE;
					}
				}
        }

	/* return with data data block											*/

        return(loaded);
}


	/*\
	|*|----====< GetKey() >====----
	|*|
	|*| Get a new key
	|*|
	\*/
int GetKey()
{
char c;

	while (kbhit()) getch();

	while (!kbhit()) ;
	if (getch() == 0) getch();

}


	/*\
	|*|----====< GetNextBlock() >====----
	|*|
	|*| Process the header to the next block, & return TRUE if data is
	|*| pointed to.
	|*|
	\*/
int GetNextBlock()
{
int looping = TRUE;
long l;

    /* get the record type & process to get the sample rate             */

		VOCBlockLength = 0; 			/* we must end up with data!	*/
		while (looping) {

			switch (VOCBlockType = fgetc(inf)) {

				case TERMINATOR:
					return(0);			/* if at the end, just exit 	*/

				case SILENCE:
                    fgetc(inf);fgetc(inf);fgetc(inf);
                    VOCBlockLength  = fgetc(inf) & 0xff;
					VOCBlockLength += ((long)(fgetc(inf) & 0xff)) << 8;
					SetupPlayRate(fgetc(inf) & 0xff);
					VOCBlockLength -= 3;	/* 3 less for header data	*/
					looping = FALSE;
                    break;

                case VOICEDATA:
					VOCBlockLength	= fgetc(inf) & 0xff;
					VOCBlockLength += ((long)(fgetc(inf) & 0xff)) << 8;
					VOCBlockLength += ((long)(fgetc(inf) & 0xff)) << 16;
					SetupPlayRate(fgetc(inf) & 0xff);

					/* determine mono/stereo							*/

					StereoMono = 0;
					if (((VOCPackType = fgetc(inf)) & 0xff) == 5) {
						StereoMono = 1;
						VOCPackType = 0;
					}
#if THUNDER
					/* determine compression							*/

					if (VOCPackType <= 3)	/* types 0 - 3				*/
						Compression = VOCPackType;
#endif
                    VOCBlockLength -= 2;    /* 2 less for header data   */
					looping = FALSE;
					break;

				case ASCIITEXT:
					l  = fgetc(inf) & 0xff;
					l += ((long)(fgetc(inf) & 0xff)) << 8;
					l += ((long)(fgetc(inf) & 0xff)) << 16;
					for (;l;l--)
						fgetc(inf);
					break;

				case MARKER:
				case REPEAT:
					fgetc(inf);fgetc(inf);
				case ENDREPEAT:
					fgetc(inf);fgetc(inf);fgetc(inf);
					break;

				default:
					printf (TXT_MSG27);
					DoExit(-1);
					break;

			}
		}

	/* we leave the file pointing to the first data byte				*/

		return(1);
}

	/*\
	|*|----====< PreProcessFile >====----
	|*|
	|*| Fill the play buffer with the contents of the disk file
	|*|
	\*/
int PreProcessFile (fn)
	char *fn;
{
char buff[100];
int n,looping;
long psize,l;
char *p,*b;
long* ptr;
FILE *wf;

	/* attempt to open the users disk file								*/

		if ((inf = fopen(fn,"rb")) == 0) {

            strcpy (buff,fn);
			strcat (buff,".WAV");
			if ((inf = fopen(buff,"rb")) == 0) {

                strcpy (buff,fn);
				strcat (buff,".VOC");
				if ((inf = fopen(buff,"rb")) == 0) {

                    printf (TXT_MSG28,fn);
					DoExit (-1);
				}
			}
        }

	/* get the 1st 2 characters in the file 							*/

        n = fgetc(inf) & 0xff;
		n = n + ((fgetc(inf) & 0xff) << 8);

		fseek (inf,0L,SEEK_SET); /* rewind to the start 				*/

	/* special case a .WAV file 										*/

        if (n == 0x4952) {
			 ProcessWAVFile();
			 return(0);
		}

	/* special case anything else than a .VOC file						*/

		if (n != 0x7243) {		/* if NE to Creative..., then it's PCM  */
			 ProcessPCMFile();
			 return(0);
		}

	/* .VOC type of source file 										*/

		FileType = VOCFILE;

    /* get the header of the voice file                                 */

		b = &buff[0];
		fseek(inf,0L,SEEK_SET); 		/* move to the first byte		*/
		for (n=0;n<(sizeof (VOCHDR));n++)
			*b++ = fgetc(inf);

		if (feof(inf)) {
			printf (TXT_MSG29);
			DoExit (-1);
		}

	/* Make sure it's a legit file                                      */

		if (strncmp (buff,"Creative Voice File",0x13) != 0) {
			printf (TXT_MSG30);
			DoExit (-1);
		}

		p = &buff[0x14];				/* get a pointer to the offset	*/

		psize = LONG(*p) & 0xffff;		/* get the 16 bit word			*/

		fseek(inf,psize,SEEK_SET);		/* move to the first byte		*/

		if (!GetNextBlock())			/* process the next header		*/
			DoExit(0);

}


	/*\
	|*|----====< ProcessWAVFile >====----
	|*|
	|*| load the header from our WAV file format
	|*|
	\*/
int ProcessWAVFile(f)
{
int n;
char *b,c;
WaveInfo whd;
DataHeader dhd;

	/* We are a WAVE file												*/

        FileType = WAVEFILE;            /* type of source file          */

	/* eat the RIFF portion of the header								*/

		c = fgetc(inf);

		if (c == 'R') {
			for (n=7;n;n--)
				fgetc(inf);
			c = fgetc(inf);
		}

	/* pas up the wave block header name								*/

		if (c != 'W') {
			printf (TXT_MSG31);
			DoExit(-1);
		}
		fgetc(inf); fgetc(inf); fgetc(inf); 	/* move past the data	*/

	/* pass up the format section name									*/

		c = fgetc(inf);
		if (c != 'f') {
			printf (TXT_MSG32);
			DoExit(-1);
		}
		for (n=7;n;n--)
			fgetc(inf); 						/* move past the data	*/

	/* load the actual header data										*/

		b = (char *) &whd;
		for (n=0;n<sizeof (WaveInfo);n++)
			*b++ = fgetc(inf);

	/* grab the sample rate 											*/

		StereoMono = whd.nChannels - 1;
		SampleRate = whd.nSamplesPerSec;

	/* setup the data size only if no override has been requested		*/

        if (!dsoverride)
			datasize   = whd.nBitsPerSample;

	/* go to the data section and get the data length					*/

		b = (char *) &dhd;
		for (n=0;n<sizeof(DataHeader);n++)
			*b++ = fgetc(inf);					/* move past the data	*/

		if (dhd.name[0] != 'd') {
			printf (TXT_MSG33);
			DoExit(-1);
		}

		DataLength = dhd.length;

}


	/*\
	|*|----====< ProcessPCMFile >====----
	|*|
	|*| load the header from our PCM file format
	|*|
	\*/
int ProcessPCMFile()
{
int n;
char *b;

	/* we are some unknown data type									*/

		FileType = ALLOTHERS;			/* type of source file			*/

    /* ask for the sample rate                                          */

		if (UserSampleRate != -1) {
			SampleRate = UserSampleRate;

            if (UserStereoMono == -1)
				UserStereoMono = 0;

			StereoMono = UserStereoMono;
		}
		else {

			SampleRate = 11025L;
			printf (TXT_MSG34);
			while (1) {
				if (scanf ("%ld",&SampleRate) == 1)
					break;
			}

			printf (TXT_MSG35);
			while (1) {
				if (scanf ("%d",&StereoMono) == 1) {
					StereoMono--;	/* make it zero based				*/
					break;
				}
            }
        }

		if ((StereoMono < 0) || (StereoMono > 1))
			StereoMono = 0;
}


	/*\
	|*|----====< SetupPlayRate >====----
	|*|
	|*| Setup the playing rate of the interrupt routine.
	|*|
	\*/
int SetupPlayRate(n)
	int n;
{

	/* we will use a default rate										*/

		SampleRate = 11025L;

	/* search for the real rate 										*/

		while (1) {

			if (n <= 6) {
				SampleRate = 4000L; 		/* 4000 kh sampling 		*/
				break;
			}

			if (n <= 56) {
				SampleRate = 5000L; 		/* 5000 kh sampling 		*/
				break;
			}

			if (n <= 90) {
				SampleRate = 6000L; 		/* 6000 kh sampling 		*/
				break;
			}

			if (n <= 114) {
				SampleRate = 7000L; 		/* 7000 kh sampling 		*/
				break;
			}

			if (n <= 131) {
				SampleRate = 8000L; 		/* 8000 kh sampling 		*/
				break;
			}

			if (n <= 145) {
				SampleRate = 9000L; 		/* 9000 kh sampling 		*/
				break;
			}

			if (n <= 156) {
				SampleRate = 10000L;		/* 10000 kh sampling		*/
				break;
			}

			if (n <= 166) {
				SampleRate = 11000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 173) {
				SampleRate = 12000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 180) {
				SampleRate = 13000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 185) {
				SampleRate = 14000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 190) {
				SampleRate = 15000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 194) {
				SampleRate = 16000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 198) {
				SampleRate = 17000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 201) {
				SampleRate = 18000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 204) {
				SampleRate = 19000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 206) {
				SampleRate = 20000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 209) {
				SampleRate = 21000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 211) {
				SampleRate = 22000L;		/* 11000 kh sampling		*/
				break;
			}

			if (n <= 215) {
				SampleRate = 23000L;		/* 11000 kh sampling		*/
				break;
			}

			/* if unknown value, bomb out...							*/

				printf (TXT_MSG36);
				DoExit(0);

		}
}


	/*\
	|*|----====< SetupSound() >====----
	|*|
	|*| Setup the sample rate, stereo/mono.
	|*|
	\*/
void SetupSound()
{

	/* if the user wants it different...								*/

		if (UserSampleRate != -1)
			SampleRate = UserSampleRate;

		if (UserStereoMono != -1)
			StereoMono = UserStereoMono;

	/* speed is the user's %. from 0 to 200 %                           */

		SampleRate = ((SampleRate * speed) + 50) / 100;

#if PROAS
        ChooseFilter( SampleRate, Filter );
#endif

		PCMState (SampleRate, StereoMono, Compression, datasize );
}


	/*\
	|*|----====< Welcome >====----
	|*|
	|*| Print the logo & check for the appropriate hardware
	|*|
	\*/
Welcome()
{
long ver;

    /* give the normal stuff...                                         */

#if OEM

 #if PROAS
		printf (TXT_MSG37);
 #endif

 #if THUNDER
		printf (TXT_MSG38);
 #endif

		{
				static char	zsCopyright[] = "Copyright (c) 1991,1992 Media Vision, Inc. All Rights Reserved\n\n";
		}

#else

 #if PROAS
		printf (TXT_MSG39);
 #endif

 #if THUNDER
  #if THUNDER==2
		printf (TXT_MSG40);
  #else
		printf (TXT_MSG41);
  #endif
 #endif

		printf (TXT_MSG42);

#endif  //OEM

	/* check for the hardware											*/

#if PROAS
		ver = mvGetHWVersion(USE_ACTIVE_ADDR); /* get the version			   */
		if (ver == -1) {
 #if OEM
			printf (TXT_MSG43);
 #else	 //OEM
			printf (TXT_MSG44);
 #endif  //OEM
            GiveHelps();
			exit(-1);
		}
#endif

#if THUNDER
		ver = mvGetHWVersion(0);		/* get the version, or something.. */
		if ((ver < 0) || ((ver & 0xffff0000) != 0x00010000)) {
 #if OEM
			printf (TXT_MSG45);
 #else	 //OEM
  #if THUNDER==2
			printf (TXT_MSG46);
  #else
			printf (TXT_MSG47);
  #endif
 #endif
            GiveHelps();
			exit(-1);
		}

#endif  //THUNDER
}

	/*\
	|*| end of PLAYFILE.C
	\*/


