/* 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 */ /* Functions for system-level CD-ROM audio control */ #define INCL_MCIOS2 #include #include #include #include #include #include "SDL_error.h" #include "SDL_cdrom.h" #include "SDL_syscdrom.h" /* Size of MCI result buffer (in bytes) */ #define MCI_CMDRETBUFSIZE 128 /* The maximum number of CD-ROM drives we'll detect */ #define MAX_DRIVES 16 /* A list of available CD-ROM drives */ static char *SDL_cdlist[MAX_DRIVES]; //static dev_t SDL_cdmode[MAX_DRIVES]; /* 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); /* MCI Timing Functions */ #define MCI_MMTIMEPERSECOND 3000 #define FRAMESFROMMM(mmtime) (((mmtime)*CD_FPS)/MCI_MMTIMEPERSECOND) /* Ready for MCI CDAudio Devices */ int SDL_SYS_CDInit(void) { int i; /* generig counter */ MCI_SYSINFO_PARMS msp; /* Structure to MCI SysInfo parameters */ CHAR SysInfoRet[MCI_CMDRETBUFSIZE]; /* Buffer for MCI Command result */ /* 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; /* Get the number of CD ROMs in the System */ /* Clean SysInfo structure */ memset(&msp, 0x00, sizeof(MCI_SYSINFO_PARMS)); /* Prepare structure to Ask Numer of Audio CDs */ msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ if (LOUSHORT(mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_QUANTITY | MCI_WAIT, (PVOID)&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); SDL_numcds = atoi(SysInfoRet); if (SDL_numcds > MAX_DRIVES) SDL_numcds = MAX_DRIVES; /* Limit maximum CD number */ /* Get and Add their system name to the SDL_cdlist */ msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ for (i=0; istatus == CD_PLAYING || cdrom->status == CD_PAUSED) return 0; /* Get Number of Tracks */ msp.hwndCallback = (HWND)NULL; /* None */ msp.ulReturn = (ULONG)NULL; /* We want this information */ msp.ulItem = MCI_STATUS_NUMBER_OF_TRACKS; msp.ulValue = (ULONG)NULL; /* No additional information */ if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); cdrom->numtracks = msp.ulReturn; if ( cdrom->numtracks > SDL_MAX_TRACKS ) { cdrom->numtracks = SDL_MAX_TRACKS; } /* Alocate space for TOC data */ mtr = (MCI_TOC_REC *)malloc(cdrom->numtracks*sizeof(MCI_TOC_REC)); if ( mtr == NULL ) { SDL_OutOfMemory(); return(-1); } /* Get TOC from CD */ mtp.pBuf = mtr; mtp.ulBufSize = cdrom->numtracks*sizeof(MCI_TOC_REC); if (LOUSHORT(mciSendCommand(cdrom->id,MCI_GETTOC,MCI_WAIT,&mtp, 0)) != MCIERR_SUCCESS) { SDL_OutOfMemory(); free(mtr); return(CD_ERROR); } /* Fill SDL Tracks Structure */ for (i=0; inumtracks; i++) { /* Set Track ID */ cdrom->track[i].id = (mtr+i)->TrackNum; /* Set Track Type */ msp.hwndCallback = (HWND)NULL; /* None */ msp.ulReturn = (ULONG)NULL; /* We want this information */ msp.ulItem = MCI_CD_STATUS_TRACK_TYPE; msp.ulValue = (ULONG)((mtr+i)->TrackNum); /* Track Number? */ if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_TRACK | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) { free(mtr); return (CD_ERROR); } if (msp.ulReturn==MCI_CD_TRACK_AUDIO) cdrom->track[i].type = SDL_AUDIO_TRACK; else cdrom->track[i].type = SDL_DATA_TRACK; /* Set Track Length - values from MCI are in MMTIMEs - 3000 MMTIME = 1 second */ cdrom->track[i].length = FRAMESFROMMM((mtr+i)->ulEndAddr - (mtr+i)->ulStartAddr); /* Set Track Offset */ cdrom->track[i].offset = FRAMESFROMMM((mtr+i)->ulStartAddr); } free(mtr); return(0); } /* Get CD-ROM status - Ready for MCI */ static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) { CDstatus status; MCI_STATUS_PARMS msp; /* Get Status from MCI */ msp.hwndCallback = (HWND)NULL; /* None */ msp.ulReturn = (ULONG)NULL; /* We want this information */ msp.ulItem = MCI_STATUS_MODE; msp.ulValue = (ULONG)NULL; /* No additional information */ if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) status = CD_ERROR; else { switch(msp.ulReturn) { case MCI_MODE_NOT_READY: status = CD_TRAYEMPTY; break; case MCI_MODE_PAUSE: status = CD_PAUSED; break; case MCI_MODE_PLAY: status = CD_PLAYING; break; case MCI_MODE_STOP: status = CD_STOPPED; break; /* These cases should not occour */ case MCI_MODE_RECORD: case MCI_MODE_SEEK: default: status = CD_ERROR; break; } } /* Determine position */ if (position != NULL) /* The SDL $&$&%# CDROM call sends NULL pointer here! */ { if ((status == CD_PLAYING) || (status == CD_PAUSED)) { /* Get Position */ msp.hwndCallback = (HWND)NULL; /* None */ msp.ulReturn = (ULONG)NULL; /* We want this information */ msp.ulItem = MCI_STATUS_POSITION; msp.ulValue = (ULONG)NULL; /* No additiona info */ if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return (CD_ERROR); /* Convert from MSF (format selected in the Open process) to Frames (format that will be returned) */ *position = MSF_TO_FRAMES(MSF_MINUTE(msp.ulReturn),MSF_SECOND(msp.ulReturn),MSF_FRAME(msp.ulReturn)); } else *position = 0; } return(status); } /* Start play - Ready for MCI */ static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) { MCI_GENERIC_PARMS mgp; MCI_STATUS_PARMS msp; MCI_PLAY_PARMS mpp; ULONG min,sec,frm; /* Start MSF */ FRAMES_TO_MSF(start, &min, &sec, &frm); MSF_MINUTE(mpp.ulFrom) = min; MSF_SECOND(mpp.ulFrom) = sec; MSF_FRAME(mpp.ulFrom) = frm; /* End MSF */ FRAMES_TO_MSF(start+length, &min, &sec, &frm); MSF_MINUTE(mpp.ulTo) = min; MSF_SECOND(mpp.ulTo) = sec; MSF_FRAME(mpp.ulTo) = frm; #ifdef DEBUG_CDROM fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); #endif /* Verifies if it is paused first... and if it is, unpause before stopping it. */ msp.hwndCallback = (HWND)NULL; /* None */ msp.ulReturn = (ULONG)NULL; /* We want this information */ msp.ulItem = MCI_STATUS_MODE; msp.ulValue = (ULONG)NULL; /* No additional information */ if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS) { if (msp.ulReturn == MCI_MODE_PAUSE) { mgp.hwndCallback = (HWND)NULL; // None mciSendCommand(cdrom->id,MCI_RESUME,NULL,&mgp, 0); } } /* Now play it. */ mpp.hwndCallback = (HWND)NULL; // We do not want the info. temp if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PLAY,MCI_FROM | MCI_TO,&mpp, 0)) == MCIERR_SUCCESS) return 0; return (CD_ERROR); } /* Pause play - Ready for MCI */ static int SDL_SYS_CDPause(SDL_CD *cdrom) { MCI_GENERIC_PARMS mgp; mgp.hwndCallback = (HWND)NULL; // None if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PAUSE,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; return(CD_ERROR); } /* Resume play - Ready for MCI */ static int SDL_SYS_CDResume(SDL_CD *cdrom) { MCI_GENERIC_PARMS mgp; mgp.hwndCallback = (HWND)NULL; // None if (LOUSHORT(mciSendCommand(cdrom->id,MCI_RESUME,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; return(CD_ERROR); } /* Stop play - Ready for MCI */ static int SDL_SYS_CDStop(SDL_CD *cdrom) { MCI_GENERIC_PARMS mgp; MCI_STATUS_PARMS msp; /* Verifies if it is paused first... and if it is, unpause before stopping it. */ msp.hwndCallback = (HWND)NULL; /* None */ msp.ulReturn = (ULONG)NULL; /* We want this information */ msp.ulItem = MCI_STATUS_MODE; msp.ulValue = (ULONG)NULL; /* No additional information */ if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS) { if (msp.ulReturn == MCI_MODE_PAUSE) { mgp.hwndCallback = (HWND)NULL; // None mciSendCommand(cdrom->id,MCI_RESUME,NULL,&mgp, 0); } } /* Now stops the media */ mgp.hwndCallback = (HWND)NULL; // None if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STOP,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; return(CD_ERROR); } /* Eject the CD-ROM - Ready for MCI */ static int SDL_SYS_CDEject(SDL_CD *cdrom) { MCI_SET_PARMS msp; msp.hwndCallback = (HWND)NULL; // None msp.ulTimeFormat = (ULONG)NULL; // No change msp.ulSpeedFormat = (ULONG)NULL; // No change msp.ulAudio = (ULONG)NULL; // No Channel msp.ulLevel = (ULONG)NULL; // No Volume msp.ulOver = (ULONG)NULL; // No Delay msp.ulItem = (ULONG)NULL; // No item msp.ulValue = (ULONG)NULL; // No value for item flag if (LOUSHORT(mciSendCommand(cdrom->id,MCI_SET,MCI_WAIT | MCI_SET_DOOR_OPEN,&msp, 0)) == MCIERR_SUCCESS) return 0; return(CD_ERROR); } /* Close the CD-ROM handle - Ready for MCI */ static void SDL_SYS_CDClose(SDL_CD *cdrom) { MCI_GENERIC_PARMS mgp; mgp.hwndCallback = (HWND)NULL; // None mciSendCommand(cdrom->id,MCI_CLOSE,MCI_WAIT,&mgp, 0); } /* Finalize CDROM Subsystem - Ready for MCI */ void SDL_SYS_CDQuit(void) { int i; if ( SDL_numcds > 0 ) { for ( i=0; i