e14743d1 |
1 | /* |
2 | SDL - Simple DirectMedia Layer |
3 | Copyright (C) 1997-2009 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 | #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 | } |