;	/*\
;	|*|	cdmaster.c
;	|*|	
;	|*|	routines for c-interface to cdrom audio functions
;	|*|	contains routines accessing internal data structures
;	|*|
;	|*|	Copyright (c) 1992, Media Vision, Inc.  All Rights Reserved
;	|*|
;	\*/

#include <stdlib.h>

#include "cdmaster.h"

static struct cdtable OURCDTABLES[26];

;	/*\
;	|*|	struct cdtable *createaudiotoc(int drive)
;	|*|
;	|*|	allocate memory for table of contents for audio disc in drive
;	|*|	call destroyaudiotoc() to free memory and clear internal table
;	|*|
;	|*|	Entry:	drive number, address of buffer
;	|*|
;	|*|	Exit:	return address of internal table of contents
;	|*|
;	\*/

struct cdtable *createaudiotoc(int drive)
{
	int status;
	struct discinfo *di;
	struct trackinfo *ti;

	/* destroy any existing toc for this drive */
	destroyaudiotoc(drive);

	di= &OURCDTABLES[drive].di;
	status= cddiscinfo(drive, di);

	if (status& 0x8000)
		return((struct cdtable *) 0);

	ti= (struct trackinfo *) calloc(di->ltrk- di->strk+ 1+ 1, sizeof(struct trackinfo));

	if (!ti)
		return((struct cdtable *) 0);

		{
		int i;
		struct trackinfo *dti;

		/* for now, do nothing;  we will cdtrackinfo(drive, i, dti); */
		for (i= di->strk, dti= ti; i <= di->ltrk; i++, dti++)
			;	

			{
			int dmin, dsec, dframe;
			dmin= ((di->eodisc& 0x00FF0000)>> 16);
			dsec= ((di->eodisc& 0x0000FF00)>> 8);
			dframe= ((di->eodisc& 0x000000FF)>> 0);

			/* audio data starts 2 seconds into the disc */
			/* dsec-= 2; !! removed and put into cdplay */

			fixmsf(&dmin, &dsec, &dframe);

			dti->track= i;
			dti->min= (char) dmin;
			dti->sec= (char) dsec;
			dti->frame= (char) dframe;
			}
		}

	OURCDTABLES[drive].ti= ti;

	return(&OURCDTABLES[drive]);
}

;	/*\
;	|*|	struct cdtable *buildaudiotoc(int drive)
;	|*|
;	|*|	allocate memory and build table of contents for audio disc in drive
;	|*|	call destroyaudiotoc() to free memory and clear internal table
;	|*|
;	|*|	Entry:	drive number, address of buffer
;	|*|
;	|*|	Exit:	return address of internal table of contents
;	|*|
;	\*/

struct cdtable *buildaudiotoc(int drive)
{
	int i;
	struct cdtable *cdt= createaudiotoc(drive);

	if (!cdt)
		return(cdt);

	for (i= cdt->di.strk; i <= cdt->di.ltrk; i++)
		gettrackframes(drive, i);

	return(cdt);

}

;	/*\
;	|*|	void destroyaudiotoc(int drive)
;	|*|
;	|*|	free memory allocated by buildaudiotoc() and clear internal tables
;	|*|	if passed address is not the same as internal table
;	|*|
;	|*|	Entry:	drive number, address of buffer
;	|*|
;	|*|	Exit:	return 0 if table entry for drive was not 0, else -1
;	|*|
;	\*/

destroyaudiotoc(int drive)
{
	int notallocated= 0;

	if (OURCDTABLES[drive].ti)
		free(OURCDTABLES[drive].ti);
	else
		notallocated= -1;

	OURCDTABLES[drive].ti= (struct trackinfo *) 0;
//	OURCDTABLES[drive].di= (struct discinfo *) 0;

	return(notallocated);
}

;	/*\
;	|*|	struct cdtable *getcdtable(int drive)
;	|*|
;	|*|	return address of internal cd table for drive
;	|*|
;	|*|	Entry:	drive number
;	|*|
;	|*|	Exit:	address of internal cd table  
;	|*|
;	\*/

struct cdtable *getcdtable(int drive)
{
	return(&OURCDTABLES[drive]);
}

;	/*\
;	|*|	struct discinfo *getdiscinfotable(int drive)
;	|*|
;	|*|	return address of internal discinfo structure for drive
;	|*|
;	|*|	Entry:	drive number
;	|*|
;	|*|	Exit:	address of internal discinfo structure
;	|*|
;	\*/

struct discinfo *getdiscinfotable(int drive)
{
	return(&OURCDTABLES[drive].di);
}

;	/*\
;	|*|	struct trackinfo *gettrackinfotable(int drive)
;	|*|
;	|*|	return address of internal table of contents for drive
;	|*|
;	|*|	Entry:	drive number
;	|*|
;	|*|	Exit:	address of internal table of contents
;	|*|
;	\*/

struct trackinfo *gettrackinfotable(int drive)
{
	return(OURCDTABLES[drive].ti);
}

;	/*\
;	|*|	long gettrackframes(int drive, int track)
;	|*|
;	|*|	return the number of frames for given track on the disc
;	|*|
;	|*|	Entry: drive number, track number
;	|*|
;	|*|	Exit:	return length of track in frames, or
;	|*|			return 0 if internal tables not initialized or track
;	|*|			number out of range
;	|*|
;	\*/

long gettrackframes(int drive, int track)
{
	int lframe;
	int lsec;
	int lmin;
	struct discinfo *di;
	struct trackinfo *dti;
	struct trackinfo *nti;
	long tframe;

	di= &OURCDTABLES[drive].di;
	dti= OURCDTABLES[drive].ti;

	if (!di || !dti || track < di->strk || track > di->ltrk)
		return(0);

	dti+= track- di->strk;
	nti= dti+ 1;

	if (!dti->track)
		{
		cdtrackinfo(drive, track, dti);
//		dti->sec-= 2;	/* data starts 2 seconds into disc */
		}

	if (!nti->track)
		{
		cdtrackinfo(drive, track+ 1, nti);
//		nti->sec-= 2;	/* data starts 2 seconds into disc */
		}

	lmin= nti->min- dti->min;
	lsec= nti->sec- dti->sec;
	lframe= nti->frame- dti->frame;

	if (fixmsf(&lmin, &lsec, &lframe) == -1)
		return(-1);

	tframe= lmin;
	tframe*= 60;
	tframe+= lsec;
	tframe*= 75;
	tframe+= lframe;

	return(tframe);
}

;	/*\
;	|*|	playcdtrack(int drive, int track, int offset, int length)
;	|*|
;	|*|	begin audio play on disc for specified track at offset for length
;	|*|
;	|*|	Entry:	drive number, track number, offset in seconds in track,
;	|*|				length in seconds or -1 for rest of disc or -2 for track
;	|*|
;	|*|	Exit:	return -1 if no disc present, no internal table of contents,
;	|*|				track is out of range, offset is past end of track or disc
;	|*|			else return driver status
;	|*|
;	\*/

playcdtrack(int drive, int track, int offset, int length)
{
	int ourtrack;
	int ourstatus;
	struct discinfo *di;
	struct trackinfo *ti, *sti, *dti;
	int min, sec, frame;
	int dmin, dsec, dframe;

	ourstatus= cdstatus(drive);

	if (!(ourstatus& CDISHERE))
		return(-1);

	if (!OURCDTABLES[drive].ti)
		return(-1);

	di= &OURCDTABLES[drive].di;

	ourtrack= track- di->strk;

	if (ourtrack < 0 || ourtrack >= di->ltrk)
		return(-1);

	if (ourstatus& (CDISPLAYING| CDISPAUSED))
		cdstop(drive);

	/* get starting MSF for our track
	* sti points to first trackinfo structure for disc
	* ti will point to the track to play
	* dti will point to the ending point
	*/

	ti= dti= sti= OURCDTABLES[drive].ti;
	ti+= ourtrack;

	if (!ti->track)
		{
		cdtrackinfo(drive, track, ti);
//		ti->sec-= 2;
		}

	/* min,sec,frame will hold the start m:s:f address */
	min= ti->min;
	sec= ti->sec;
	frame= ti->frame;

	/* length is amount of seconds to play, a negative is special */
	if (length < 0)
		{
		switch (length)
			{
			case -1: dti+= di->ltrk- di->strk+ 1; break;	/* rest of disc */
			case -2: dti+= ourtrack+ 1; break;				/* rest of track */
			}
		length= 0;
		}

	if (!dti->track)
		{
		cdtrackinfo(drive, dti- sti+ di->strk, dti);
//		dti->sec-= 2;
		}

	/* dmin,dsec,drame holds the amount of time to play */
	dmin= dti->min- min;
	dsec= dti->sec- sec;
	dframe= dti->frame- frame;

	/* offset and length are passed as parameters as seconds, affect */
	sec+= offset;
	dsec+= length- offset;

	/* adjust length (endofdisc- startofdisc) */
	dmin-= sti->min;
	dsec-= sti->sec;
	dframe-= sti->frame;


	if (fixmsf(&min, &sec, &frame) < 0)
		return(-1);
	if (fixmsf(&dmin, &dsec, &dframe) < 0)
		return(-1);

	return(cdplaymsf(drive, min, sec, frame, dmin, dsec, dframe));
}

;	/*\
;	|*|	seektotrack(int drive, int track)
;	|*|
;	|*|	move head on drive to specified track
;	|*|
;	|*|	Entry:	drive number, track number
;	|*|
;	|*|     Exit:   return 0 if no internal tables or track out of range,
;	|*|             else return driver status
;	|*|
;	\*/

seektotrack(int drive, int track)
{
	struct discinfo *d= &OURCDTABLES[drive].di;
	struct trackinfo *t= OURCDTABLES[drive].ti;

	if (!d || !t)
		return(0);

	if (track < d->strk || track > d->ltrk)
		return(0);

	t+= track- d->strk;

	if (!t->track)
		{
		cdtrackinfo(drive, track, t);
//		t->sec-= 2;
		}

	return(cdseekmsf(drive, t->min, t->sec, t->frame));
}

