/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2006 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org */ #include "SDL_config.h" /* This is the CD-audio control API for Simple DirectMedia Layer */ #include "SDL_cdrom.h" #include "SDL_syscdrom.h" #define CLIP_FRAMES 10 /* Some CD-ROMs won't go all the way */ static int SDL_cdinitted = 0; static SDL_CD *default_cdrom; /* The system level CD-ROM control functions */ struct CDcaps SDL_CDcaps = { NULL, /* Name */ NULL, /* Open */ NULL, /* GetTOC */ NULL, /* Status */ NULL, /* Play */ NULL, /* Pause */ NULL, /* Resume */ NULL, /* Stop */ NULL, /* Eject */ NULL, /* Close */ }; int SDL_numcds; int SDL_CDROMInit(void) { int retval; SDL_numcds = 0; retval = SDL_SYS_CDInit(); if (retval == 0) { SDL_cdinitted = 1; } default_cdrom = NULL; return (retval); } /* Check to see if the CD-ROM subsystem has been initialized */ static int CheckInit(int check_cdrom, SDL_CD ** cdrom) { int okay; okay = SDL_cdinitted; if (check_cdrom && (*cdrom == NULL)) { *cdrom = default_cdrom; if (*cdrom == NULL) { SDL_SetError("CD-ROM not opened"); okay = 0; } } if (!SDL_cdinitted) { SDL_SetError("CD-ROM subsystem not initialized"); } return (okay); } int SDL_CDNumDrives(void) { if (!CheckInit(0, NULL)) { return (-1); } return (SDL_numcds); } const char * SDL_CDName(int drive) { if (!CheckInit(0, NULL)) { return (NULL); } if (drive >= SDL_numcds) { SDL_SetError("Invalid CD-ROM drive index"); return (NULL); } if (SDL_CDcaps.Name) { return (SDL_CDcaps.Name(drive)); } else { return (""); } } SDL_CD * SDL_CDOpen(int drive) { struct SDL_CD *cdrom; if (!CheckInit(0, NULL)) { return (NULL); } if (drive >= SDL_numcds) { SDL_SetError("Invalid CD-ROM drive index"); return (NULL); } cdrom = (SDL_CD *) SDL_malloc(sizeof(*cdrom)); if (cdrom == NULL) { SDL_OutOfMemory(); return (NULL); } SDL_memset(cdrom, 0, sizeof(*cdrom)); cdrom->id = SDL_CDcaps.Open(drive); if (cdrom->id < 0) { SDL_free(cdrom); return (NULL); } default_cdrom = cdrom; return (cdrom); } CDstatus SDL_CDStatus(SDL_CD * cdrom) { CDstatus status; int i; Uint32 position; /* Check if the CD-ROM subsystem has been initialized */ if (!CheckInit(1, &cdrom)) { return (CD_ERROR); } /* Get the current status of the drive */ cdrom->numtracks = 0; cdrom->cur_track = 0; cdrom->cur_frame = 0; status = SDL_CDcaps.Status(cdrom, &i); position = (Uint32) i; cdrom->status = status; /* Get the table of contents, if there's a CD available */ if (CD_INDRIVE(status)) { if (SDL_CDcaps.GetTOC(cdrom) < 0) { status = CD_ERROR; } /* If the drive is playing, get current play position */ if ((status == CD_PLAYING) || (status == CD_PAUSED)) { for (i = 1; cdrom->track[i].offset <= position; ++i) { /* Keep looking */ ; } #ifdef DEBUG_CDROM fprintf(stderr, "Current position: %d, track = %d (offset is %d)\n", position, i - 1, cdrom->track[i - 1].offset); #endif cdrom->cur_track = i - 1; position -= cdrom->track[cdrom->cur_track].offset; cdrom->cur_frame = position; } } return (status); } int SDL_CDPlayTracks(SDL_CD * cdrom, int strack, int sframe, int ntracks, int nframes) { int etrack, eframe; int start, length; /* Check if the CD-ROM subsystem has been initialized */ if (!CheckInit(1, &cdrom)) { return (CD_ERROR); } /* Determine the starting and ending tracks */ if ((strack < 0) || (strack >= cdrom->numtracks)) { SDL_SetError("Invalid starting track"); return (CD_ERROR); } if (!ntracks && !nframes) { etrack = cdrom->numtracks; eframe = 0; } else { etrack = strack + ntracks; if (etrack == strack) { eframe = sframe + nframes; } else { eframe = nframes; } } if (etrack > cdrom->numtracks) { SDL_SetError("Invalid play length"); return (CD_ERROR); } /* Skip data tracks and verify frame offsets */ while ((strack <= etrack) && (cdrom->track[strack].type == SDL_DATA_TRACK)) { ++strack; } if (sframe >= (int) cdrom->track[strack].length) { SDL_SetError("Invalid starting frame for track %d", strack); return (CD_ERROR); } while ((etrack > strack) && (cdrom->track[etrack - 1].type == SDL_DATA_TRACK)) { --etrack; } if (eframe > (int) cdrom->track[etrack].length) { SDL_SetError("Invalid ending frame for track %d", etrack); return (CD_ERROR); } /* Determine start frame and play length */ start = (cdrom->track[strack].offset + sframe); length = (cdrom->track[etrack].offset + eframe) - start; #ifdef CLIP_FRAMES /* I've never seen this necessary, but xmcd does it.. */ length -= CLIP_FRAMES; /* CLIP_FRAMES == 10 */ #endif if (length < 0) { return (0); } /* Play! */ #ifdef DEBUG_CDROM fprintf(stderr, "Playing %d frames at offset %d\n", length, start); #endif return (SDL_CDcaps.Play(cdrom, start, length)); } int SDL_CDPlay(SDL_CD * cdrom, int sframe, int length) { /* Check if the CD-ROM subsystem has been initialized */ if (!CheckInit(1, &cdrom)) { return (CD_ERROR); } return (SDL_CDcaps.Play(cdrom, sframe, length)); } int SDL_CDPause(SDL_CD * cdrom) { CDstatus status; int retval; /* Check if the CD-ROM subsystem has been initialized */ if (!CheckInit(1, &cdrom)) { return (CD_ERROR); } status = SDL_CDcaps.Status(cdrom, NULL); switch (status) { case CD_PLAYING: retval = SDL_CDcaps.Pause(cdrom); break; default: retval = 0; break; } return (retval); } int SDL_CDResume(SDL_CD * cdrom) { CDstatus status; int retval; /* Check if the CD-ROM subsystem has been initialized */ if (!CheckInit(1, &cdrom)) { return (CD_ERROR); } status = SDL_CDcaps.Status(cdrom, NULL); switch (status) { case CD_PAUSED: retval = SDL_CDcaps.Resume(cdrom); default: retval = 0; break; } return (retval); } int SDL_CDStop(SDL_CD * cdrom) { CDstatus status; int retval; /* Check if the CD-ROM subsystem has been initialized */ if (!CheckInit(1, &cdrom)) { return (CD_ERROR); } status = SDL_CDcaps.Status(cdrom, NULL); switch (status) { case CD_PLAYING: case CD_PAUSED: retval = SDL_CDcaps.Stop(cdrom); default: retval = 0; break; } return (retval); } int SDL_CDEject(SDL_CD * cdrom) { /* Check if the CD-ROM subsystem has been initialized */ if (!CheckInit(1, &cdrom)) { return (CD_ERROR); } return (SDL_CDcaps.Eject(cdrom)); } void SDL_CDClose(SDL_CD * cdrom) { /* Check if the CD-ROM subsystem has been initialized */ if (!CheckInit(1, &cdrom)) { return; } SDL_CDcaps.Close(cdrom); SDL_free(cdrom); default_cdrom = NULL; } void SDL_CDROMQuit(void) { SDL_SYS_CDQuit(); SDL_cdinitted = 0; } /* vi: set ts=4 sw=4 expandtab: */