src/cdrom/SDL_cdrom.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 14 Dec 2001 13:13:20 +0000
changeset 254 4fc12b8edf74
parent 252 e8157fcb3114
child 297 f6ffac90895c
permissions -rw-r--r--
*** empty log message ***
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 /* This is the CD-audio control API for Simple DirectMedia Layer */
    29 
    30 #include <stdio.h>
    31 #include <stdlib.h>
    32 #include <string.h>
    33 
    34 #include "SDL_error.h"
    35 #include "SDL_cdrom.h"
    36 #include "SDL_syscdrom.h"
    37 
    38 #if !defined(macintosh)
    39 #define CLIP_FRAMES	10	/* Some CD-ROMs won't go all the way */
    40 #endif
    41 
    42 static int SDL_cdinitted = 0;
    43 static SDL_CD *default_cdrom;
    44 
    45 /* The system level CD-ROM control functions */
    46 struct CDcaps SDL_CDcaps = {
    47 	NULL,					/* Name */
    48 	NULL,					/* Open */
    49 	NULL,					/* GetTOC */
    50 	NULL,					/* Status */
    51 	NULL,					/* Play */
    52 	NULL,					/* Pause */
    53 	NULL,					/* Resume */
    54 	NULL,					/* Stop */
    55 	NULL,					/* Eject */
    56 	NULL,					/* Close */
    57 };
    58 int SDL_numcds;
    59 
    60 int SDL_CDROMInit(void)
    61 {
    62 	int retval;
    63 
    64 	SDL_numcds = 0;
    65 	retval = SDL_SYS_CDInit();
    66 	if ( retval == 0 ) {
    67 		SDL_cdinitted = 1;
    68 	}
    69 	default_cdrom = NULL;
    70 	return(retval);
    71 }
    72 
    73 /* Check to see if the CD-ROM subsystem has been initialized */
    74 static int CheckInit(int check_cdrom, SDL_CD **cdrom)
    75 {
    76 	int okay;
    77 
    78 	okay = SDL_cdinitted;
    79 	if ( check_cdrom && (*cdrom == NULL) ) {
    80 		*cdrom = default_cdrom;
    81 		if ( *cdrom == NULL ) {
    82 			SDL_SetError("CD-ROM not opened");
    83 			okay = 0;
    84 		}
    85 	}
    86 	if ( ! SDL_cdinitted ) {
    87 		SDL_SetError("CD-ROM subsystem not initialized");
    88 	}
    89 	return(okay);
    90 }
    91 
    92 int SDL_CDNumDrives(void)
    93 {
    94 	if ( ! CheckInit(0, NULL) ) {
    95 		return(-1);
    96 	}
    97 	return(SDL_numcds);
    98 }
    99 
   100 const char *SDL_CDName(int drive)
   101 {
   102 	if ( ! CheckInit(0, NULL) ) {
   103 		return(NULL);
   104 	}
   105 	if ( drive >= SDL_numcds ) {
   106 		SDL_SetError("Invalid CD-ROM drive index");
   107 		return(NULL);
   108 	}
   109 	if ( SDL_CDcaps.Name ) {
   110 		return(SDL_CDcaps.Name(drive));
   111 	} else {
   112 		return("");
   113 	}
   114 }
   115 
   116 SDL_CD *SDL_CDOpen(int drive)
   117 {
   118 	struct SDL_CD *cdrom;
   119 
   120 	if ( ! CheckInit(0, NULL) ) {
   121 		return(NULL);
   122 	}
   123 	if ( drive >= SDL_numcds ) {
   124 		SDL_SetError("Invalid CD-ROM drive index");
   125 		return(NULL);
   126 	}
   127 	cdrom = (SDL_CD *)malloc(sizeof(*cdrom));
   128 	if ( cdrom == NULL ) {
   129 		SDL_OutOfMemory();
   130 		return(NULL);
   131 	}
   132 	memset(cdrom, 0, sizeof(*cdrom));
   133 	cdrom->id = SDL_CDcaps.Open(drive);
   134 	if ( cdrom->id < 0 ) {
   135 		free(cdrom);
   136 		return(NULL);
   137 	}
   138 	default_cdrom = cdrom;
   139 	return(cdrom);
   140 }
   141 
   142 CDstatus SDL_CDStatus(SDL_CD *cdrom)
   143 {
   144 	CDstatus status;
   145 	int i;
   146 	Uint32 position;
   147 
   148 	/* Check if the CD-ROM subsystem has been initialized */
   149 	if ( ! CheckInit(1, &cdrom) ) {
   150 		return(CD_ERROR);
   151 	}
   152 
   153 	/* Get the current status of the drive */
   154 	cdrom->numtracks = 0;
   155 	cdrom->cur_track = 0;
   156 	cdrom->cur_frame = 0;
   157 	status = SDL_CDcaps.Status(cdrom, &i);
   158 	position = (Uint32)i;
   159 	cdrom->status = status;
   160 
   161 	/* Get the table of contents, if there's a CD available */
   162 	if ( CD_INDRIVE(status) ) {
   163 		if ( SDL_CDcaps.GetTOC(cdrom) < 0 ) {
   164 			status = CD_ERROR;
   165 		}
   166 		/* If the drive is playing, get current play position */
   167 		if ( (status == CD_PLAYING) || (status == CD_PAUSED) ) {
   168 			for ( i=1; cdrom->track[i].offset <= position; ++i ) {
   169 				/* Keep looking */;
   170 			}
   171 #ifdef DEBUG_CDROM
   172   fprintf(stderr, "Current position: %d, track = %d (offset is %d)\n",
   173 				position, i-1, cdrom->track[i-1].offset);
   174 #endif
   175 			cdrom->cur_track = i-1;
   176 			position -= cdrom->track[cdrom->cur_track].offset;
   177 			cdrom->cur_frame = position;
   178 		}
   179 	}
   180 	return(status);
   181 }
   182 
   183 int SDL_CDPlayTracks(SDL_CD *cdrom,
   184 			int strack, int sframe, int ntracks, int nframes)
   185 {
   186 	int etrack, eframe;
   187 	int start, length;
   188 
   189 	/* Check if the CD-ROM subsystem has been initialized */
   190 	if ( ! CheckInit(1, &cdrom) ) {
   191 		return(CD_ERROR);
   192 	}
   193 
   194 	/* Determine the starting and ending tracks */
   195 	if ( (strack < 0) || (strack >= cdrom->numtracks) ) {
   196 		SDL_SetError("Invalid starting track");
   197 		return(CD_ERROR);
   198 	}
   199 	if ( ! ntracks && ! nframes ) {
   200 		etrack = cdrom->numtracks;
   201 		eframe = 0;
   202 	} else {
   203 		etrack = strack+ntracks;
   204 		if ( etrack == strack ) {
   205 			eframe = sframe + nframes;
   206 		} else {
   207 			eframe = nframes;
   208 		}
   209 	}
   210 	if ( etrack > cdrom->numtracks ) {
   211 		SDL_SetError("Invalid play length");
   212 		return(CD_ERROR);
   213 	}
   214 
   215 	/* Skip data tracks and verify frame offsets */
   216 	while ( (strack <= etrack) &&
   217 			(cdrom->track[strack].type == SDL_DATA_TRACK) ) {
   218 		++strack;
   219 	}
   220 	if ( sframe >= (int)cdrom->track[strack].length ) {
   221 		SDL_SetError("Invalid starting frame for track %d", strack);
   222 		return(CD_ERROR);
   223 	}
   224 	while ( (etrack > strack) &&
   225 			(cdrom->track[etrack-1].type == SDL_DATA_TRACK) ) {
   226 		--etrack;
   227 	}
   228 	if ( eframe > (int)cdrom->track[etrack].length ) {
   229 		SDL_SetError("Invalid ending frame for track %d", etrack);
   230 		return(CD_ERROR);
   231 	}
   232 
   233 	/* Determine start frame and play length */
   234 	start = (cdrom->track[strack].offset+sframe);
   235 	length = (cdrom->track[etrack].offset+eframe)-start;
   236 #ifdef CLIP_FRAMES
   237 	/* I've never seen this necessary, but xmcd does it.. */
   238 	length -= CLIP_FRAMES;	/* CLIP_FRAMES == 10 */
   239 #endif
   240 	if ( length < 0 ) {
   241 		return(0);
   242 	}
   243 
   244 	/* Play! */
   245 #ifdef DEBUG_CDROM
   246   fprintf(stderr, "Playing %d frames at offset %d\n", length, start);
   247 #endif
   248 	return(SDL_CDcaps.Play(cdrom, start, length));
   249 }
   250 
   251 int SDL_CDPlay(SDL_CD *cdrom, int sframe, int length)
   252 {
   253 	/* Check if the CD-ROM subsystem has been initialized */
   254 	if ( ! CheckInit(1, &cdrom) ) {
   255 		return(CD_ERROR);
   256 	}
   257 
   258 	return(SDL_CDcaps.Play(cdrom, sframe, length));
   259 }
   260 
   261 int SDL_CDPause(SDL_CD *cdrom)
   262 {
   263 	CDstatus status;
   264 	int retval;
   265 
   266 	/* Check if the CD-ROM subsystem has been initialized */
   267 	if ( ! CheckInit(1, &cdrom) ) {
   268 		return(CD_ERROR);
   269 	}
   270 
   271 	status = SDL_CDcaps.Status(cdrom, NULL);
   272 	switch (status) {
   273 		case CD_PLAYING:
   274 			retval = SDL_CDcaps.Pause(cdrom);
   275 			break;
   276 		default:
   277 			retval = 0;
   278 			break;
   279 	}
   280 	return(retval);
   281 }
   282 
   283 int SDL_CDResume(SDL_CD *cdrom)
   284 {
   285 	CDstatus status;
   286 	int retval;
   287 
   288 	/* Check if the CD-ROM subsystem has been initialized */
   289 	if ( ! CheckInit(1, &cdrom) ) {
   290 		return(CD_ERROR);
   291 	}
   292 
   293 	status = SDL_CDcaps.Status(cdrom, NULL);
   294 	switch (status) {
   295 		case CD_PAUSED:
   296 			retval = SDL_CDcaps.Resume(cdrom);
   297 		default:
   298 			retval = 0;
   299 			break;
   300 	}
   301 	return(retval);
   302 }
   303 
   304 int SDL_CDStop(SDL_CD *cdrom)
   305 {
   306 	CDstatus status;
   307 	int retval;
   308 
   309 	/* Check if the CD-ROM subsystem has been initialized */
   310 	if ( ! CheckInit(1, &cdrom) ) {
   311 		return(CD_ERROR);
   312 	}
   313 
   314 	status = SDL_CDcaps.Status(cdrom, NULL);
   315 	switch (status) {
   316 		case CD_PLAYING:
   317 		case CD_PAUSED:
   318 			retval = SDL_CDcaps.Stop(cdrom);
   319 		default:
   320 			retval = 0;
   321 			break;
   322 	}
   323 	return(retval);
   324 }
   325 
   326 int SDL_CDEject(SDL_CD *cdrom)
   327 {
   328 	/* Check if the CD-ROM subsystem has been initialized */
   329 	if ( ! CheckInit(1, &cdrom) ) {
   330 		return(CD_ERROR);
   331 	}
   332 	return(SDL_CDcaps.Eject(cdrom));
   333 }
   334 
   335 void SDL_CDClose(SDL_CD *cdrom)
   336 {
   337 	/* Check if the CD-ROM subsystem has been initialized */
   338 	if ( ! CheckInit(1, &cdrom) ) {
   339 		return;
   340 	}
   341 	SDL_CDcaps.Close(cdrom);
   342 	free(cdrom);
   343 	default_cdrom = NULL;
   344 }
   345 
   346 void SDL_CDROMQuit(void)
   347 {
   348 	SDL_SYS_CDQuit();
   349 	SDL_cdinitted = 0;
   350 }