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