diff src/cdrom/macos/SDL_syscdrom.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children e8157fcb3114
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cdrom/macos/SDL_syscdrom.c	Thu Apr 26 16:45:43 2001 +0000
@@ -0,0 +1,526 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@devolution.com
+*/
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id$";
+#endif
+
+/* MacOS functions for system-level CD-ROM audio control */
+
+#include <Devices.h>
+#include <Files.h>
+#include <LowMem.h> /* Use entry table macros, not functions in InterfaceLib  */
+
+#include "SDL_cdrom.h"
+#include "SDL_syscdrom.h"
+#include "SDL_syscdrom_c.h"
+
+/* Added by Matt Slot */
+#if !defined(LMGetUnitTableEntryCount)
+  #define LMGetUnitTableEntryCount()   *(short *)0x01D2
+#endif
+
+/* The maximum number of CD-ROM drives we'll detect */
+#define MAX_DRIVES	26	
+
+/* A list of available CD-ROM drives */
+static long SDL_cdversion = 0;
+static struct {
+	short		dRefNum;
+	short		driveNum;
+	long		frames;
+	char		name[256];
+	Boolean		hasAudio;
+	} SDL_cdlist[MAX_DRIVES];
+static StringPtr gDriverName = "\p.AppleCD";
+
+/* The system-dependent CD control functions */
+static const char *SDL_SYS_CDName(int drive);
+static int SDL_SYS_CDOpen(int drive);
+static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
+static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
+static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
+static int SDL_SYS_CDPause(SDL_CD *cdrom);
+static int SDL_SYS_CDResume(SDL_CD *cdrom);
+static int SDL_SYS_CDStop(SDL_CD *cdrom);
+static int SDL_SYS_CDEject(SDL_CD *cdrom);
+static void SDL_SYS_CDClose(SDL_CD *cdrom);
+
+static short SDL_SYS_ShortToBCD(short value)
+{
+	return((value % 10) + (value / 10) * 0x10); /* Convert value to BCD */
+}
+
+static short SDL_SYS_BCDToShort(short value)
+{
+	return((value % 0x10) + (value / 0x10) * 10); /* Convert value from BCD */
+}
+
+int  SDL_SYS_CDInit(void)
+{
+	SInt16			dRefNum = 0;
+	SInt16			first, last;
+
+	SDL_numcds = 0;
+
+	/* Check that the software is available */
+	if (Gestalt(kGestaltAudioCDSelector, &SDL_cdversion) || 
+			!SDL_cdversion) return(0);
+
+	/* Fill in our driver capabilities */
+	SDL_CDcaps.Name = SDL_SYS_CDName;
+	SDL_CDcaps.Open = SDL_SYS_CDOpen;
+	SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
+	SDL_CDcaps.Status = SDL_SYS_CDStatus;
+	SDL_CDcaps.Play = SDL_SYS_CDPlay;
+	SDL_CDcaps.Pause = SDL_SYS_CDPause;
+	SDL_CDcaps.Resume = SDL_SYS_CDResume;
+	SDL_CDcaps.Stop = SDL_SYS_CDStop;
+	SDL_CDcaps.Eject = SDL_SYS_CDEject;
+	SDL_CDcaps.Close = SDL_SYS_CDClose;
+
+	/* Walk the list, count each AudioCD driver, and save the refnums */
+	first = -1;
+	last = 0 - LMGetUnitTableEntryCount();
+	for(dRefNum = first; dRefNum >= last; dRefNum--) {
+		Str255		driverName;
+		StringPtr	namePtr;
+		DCtlHandle	deviceEntry;
+
+		deviceEntry = GetDCtlEntry(dRefNum);
+		if (! deviceEntry) continue;
+		
+		/* Is this an .AppleCD ? */
+		namePtr = (*deviceEntry)->dCtlFlags & (1L << dRAMBased) ?
+				((StringPtr) ((DCtlPtr) deviceEntry)->dCtlDriver + 18) :
+				((StringPtr) (*deviceEntry)->dCtlDriver + 18);
+		BlockMoveData(namePtr, driverName, namePtr[0]+1);
+		if (driverName[0] > gDriverName[0]) driverName[0] = gDriverName[0];
+		if (! EqualString(driverName, gDriverName, false, false)) continue;
+
+		/* Record the basic info for each drive */
+		SDL_cdlist[SDL_numcds].dRefNum = dRefNum;
+		BlockMoveData(namePtr + 1, SDL_cdlist[SDL_numcds].name, namePtr[0]);
+		SDL_cdlist[SDL_numcds].name[namePtr[0]] = 0;
+		SDL_cdlist[SDL_numcds].hasAudio = false;
+		SDL_numcds++;
+	}
+	return(0);
+}
+
+static const char *SDL_SYS_CDName(int drive)
+{
+	return(SDL_cdlist[drive].name);
+}
+
+static int get_drivenum(int drive)
+{
+	QHdr *driveQ = GetDrvQHdr();
+	DrvQEl *driveElem;
+
+	/* Update the drive number */
+	SDL_cdlist[drive].driveNum = 0;
+	if ( driveQ->qTail ) {
+		driveQ->qTail->qLink = 0;
+	}
+	for ( driveElem=(DrvQEl *)driveQ->qHead; driveElem;
+	      driveElem = (DrvQEl *)driveElem->qLink ) {
+		if ( driveElem->dQRefNum == SDL_cdlist[drive].dRefNum ) {
+			SDL_cdlist[drive].driveNum = driveElem->dQDrive;
+			break;
+		}
+	}
+	return(SDL_cdlist[drive].driveNum);
+}
+
+static int SDL_SYS_CDOpen(int drive)
+{
+	return(drive);
+}
+
+static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
+{
+	CDCntrlParam		cdpb;
+	CDTrackData			tracks[SDL_MAX_TRACKS];
+	long				i, leadout;
+
+	/* Get the number of tracks on the CD by examining the TOC */
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kReadTOC;
+	cdpb.csParam.words[0] = kGetTrackRange;
+	if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+		SDL_SetError("PBControlSync() failed");
+		return(-1);
+	}
+
+	cdrom->numtracks = 
+			SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]) - 
+			SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]) + 1;
+	if ( cdrom->numtracks > SDL_MAX_TRACKS )
+		cdrom->numtracks = SDL_MAX_TRACKS;
+	cdrom->status = CD_STOPPED;
+	cdrom->cur_track = 0; /* Apparently these are set elsewhere */
+	cdrom->cur_frame = 0; /* Apparently these are set elsewhere */
+
+
+	/* Get the lead out area of the CD by examining the TOC */
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kReadTOC;
+	cdpb.csParam.words[0] = kGetLeadOutArea;
+	if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+		SDL_SetError("PBControlSync() failed");
+		return(-1);
+	}
+
+	leadout = MSF_TO_FRAMES(
+			SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]),
+			SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]),
+			SDL_SYS_BCDToShort(cdpb.csParam.bytes[2]));
+
+	/* Get an array of track locations by examining the TOC */
+	memset(tracks, 0, sizeof(tracks));
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kReadTOC;
+	cdpb.csParam.words[0] = kGetTrackEntries;	/* Type of Query */
+	* ((long *) (cdpb.csParam.words+1)) = (long) tracks;				
+	cdpb.csParam.words[3] = cdrom->numtracks * sizeof(tracks[0]);		
+	* ((char *) (cdpb.csParam.words+4)) = 1;	/* First track */
+	if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+		SDL_SetError("PBControlSync() failed");
+		return(-1);
+	}
+
+	/* Read all the track TOC entries */
+	SDL_cdlist[cdrom->id].hasAudio = false;
+	for ( i=0; i<cdrom->numtracks; ++i ) 
+		{
+		cdrom->track[i].id = i+1;
+		if (tracks[i].entry.control & kDataTrackMask)
+			cdrom->track[i].type = SDL_DATA_TRACK;
+		else
+			{
+			cdrom->track[i].type = SDL_AUDIO_TRACK;
+			SDL_cdlist[SDL_numcds].hasAudio = true;
+			}
+		
+		cdrom->track[i].offset = MSF_TO_FRAMES(
+				SDL_SYS_BCDToShort(tracks[i].entry.min),
+				SDL_SYS_BCDToShort(tracks[i].entry.min),
+				SDL_SYS_BCDToShort(tracks[i].entry.frame));
+		cdrom->track[i].length = MSF_TO_FRAMES(
+				SDL_SYS_BCDToShort(tracks[i+1].entry.min),
+				SDL_SYS_BCDToShort(tracks[i+1].entry.min),
+				SDL_SYS_BCDToShort(tracks[i+1].entry.frame)) -
+				cdrom->track[i].offset;
+		}
+	
+	/* Apparently SDL wants a fake last entry */
+	cdrom->track[i].offset = leadout;
+	cdrom->track[i].length = 0;
+
+	return(0);
+}
+
+/* Get CD-ROM status */
+static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
+{
+	CDCntrlParam cdpb;
+	CDstatus status = CD_ERROR;
+	Boolean spinning = false;
+
+	if (position) *position = 0;
+
+	/* Get the number of tracks on the CD by examining the TOC */
+	if ( ! get_drivenum(cdrom->id) ) {
+		return(CD_TRAYEMPTY);
+	}
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kReadTOC;
+	cdpb.csParam.words[0] = kGetTrackRange;
+	if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+		SDL_SetError("PBControlSync() failed");
+		return(CD_ERROR);
+	}
+
+	cdrom->numtracks = 
+			SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]) - 
+			SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]) + 1;
+	if ( cdrom->numtracks > SDL_MAX_TRACKS )
+		cdrom->numtracks = SDL_MAX_TRACKS;
+	cdrom->cur_track = 0; /* Apparently these are set elsewhere */
+	cdrom->cur_frame = 0; /* Apparently these are set elsewhere */
+
+
+	if (1 || SDL_cdlist[cdrom->id].hasAudio) {
+		/* Get the current playback status */
+		memset(&cdpb, 0, sizeof(cdpb));
+		cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+		cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+		cdpb.csCode = kAudioStatus;
+		if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+			SDL_SetError("PBControlSync() failed");
+			return(-1);
+		}
+	
+		switch(cdpb.csParam.cd.status) {
+			case kStatusPlaying:
+				status = CD_PLAYING;
+				spinning = true;
+				break;
+			case kStatusPaused:
+				status = CD_PAUSED;
+				spinning = true;
+				break;
+			case kStatusMuted:
+				status = CD_PLAYING; /* What should I do here? */
+				spinning = true;
+				break;
+			case kStatusDone:
+				status = CD_STOPPED;
+				spinning = true;
+				break;
+			case kStatusStopped:
+				status = CD_STOPPED;
+				spinning = false;
+				break;
+			case kStatusError:
+			default:
+				status = CD_ERROR;
+				spinning = false;
+				break;
+			}
+
+		if (spinning && position) *position = MSF_TO_FRAMES(
+				SDL_SYS_BCDToShort(cdpb.csParam.cd.minute),
+				SDL_SYS_BCDToShort(cdpb.csParam.cd.second),
+				SDL_SYS_BCDToShort(cdpb.csParam.cd.frame));
+		}
+	else
+		status = CD_ERROR; /* What should I do here? */
+
+	return(status);
+}
+
+/* Start play */
+static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
+{
+	CDCntrlParam cdpb;
+
+	/* Pause the current audio playback to avoid audible artifacts */
+	if ( SDL_SYS_CDPause(cdrom) < 0 ) {
+		return(-1);
+	}
+
+	/* Specify the AudioCD playback mode */
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kSetPlayMode;
+	cdpb.csParam.bytes[0] = false;			/* Repeat? */
+	cdpb.csParam.bytes[1] = kPlayModeSequential;	/* Play mode */
+	/* ¥¥¥ÊTreat as soft error, NEC Drive doesnt support this call ¥¥¥ */
+	PBControlSync((ParmBlkPtr) &cdpb);
+
+#if 1
+	/* Specify the end of audio playback */
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kAudioStop;
+	cdpb.csParam.words[0] = kBlockPosition;		/* Position Mode */
+	*(long *) (cdpb.csParam.words + 1) = start+length-1; /* Search Address */
+	if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+		SDL_SetError("PBControlSync() failed");
+		return(-1);
+	}
+
+	/* Specify the start of audio playback, and start it */
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kAudioPlay;
+	cdpb.csParam.words[0] = kBlockPosition;			/* Position Mode */
+	*(long *) (cdpb.csParam.words + 1) = start+1;	/* Search Address */
+	cdpb.csParam.words[3] = false;					/* Stop address? */
+	cdpb.csParam.words[4] = kStereoPlayMode;		/* Audio Play Mode */
+	if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+		SDL_SetError("PBControlSync() failed");
+		return(-1);
+	}
+#else
+	/* Specify the end of audio playback */
+	FRAMES_TO_MSF(start+length, &m, &s, &f);
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kAudioStop;
+	cdpb.csParam.words[0] = kTrackPosition;			/* Position Mode */
+	cdpb.csParam.words[1] = 0;						/* Search Address (hiword)*/
+	cdpb.csParam.words[2] = 						/* Search Address (loword)*/
+			SDL_SYS_ShortToBCD(cdrom->numtracks);	
+	if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+		SDL_SetError("PBControlSync() failed");
+		return(-1);
+	}
+
+	/* Specify the start of audio playback, and start it */
+	FRAMES_TO_MSF(start, &m, &s, &f);
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kAudioPlay;
+	cdpb.csParam.words[0] = kTrackPosition;			/* Position Mode */
+	cdpb.csParam.words[1] = 0;						/* Search Address (hiword)*/
+	cdpb.csParam.words[2] = SDL_SYS_ShortToBCD(1);	/* Search Address (loword)*/
+	cdpb.csParam.words[3] = false;					/* Stop address? */
+	cdpb.csParam.words[4] = kStereoPlayMode;		/* Audio Play Mode */
+	if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+		SDL_SetError("PBControlSync() failed");
+		return(-1);
+	}
+#endif
+
+	return(0);
+}
+
+/* Pause play */
+static int SDL_SYS_CDPause(SDL_CD *cdrom)
+{
+	CDCntrlParam cdpb;
+
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kAudioPause;
+	cdpb.csParam.words[0] = 0;	/* Pause/Continue Flag (hiword) */
+	cdpb.csParam.words[1] = 1;	/* Pause/Continue Flag (loword) */
+	if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+		SDL_SetError("PBControlSync() failed");
+		return(-1);
+	}
+	return(0);
+}
+
+/* Resume play */
+static int SDL_SYS_CDResume(SDL_CD *cdrom)
+{
+	CDCntrlParam cdpb;
+
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kAudioPause;
+	cdpb.csParam.words[0] = 0;	/* Pause/Continue Flag (hiword) */
+	cdpb.csParam.words[1] = 0;	/* Pause/Continue Flag (loword) */
+	if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+		SDL_SetError("PBControlSync() failed");
+		return(-1);
+	}
+	return(0);
+}
+
+/* Stop play */
+static int SDL_SYS_CDStop(SDL_CD *cdrom)
+{
+	CDCntrlParam cdpb;
+
+	memset(&cdpb, 0, sizeof(cdpb));
+	cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
+	cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+	cdpb.csCode = kAudioStop;
+	cdpb.csParam.words[0] = 0;		/* Position Mode */
+	cdpb.csParam.words[1] = 0;		/* Search Address (hiword) */
+	cdpb.csParam.words[2] = 0;		/* Search Address (loword) */
+	if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
+		SDL_SetError("PBControlSync() failed");
+		return(-1);
+	}
+	return(0);
+}
+
+/* Eject the CD-ROM */
+static int SDL_SYS_CDEject(SDL_CD *cdrom)
+{
+	Boolean	disk = false;
+	QHdr *driveQ = GetDrvQHdr();
+	DrvQEl *driveElem;
+	HParamBlockRec hpb;
+	ParamBlockRec cpb;
+
+	for ( driveElem = (DrvQEl *) driveQ->qHead; driveElem; driveElem = 
+			  (driveElem) ? ((DrvQEl *) driveElem->qLink) : 
+			  ((DrvQEl *) driveQ->qHead) ) {
+		if ( driveQ->qTail ) {
+			driveQ->qTail->qLink = 0;
+		}
+		if ( driveElem->dQRefNum != SDL_cdlist[cdrom->id].dRefNum ) {
+			continue;
+		}
+	
+		/* Does drive contain mounted volume? If not, skip */
+		memset(&hpb, 0, sizeof(hpb));
+		hpb.volumeParam.ioVRefNum = driveElem->dQDrive;
+		if ( PBHGetVInfoSync(&hpb) != noErr ) {
+			continue;
+		}
+		if ( (UnmountVol(0, driveElem->dQDrive) == noErr) && 
+		     (Eject(0, driveElem->dQDrive) == noErr) ) {
+			driveElem = 0; /* Clear pointer to reset our loop */
+			disk = true;
+		}
+	}
+
+	/* If no disk is present, just eject the tray */
+	if (! disk) {
+		memset(&cpb, 0, sizeof(cpb));
+		cpb.cntrlParam.ioVRefNum = 0; /* No Drive */
+		cpb.cntrlParam.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
+		cpb.cntrlParam.csCode = kEjectTheDisc;
+		if ( PBControlSync((ParmBlkPtr)&cpb) != noErr ) {
+			SDL_SetError("PBControlSync() failed");
+			return(-1);
+		}
+	}
+	return(0);
+}
+
+/* Close the CD-ROM handle */
+static void SDL_SYS_CDClose(SDL_CD *cdrom)
+{
+	return;
+}
+
+void SDL_SYS_CDQuit(void)
+{
+	while(SDL_numcds--) 
+		memset(SDL_cdlist + SDL_numcds, 0, sizeof(SDL_cdlist[0]));
+}
+