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