|
1 /* CD module -- interface to Mark Callow's and Roger Chickering's */ |
|
2 /* CD Audio Library (CD). */ |
|
3 |
|
4 #include <sys/types.h> |
|
5 #include <cdaudio.h> |
|
6 #include "Python.h" |
|
7 |
|
8 #define NCALLBACKS 8 |
|
9 |
|
10 typedef struct { |
|
11 PyObject_HEAD |
|
12 CDPLAYER *ob_cdplayer; |
|
13 } cdplayerobject; |
|
14 |
|
15 static PyObject *CdError; /* exception cd.error */ |
|
16 |
|
17 static PyObject * |
|
18 CD_allowremoval(cdplayerobject *self, PyObject *args) |
|
19 { |
|
20 if (!PyArg_ParseTuple(args, ":allowremoval")) |
|
21 return NULL; |
|
22 |
|
23 CDallowremoval(self->ob_cdplayer); |
|
24 |
|
25 Py_INCREF(Py_None); |
|
26 return Py_None; |
|
27 } |
|
28 |
|
29 static PyObject * |
|
30 CD_preventremoval(cdplayerobject *self, PyObject *args) |
|
31 { |
|
32 if (!PyArg_ParseTuple(args, ":preventremoval")) |
|
33 return NULL; |
|
34 |
|
35 CDpreventremoval(self->ob_cdplayer); |
|
36 |
|
37 Py_INCREF(Py_None); |
|
38 return Py_None; |
|
39 } |
|
40 |
|
41 static PyObject * |
|
42 CD_bestreadsize(cdplayerobject *self, PyObject *args) |
|
43 { |
|
44 if (!PyArg_ParseTuple(args, ":bestreadsize")) |
|
45 return NULL; |
|
46 |
|
47 return PyInt_FromLong((long) CDbestreadsize(self->ob_cdplayer)); |
|
48 } |
|
49 |
|
50 static PyObject * |
|
51 CD_close(cdplayerobject *self, PyObject *args) |
|
52 { |
|
53 if (!PyArg_ParseTuple(args, ":close")) |
|
54 return NULL; |
|
55 |
|
56 if (!CDclose(self->ob_cdplayer)) { |
|
57 PyErr_SetFromErrno(CdError); /* XXX - ??? */ |
|
58 return NULL; |
|
59 } |
|
60 self->ob_cdplayer = NULL; |
|
61 |
|
62 Py_INCREF(Py_None); |
|
63 return Py_None; |
|
64 } |
|
65 |
|
66 static PyObject * |
|
67 CD_eject(cdplayerobject *self, PyObject *args) |
|
68 { |
|
69 CDSTATUS status; |
|
70 |
|
71 if (!PyArg_ParseTuple(args, ":eject")) |
|
72 return NULL; |
|
73 |
|
74 if (!CDeject(self->ob_cdplayer)) { |
|
75 if (CDgetstatus(self->ob_cdplayer, &status) && |
|
76 status.state == CD_NODISC) |
|
77 PyErr_SetString(CdError, "no disc in player"); |
|
78 else |
|
79 PyErr_SetString(CdError, "eject failed"); |
|
80 return NULL; |
|
81 } |
|
82 |
|
83 Py_INCREF(Py_None); |
|
84 return Py_None; |
|
85 } |
|
86 |
|
87 static PyObject * |
|
88 CD_getstatus(cdplayerobject *self, PyObject *args) |
|
89 { |
|
90 CDSTATUS status; |
|
91 |
|
92 if (!PyArg_ParseTuple(args, ":getstatus")) |
|
93 return NULL; |
|
94 |
|
95 if (!CDgetstatus(self->ob_cdplayer, &status)) { |
|
96 PyErr_SetFromErrno(CdError); /* XXX - ??? */ |
|
97 return NULL; |
|
98 } |
|
99 |
|
100 return Py_BuildValue("(ii(iii)(iii)(iii)iiii)", status.state, |
|
101 status.track, status.min, status.sec, status.frame, |
|
102 status.abs_min, status.abs_sec, status.abs_frame, |
|
103 status.total_min, status.total_sec, status.total_frame, |
|
104 status.first, status.last, status.scsi_audio, |
|
105 status.cur_block); |
|
106 } |
|
107 |
|
108 static PyObject * |
|
109 CD_gettrackinfo(cdplayerobject *self, PyObject *args) |
|
110 { |
|
111 int track; |
|
112 CDTRACKINFO info; |
|
113 CDSTATUS status; |
|
114 |
|
115 if (!PyArg_ParseTuple(args, "i:gettrackinfo", &track)) |
|
116 return NULL; |
|
117 |
|
118 if (!CDgettrackinfo(self->ob_cdplayer, track, &info)) { |
|
119 if (CDgetstatus(self->ob_cdplayer, &status) && |
|
120 status.state == CD_NODISC) |
|
121 PyErr_SetString(CdError, "no disc in player"); |
|
122 else |
|
123 PyErr_SetString(CdError, "gettrackinfo failed"); |
|
124 return NULL; |
|
125 } |
|
126 |
|
127 return Py_BuildValue("((iii)(iii))", |
|
128 info.start_min, info.start_sec, info.start_frame, |
|
129 info.total_min, info.total_sec, info.total_frame); |
|
130 } |
|
131 |
|
132 static PyObject * |
|
133 CD_msftoblock(cdplayerobject *self, PyObject *args) |
|
134 { |
|
135 int min, sec, frame; |
|
136 |
|
137 if (!PyArg_ParseTuple(args, "iii:msftoblock", &min, &sec, &frame)) |
|
138 return NULL; |
|
139 |
|
140 return PyInt_FromLong((long) CDmsftoblock(self->ob_cdplayer, |
|
141 min, sec, frame)); |
|
142 } |
|
143 |
|
144 static PyObject * |
|
145 CD_play(cdplayerobject *self, PyObject *args) |
|
146 { |
|
147 int start, play; |
|
148 CDSTATUS status; |
|
149 |
|
150 if (!PyArg_ParseTuple(args, "ii:play", &start, &play)) |
|
151 return NULL; |
|
152 |
|
153 if (!CDplay(self->ob_cdplayer, start, play)) { |
|
154 if (CDgetstatus(self->ob_cdplayer, &status) && |
|
155 status.state == CD_NODISC) |
|
156 PyErr_SetString(CdError, "no disc in player"); |
|
157 else |
|
158 PyErr_SetString(CdError, "play failed"); |
|
159 return NULL; |
|
160 } |
|
161 |
|
162 Py_INCREF(Py_None); |
|
163 return Py_None; |
|
164 } |
|
165 |
|
166 static PyObject * |
|
167 CD_playabs(cdplayerobject *self, PyObject *args) |
|
168 { |
|
169 int min, sec, frame, play; |
|
170 CDSTATUS status; |
|
171 |
|
172 if (!PyArg_ParseTuple(args, "iiii:playabs", &min, &sec, &frame, &play)) |
|
173 return NULL; |
|
174 |
|
175 if (!CDplayabs(self->ob_cdplayer, min, sec, frame, play)) { |
|
176 if (CDgetstatus(self->ob_cdplayer, &status) && |
|
177 status.state == CD_NODISC) |
|
178 PyErr_SetString(CdError, "no disc in player"); |
|
179 else |
|
180 PyErr_SetString(CdError, "playabs failed"); |
|
181 return NULL; |
|
182 } |
|
183 |
|
184 Py_INCREF(Py_None); |
|
185 return Py_None; |
|
186 } |
|
187 |
|
188 static PyObject * |
|
189 CD_playtrack(cdplayerobject *self, PyObject *args) |
|
190 { |
|
191 int start, play; |
|
192 CDSTATUS status; |
|
193 |
|
194 if (!PyArg_ParseTuple(args, "ii:playtrack", &start, &play)) |
|
195 return NULL; |
|
196 |
|
197 if (!CDplaytrack(self->ob_cdplayer, start, play)) { |
|
198 if (CDgetstatus(self->ob_cdplayer, &status) && |
|
199 status.state == CD_NODISC) |
|
200 PyErr_SetString(CdError, "no disc in player"); |
|
201 else |
|
202 PyErr_SetString(CdError, "playtrack failed"); |
|
203 return NULL; |
|
204 } |
|
205 |
|
206 Py_INCREF(Py_None); |
|
207 return Py_None; |
|
208 } |
|
209 |
|
210 static PyObject * |
|
211 CD_playtrackabs(cdplayerobject *self, PyObject *args) |
|
212 { |
|
213 int track, min, sec, frame, play; |
|
214 CDSTATUS status; |
|
215 |
|
216 if (!PyArg_ParseTuple(args, "iiiii:playtrackabs", &track, &min, &sec, |
|
217 &frame, &play)) |
|
218 return NULL; |
|
219 |
|
220 if (!CDplaytrackabs(self->ob_cdplayer, track, min, sec, frame, play)) { |
|
221 if (CDgetstatus(self->ob_cdplayer, &status) && |
|
222 status.state == CD_NODISC) |
|
223 PyErr_SetString(CdError, "no disc in player"); |
|
224 else |
|
225 PyErr_SetString(CdError, "playtrackabs failed"); |
|
226 return NULL; |
|
227 } |
|
228 |
|
229 Py_INCREF(Py_None); |
|
230 return Py_None; |
|
231 } |
|
232 |
|
233 static PyObject * |
|
234 CD_readda(cdplayerobject *self, PyObject *args) |
|
235 { |
|
236 int numframes, n; |
|
237 PyObject *result; |
|
238 |
|
239 if (!PyArg_ParseTuple(args, "i:readda", &numframes)) |
|
240 return NULL; |
|
241 |
|
242 result = PyString_FromStringAndSize(NULL, numframes * sizeof(CDFRAME)); |
|
243 if (result == NULL) |
|
244 return NULL; |
|
245 |
|
246 n = CDreadda(self->ob_cdplayer, |
|
247 (CDFRAME *) PyString_AsString(result), numframes); |
|
248 if (n == -1) { |
|
249 Py_DECREF(result); |
|
250 PyErr_SetFromErrno(CdError); |
|
251 return NULL; |
|
252 } |
|
253 if (n < numframes) |
|
254 _PyString_Resize(&result, n * sizeof(CDFRAME)); |
|
255 |
|
256 return result; |
|
257 } |
|
258 |
|
259 static PyObject * |
|
260 CD_seek(cdplayerobject *self, PyObject *args) |
|
261 { |
|
262 int min, sec, frame; |
|
263 long PyTryBlock; |
|
264 |
|
265 if (!PyArg_ParseTuple(args, "iii:seek", &min, &sec, &frame)) |
|
266 return NULL; |
|
267 |
|
268 PyTryBlock = CDseek(self->ob_cdplayer, min, sec, frame); |
|
269 if (PyTryBlock == -1) { |
|
270 PyErr_SetFromErrno(CdError); |
|
271 return NULL; |
|
272 } |
|
273 |
|
274 return PyInt_FromLong(PyTryBlock); |
|
275 } |
|
276 |
|
277 static PyObject * |
|
278 CD_seektrack(cdplayerobject *self, PyObject *args) |
|
279 { |
|
280 int track; |
|
281 long PyTryBlock; |
|
282 |
|
283 if (!PyArg_ParseTuple(args, "i:seektrack", &track)) |
|
284 return NULL; |
|
285 |
|
286 PyTryBlock = CDseektrack(self->ob_cdplayer, track); |
|
287 if (PyTryBlock == -1) { |
|
288 PyErr_SetFromErrno(CdError); |
|
289 return NULL; |
|
290 } |
|
291 |
|
292 return PyInt_FromLong(PyTryBlock); |
|
293 } |
|
294 |
|
295 static PyObject * |
|
296 CD_seekblock(cdplayerobject *self, PyObject *args) |
|
297 { |
|
298 unsigned long PyTryBlock; |
|
299 |
|
300 if (!PyArg_ParseTuple(args, "l:seekblock", &PyTryBlock)) |
|
301 return NULL; |
|
302 |
|
303 PyTryBlock = CDseekblock(self->ob_cdplayer, PyTryBlock); |
|
304 if (PyTryBlock == (unsigned long) -1) { |
|
305 PyErr_SetFromErrno(CdError); |
|
306 return NULL; |
|
307 } |
|
308 |
|
309 return PyInt_FromLong(PyTryBlock); |
|
310 } |
|
311 |
|
312 static PyObject * |
|
313 CD_stop(cdplayerobject *self, PyObject *args) |
|
314 { |
|
315 CDSTATUS status; |
|
316 |
|
317 if (!PyArg_ParseTuple(args, ":stop")) |
|
318 return NULL; |
|
319 |
|
320 if (!CDstop(self->ob_cdplayer)) { |
|
321 if (CDgetstatus(self->ob_cdplayer, &status) && |
|
322 status.state == CD_NODISC) |
|
323 PyErr_SetString(CdError, "no disc in player"); |
|
324 else |
|
325 PyErr_SetString(CdError, "stop failed"); |
|
326 return NULL; |
|
327 } |
|
328 |
|
329 Py_INCREF(Py_None); |
|
330 return Py_None; |
|
331 } |
|
332 |
|
333 static PyObject * |
|
334 CD_togglepause(cdplayerobject *self, PyObject *args) |
|
335 { |
|
336 CDSTATUS status; |
|
337 |
|
338 if (!PyArg_ParseTuple(args, ":togglepause")) |
|
339 return NULL; |
|
340 |
|
341 if (!CDtogglepause(self->ob_cdplayer)) { |
|
342 if (CDgetstatus(self->ob_cdplayer, &status) && |
|
343 status.state == CD_NODISC) |
|
344 PyErr_SetString(CdError, "no disc in player"); |
|
345 else |
|
346 PyErr_SetString(CdError, "togglepause failed"); |
|
347 return NULL; |
|
348 } |
|
349 |
|
350 Py_INCREF(Py_None); |
|
351 return Py_None; |
|
352 } |
|
353 |
|
354 static PyMethodDef cdplayer_methods[] = { |
|
355 {"allowremoval", (PyCFunction)CD_allowremoval, METH_VARARGS}, |
|
356 {"bestreadsize", (PyCFunction)CD_bestreadsize, METH_VARARGS}, |
|
357 {"close", (PyCFunction)CD_close, METH_VARARGS}, |
|
358 {"eject", (PyCFunction)CD_eject, METH_VARARGS}, |
|
359 {"getstatus", (PyCFunction)CD_getstatus, METH_VARARGS}, |
|
360 {"gettrackinfo", (PyCFunction)CD_gettrackinfo, METH_VARARGS}, |
|
361 {"msftoblock", (PyCFunction)CD_msftoblock, METH_VARARGS}, |
|
362 {"play", (PyCFunction)CD_play, METH_VARARGS}, |
|
363 {"playabs", (PyCFunction)CD_playabs, METH_VARARGS}, |
|
364 {"playtrack", (PyCFunction)CD_playtrack, METH_VARARGS}, |
|
365 {"playtrackabs", (PyCFunction)CD_playtrackabs, METH_VARARGS}, |
|
366 {"preventremoval", (PyCFunction)CD_preventremoval, METH_VARARGS}, |
|
367 {"readda", (PyCFunction)CD_readda, METH_VARARGS}, |
|
368 {"seek", (PyCFunction)CD_seek, METH_VARARGS}, |
|
369 {"seekblock", (PyCFunction)CD_seekblock, METH_VARARGS}, |
|
370 {"seektrack", (PyCFunction)CD_seektrack, METH_VARARGS}, |
|
371 {"stop", (PyCFunction)CD_stop, METH_VARARGS}, |
|
372 {"togglepause", (PyCFunction)CD_togglepause, METH_VARARGS}, |
|
373 {NULL, NULL} /* sentinel */ |
|
374 }; |
|
375 |
|
376 static void |
|
377 cdplayer_dealloc(cdplayerobject *self) |
|
378 { |
|
379 if (self->ob_cdplayer != NULL) |
|
380 CDclose(self->ob_cdplayer); |
|
381 PyObject_Del(self); |
|
382 } |
|
383 |
|
384 static PyObject * |
|
385 cdplayer_getattr(cdplayerobject *self, char *name) |
|
386 { |
|
387 if (self->ob_cdplayer == NULL) { |
|
388 PyErr_SetString(PyExc_RuntimeError, "no player active"); |
|
389 return NULL; |
|
390 } |
|
391 return Py_FindMethod(cdplayer_methods, (PyObject *)self, name); |
|
392 } |
|
393 |
|
394 PyTypeObject CdPlayertype = { |
|
395 PyObject_HEAD_INIT(&PyType_Type) |
|
396 0, /*ob_size*/ |
|
397 "cd.cdplayer", /*tp_name*/ |
|
398 sizeof(cdplayerobject), /*tp_size*/ |
|
399 0, /*tp_itemsize*/ |
|
400 /* methods */ |
|
401 (destructor)cdplayer_dealloc, /*tp_dealloc*/ |
|
402 0, /*tp_print*/ |
|
403 (getattrfunc)cdplayer_getattr, /*tp_getattr*/ |
|
404 0, /*tp_setattr*/ |
|
405 0, /*tp_compare*/ |
|
406 0, /*tp_repr*/ |
|
407 }; |
|
408 |
|
409 static PyObject * |
|
410 newcdplayerobject(CDPLAYER *cdp) |
|
411 { |
|
412 cdplayerobject *p; |
|
413 |
|
414 p = PyObject_New(cdplayerobject, &CdPlayertype); |
|
415 if (p == NULL) |
|
416 return NULL; |
|
417 p->ob_cdplayer = cdp; |
|
418 return (PyObject *) p; |
|
419 } |
|
420 |
|
421 static PyObject * |
|
422 CD_open(PyObject *self, PyObject *args) |
|
423 { |
|
424 char *dev, *direction; |
|
425 CDPLAYER *cdp; |
|
426 |
|
427 /* |
|
428 * Variable number of args. |
|
429 * First defaults to "None", second defaults to "r". |
|
430 */ |
|
431 dev = NULL; |
|
432 direction = "r"; |
|
433 if (!PyArg_ParseTuple(args, "|zs:open", &dev, &direction)) |
|
434 return NULL; |
|
435 |
|
436 cdp = CDopen(dev, direction); |
|
437 if (cdp == NULL) { |
|
438 PyErr_SetFromErrno(CdError); |
|
439 return NULL; |
|
440 } |
|
441 |
|
442 return newcdplayerobject(cdp); |
|
443 } |
|
444 |
|
445 typedef struct { |
|
446 PyObject_HEAD |
|
447 CDPARSER *ob_cdparser; |
|
448 struct { |
|
449 PyObject *ob_cdcallback; |
|
450 PyObject *ob_cdcallbackarg; |
|
451 } ob_cdcallbacks[NCALLBACKS]; |
|
452 } cdparserobject; |
|
453 |
|
454 static void |
|
455 CD_callback(void *arg, CDDATATYPES type, void *data) |
|
456 { |
|
457 PyObject *result, *args, *v = NULL; |
|
458 char *p; |
|
459 int i; |
|
460 cdparserobject *self; |
|
461 |
|
462 self = (cdparserobject *) arg; |
|
463 args = PyTuple_New(3); |
|
464 if (args == NULL) |
|
465 return; |
|
466 Py_INCREF(self->ob_cdcallbacks[type].ob_cdcallbackarg); |
|
467 PyTuple_SetItem(args, 0, self->ob_cdcallbacks[type].ob_cdcallbackarg); |
|
468 PyTuple_SetItem(args, 1, PyInt_FromLong((long) type)); |
|
469 switch (type) { |
|
470 case cd_audio: |
|
471 v = PyString_FromStringAndSize(data, CDDA_DATASIZE); |
|
472 break; |
|
473 case cd_pnum: |
|
474 case cd_index: |
|
475 v = PyInt_FromLong(((CDPROGNUM *) data)->value); |
|
476 break; |
|
477 case cd_ptime: |
|
478 case cd_atime: |
|
479 #define ptr ((struct cdtimecode *) data) |
|
480 v = Py_BuildValue("(iii)", |
|
481 ptr->mhi * 10 + ptr->mlo, |
|
482 ptr->shi * 10 + ptr->slo, |
|
483 ptr->fhi * 10 + ptr->flo); |
|
484 #undef ptr |
|
485 break; |
|
486 case cd_catalog: |
|
487 v = PyString_FromStringAndSize(NULL, 13); |
|
488 p = PyString_AsString(v); |
|
489 for (i = 0; i < 13; i++) |
|
490 *p++ = ((char *) data)[i] + '0'; |
|
491 break; |
|
492 case cd_ident: |
|
493 #define ptr ((struct cdident *) data) |
|
494 v = PyString_FromStringAndSize(NULL, 12); |
|
495 p = PyString_AsString(v); |
|
496 CDsbtoa(p, ptr->country, 2); |
|
497 p += 2; |
|
498 CDsbtoa(p, ptr->owner, 3); |
|
499 p += 3; |
|
500 *p++ = ptr->year[0] + '0'; |
|
501 *p++ = ptr->year[1] + '0'; |
|
502 *p++ = ptr->serial[0] + '0'; |
|
503 *p++ = ptr->serial[1] + '0'; |
|
504 *p++ = ptr->serial[2] + '0'; |
|
505 *p++ = ptr->serial[3] + '0'; |
|
506 *p++ = ptr->serial[4] + '0'; |
|
507 #undef ptr |
|
508 break; |
|
509 case cd_control: |
|
510 v = PyInt_FromLong((long) *((unchar *) data)); |
|
511 break; |
|
512 } |
|
513 PyTuple_SetItem(args, 2, v); |
|
514 if (PyErr_Occurred()) { |
|
515 Py_DECREF(args); |
|
516 return; |
|
517 } |
|
518 |
|
519 result = PyEval_CallObject(self->ob_cdcallbacks[type].ob_cdcallback, |
|
520 args); |
|
521 Py_DECREF(args); |
|
522 Py_XDECREF(result); |
|
523 } |
|
524 |
|
525 static PyObject * |
|
526 CD_deleteparser(cdparserobject *self, PyObject *args) |
|
527 { |
|
528 int i; |
|
529 |
|
530 if (!PyArg_ParseTuple(args, ":deleteparser")) |
|
531 return NULL; |
|
532 |
|
533 CDdeleteparser(self->ob_cdparser); |
|
534 self->ob_cdparser = NULL; |
|
535 |
|
536 /* no sense in keeping the callbacks, so remove them */ |
|
537 for (i = 0; i < NCALLBACKS; i++) { |
|
538 Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback); |
|
539 self->ob_cdcallbacks[i].ob_cdcallback = NULL; |
|
540 Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg); |
|
541 self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL; |
|
542 } |
|
543 |
|
544 Py_INCREF(Py_None); |
|
545 return Py_None; |
|
546 } |
|
547 |
|
548 static PyObject * |
|
549 CD_parseframe(cdparserobject *self, PyObject *args) |
|
550 { |
|
551 char *cdfp; |
|
552 int length; |
|
553 CDFRAME *p; |
|
554 |
|
555 if (!PyArg_ParseTuple(args, "s#:parseframe", &cdfp, &length)) |
|
556 return NULL; |
|
557 |
|
558 if (length % sizeof(CDFRAME) != 0) { |
|
559 PyErr_SetString(PyExc_TypeError, "bad length"); |
|
560 return NULL; |
|
561 } |
|
562 |
|
563 p = (CDFRAME *) cdfp; |
|
564 while (length > 0) { |
|
565 CDparseframe(self->ob_cdparser, p); |
|
566 length -= sizeof(CDFRAME); |
|
567 p++; |
|
568 if (PyErr_Occurred()) |
|
569 return NULL; |
|
570 } |
|
571 |
|
572 Py_INCREF(Py_None); |
|
573 return Py_None; |
|
574 } |
|
575 |
|
576 static PyObject * |
|
577 CD_removecallback(cdparserobject *self, PyObject *args) |
|
578 { |
|
579 int type; |
|
580 |
|
581 if (!PyArg_ParseTuple(args, "i:removecallback", &type)) |
|
582 return NULL; |
|
583 |
|
584 if (type < 0 || type >= NCALLBACKS) { |
|
585 PyErr_SetString(PyExc_TypeError, "bad type"); |
|
586 return NULL; |
|
587 } |
|
588 |
|
589 CDremovecallback(self->ob_cdparser, (CDDATATYPES) type); |
|
590 |
|
591 Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback); |
|
592 self->ob_cdcallbacks[type].ob_cdcallback = NULL; |
|
593 |
|
594 Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg); |
|
595 self->ob_cdcallbacks[type].ob_cdcallbackarg = NULL; |
|
596 |
|
597 Py_INCREF(Py_None); |
|
598 return Py_None; |
|
599 } |
|
600 |
|
601 static PyObject * |
|
602 CD_resetparser(cdparserobject *self, PyObject *args) |
|
603 { |
|
604 if (!PyArg_ParseTuple(args, ":resetparser")) |
|
605 return NULL; |
|
606 |
|
607 CDresetparser(self->ob_cdparser); |
|
608 |
|
609 Py_INCREF(Py_None); |
|
610 return Py_None; |
|
611 } |
|
612 |
|
613 static PyObject * |
|
614 CD_addcallback(cdparserobject *self, PyObject *args) |
|
615 { |
|
616 int type; |
|
617 PyObject *func, *funcarg; |
|
618 |
|
619 /* XXX - more work here */ |
|
620 if (!PyArg_ParseTuple(args, "iOO:addcallback", &type, &func, &funcarg)) |
|
621 return NULL; |
|
622 |
|
623 if (type < 0 || type >= NCALLBACKS) { |
|
624 PyErr_SetString(PyExc_TypeError, "argument out of range"); |
|
625 return NULL; |
|
626 } |
|
627 |
|
628 #ifdef CDsetcallback |
|
629 CDaddcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback, |
|
630 (void *) self); |
|
631 #else |
|
632 CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback, |
|
633 (void *) self); |
|
634 #endif |
|
635 Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback); |
|
636 Py_INCREF(func); |
|
637 self->ob_cdcallbacks[type].ob_cdcallback = func; |
|
638 Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg); |
|
639 Py_INCREF(funcarg); |
|
640 self->ob_cdcallbacks[type].ob_cdcallbackarg = funcarg; |
|
641 |
|
642 /* |
|
643 if (type == cd_audio) { |
|
644 sigfpe_[_UNDERFL].repls = _ZERO; |
|
645 handle_sigfpes(_ON, _EN_UNDERFL, NULL, |
|
646 _ABORT_ON_ERROR, NULL); |
|
647 } |
|
648 */ |
|
649 |
|
650 Py_INCREF(Py_None); |
|
651 return Py_None; |
|
652 } |
|
653 |
|
654 static PyMethodDef cdparser_methods[] = { |
|
655 {"addcallback", (PyCFunction)CD_addcallback, METH_VARARGS}, |
|
656 {"deleteparser", (PyCFunction)CD_deleteparser, METH_VARARGS}, |
|
657 {"parseframe", (PyCFunction)CD_parseframe, METH_VARARGS}, |
|
658 {"removecallback", (PyCFunction)CD_removecallback, METH_VARARGS}, |
|
659 {"resetparser", (PyCFunction)CD_resetparser, METH_VARARGS}, |
|
660 /* backward compatibility */ |
|
661 {"setcallback", (PyCFunction)CD_addcallback, METH_VARARGS}, |
|
662 {NULL, NULL} /* sentinel */ |
|
663 }; |
|
664 |
|
665 static void |
|
666 cdparser_dealloc(cdparserobject *self) |
|
667 { |
|
668 int i; |
|
669 |
|
670 for (i = 0; i < NCALLBACKS; i++) { |
|
671 Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback); |
|
672 self->ob_cdcallbacks[i].ob_cdcallback = NULL; |
|
673 Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg); |
|
674 self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL; |
|
675 } |
|
676 CDdeleteparser(self->ob_cdparser); |
|
677 PyObject_Del(self); |
|
678 } |
|
679 |
|
680 static PyObject * |
|
681 cdparser_getattr(cdparserobject *self, char *name) |
|
682 { |
|
683 if (self->ob_cdparser == NULL) { |
|
684 PyErr_SetString(PyExc_RuntimeError, "no parser active"); |
|
685 return NULL; |
|
686 } |
|
687 |
|
688 return Py_FindMethod(cdparser_methods, (PyObject *)self, name); |
|
689 } |
|
690 |
|
691 PyTypeObject CdParsertype = { |
|
692 PyObject_HEAD_INIT(&PyType_Type) |
|
693 0, /*ob_size*/ |
|
694 "cd.cdparser", /*tp_name*/ |
|
695 sizeof(cdparserobject), /*tp_size*/ |
|
696 0, /*tp_itemsize*/ |
|
697 /* methods */ |
|
698 (destructor)cdparser_dealloc, /*tp_dealloc*/ |
|
699 0, /*tp_print*/ |
|
700 (getattrfunc)cdparser_getattr, /*tp_getattr*/ |
|
701 0, /*tp_setattr*/ |
|
702 0, /*tp_compare*/ |
|
703 0, /*tp_repr*/ |
|
704 }; |
|
705 |
|
706 static PyObject * |
|
707 newcdparserobject(CDPARSER *cdp) |
|
708 { |
|
709 cdparserobject *p; |
|
710 int i; |
|
711 |
|
712 p = PyObject_New(cdparserobject, &CdParsertype); |
|
713 if (p == NULL) |
|
714 return NULL; |
|
715 p->ob_cdparser = cdp; |
|
716 for (i = 0; i < NCALLBACKS; i++) { |
|
717 p->ob_cdcallbacks[i].ob_cdcallback = NULL; |
|
718 p->ob_cdcallbacks[i].ob_cdcallbackarg = NULL; |
|
719 } |
|
720 return (PyObject *) p; |
|
721 } |
|
722 |
|
723 static PyObject * |
|
724 CD_createparser(PyObject *self, PyObject *args) |
|
725 { |
|
726 CDPARSER *cdp; |
|
727 |
|
728 if (!PyArg_ParseTuple(args, ":createparser")) |
|
729 return NULL; |
|
730 cdp = CDcreateparser(); |
|
731 if (cdp == NULL) { |
|
732 PyErr_SetString(CdError, "createparser failed"); |
|
733 return NULL; |
|
734 } |
|
735 |
|
736 return newcdparserobject(cdp); |
|
737 } |
|
738 |
|
739 static PyObject * |
|
740 CD_msftoframe(PyObject *self, PyObject *args) |
|
741 { |
|
742 int min, sec, frame; |
|
743 |
|
744 if (!PyArg_ParseTuple(args, "iii:msftoframe", &min, &sec, &frame)) |
|
745 return NULL; |
|
746 |
|
747 return PyInt_FromLong((long) CDmsftoframe(min, sec, frame)); |
|
748 } |
|
749 |
|
750 static PyMethodDef CD_methods[] = { |
|
751 {"open", (PyCFunction)CD_open, METH_VARARGS}, |
|
752 {"createparser", (PyCFunction)CD_createparser, METH_VARARGS}, |
|
753 {"msftoframe", (PyCFunction)CD_msftoframe, METH_VARARGS}, |
|
754 {NULL, NULL} /* Sentinel */ |
|
755 }; |
|
756 |
|
757 void |
|
758 initcd(void) |
|
759 { |
|
760 PyObject *m, *d; |
|
761 |
|
762 if (PyErr_WarnPy3k("the cd module has been removed in " |
|
763 "Python 3.0", 2) < 0) |
|
764 return; |
|
765 |
|
766 m = Py_InitModule("cd", CD_methods); |
|
767 if (m == NULL) |
|
768 return; |
|
769 d = PyModule_GetDict(m); |
|
770 |
|
771 CdError = PyErr_NewException("cd.error", NULL, NULL); |
|
772 PyDict_SetItemString(d, "error", CdError); |
|
773 |
|
774 /* Identifiers for the different types of callbacks from the parser */ |
|
775 PyDict_SetItemString(d, "audio", PyInt_FromLong((long) cd_audio)); |
|
776 PyDict_SetItemString(d, "pnum", PyInt_FromLong((long) cd_pnum)); |
|
777 PyDict_SetItemString(d, "index", PyInt_FromLong((long) cd_index)); |
|
778 PyDict_SetItemString(d, "ptime", PyInt_FromLong((long) cd_ptime)); |
|
779 PyDict_SetItemString(d, "atime", PyInt_FromLong((long) cd_atime)); |
|
780 PyDict_SetItemString(d, "catalog", PyInt_FromLong((long) cd_catalog)); |
|
781 PyDict_SetItemString(d, "ident", PyInt_FromLong((long) cd_ident)); |
|
782 PyDict_SetItemString(d, "control", PyInt_FromLong((long) cd_control)); |
|
783 |
|
784 /* Block size information for digital audio data */ |
|
785 PyDict_SetItemString(d, "DATASIZE", |
|
786 PyInt_FromLong((long) CDDA_DATASIZE)); |
|
787 PyDict_SetItemString(d, "BLOCKSIZE", |
|
788 PyInt_FromLong((long) CDDA_BLOCKSIZE)); |
|
789 |
|
790 /* Possible states for the cd player */ |
|
791 PyDict_SetItemString(d, "ERROR", PyInt_FromLong((long) CD_ERROR)); |
|
792 PyDict_SetItemString(d, "NODISC", PyInt_FromLong((long) CD_NODISC)); |
|
793 PyDict_SetItemString(d, "READY", PyInt_FromLong((long) CD_READY)); |
|
794 PyDict_SetItemString(d, "PLAYING", PyInt_FromLong((long) CD_PLAYING)); |
|
795 PyDict_SetItemString(d, "PAUSED", PyInt_FromLong((long) CD_PAUSED)); |
|
796 PyDict_SetItemString(d, "STILL", PyInt_FromLong((long) CD_STILL)); |
|
797 #ifdef CD_CDROM /* only newer versions of the library */ |
|
798 PyDict_SetItemString(d, "CDROM", PyInt_FromLong((long) CD_CDROM)); |
|
799 #endif |
|
800 } |