1 /* CD module -- interface to Mark Callow's and Roger Chickering's */
2 /* CD Audio Library (CD). */
12 CDPLAYER
*ob_cdplayer
;
15 static PyObject
*CdError
; /* exception cd.error */
18 CD_allowremoval(cdplayerobject
*self
, PyObject
*args
)
20 if (!PyArg_ParseTuple(args
, ":allowremoval"))
23 CDallowremoval(self
->ob_cdplayer
);
30 CD_preventremoval(cdplayerobject
*self
, PyObject
*args
)
32 if (!PyArg_ParseTuple(args
, ":preventremoval"))
35 CDpreventremoval(self
->ob_cdplayer
);
42 CD_bestreadsize(cdplayerobject
*self
, PyObject
*args
)
44 if (!PyArg_ParseTuple(args
, ":bestreadsize"))
47 return PyInt_FromLong((long) CDbestreadsize(self
->ob_cdplayer
));
51 CD_close(cdplayerobject
*self
, PyObject
*args
)
53 if (!PyArg_ParseTuple(args
, ":close"))
56 if (!CDclose(self
->ob_cdplayer
)) {
57 PyErr_SetFromErrno(CdError
); /* XXX - ??? */
60 self
->ob_cdplayer
= NULL
;
67 CD_eject(cdplayerobject
*self
, PyObject
*args
)
71 if (!PyArg_ParseTuple(args
, ":eject"))
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");
79 PyErr_SetString(CdError
, "eject failed");
88 CD_getstatus(cdplayerobject
*self
, PyObject
*args
)
92 if (!PyArg_ParseTuple(args
, ":getstatus"))
95 if (!CDgetstatus(self
->ob_cdplayer
, &status
)) {
96 PyErr_SetFromErrno(CdError
); /* XXX - ??? */
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
,
109 CD_gettrackinfo(cdplayerobject
*self
, PyObject
*args
)
115 if (!PyArg_ParseTuple(args
, "i:gettrackinfo", &track
))
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");
123 PyErr_SetString(CdError
, "gettrackinfo failed");
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
);
133 CD_msftoblock(cdplayerobject
*self
, PyObject
*args
)
137 if (!PyArg_ParseTuple(args
, "iii:msftoblock", &min
, &sec
, &frame
))
140 return PyInt_FromLong((long) CDmsftoblock(self
->ob_cdplayer
,
145 CD_play(cdplayerobject
*self
, PyObject
*args
)
150 if (!PyArg_ParseTuple(args
, "ii:play", &start
, &play
))
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");
158 PyErr_SetString(CdError
, "play failed");
167 CD_playabs(cdplayerobject
*self
, PyObject
*args
)
169 int min
, sec
, frame
, play
;
172 if (!PyArg_ParseTuple(args
, "iiii:playabs", &min
, &sec
, &frame
, &play
))
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");
180 PyErr_SetString(CdError
, "playabs failed");
189 CD_playtrack(cdplayerobject
*self
, PyObject
*args
)
194 if (!PyArg_ParseTuple(args
, "ii:playtrack", &start
, &play
))
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");
202 PyErr_SetString(CdError
, "playtrack failed");
211 CD_playtrackabs(cdplayerobject
*self
, PyObject
*args
)
213 int track
, min
, sec
, frame
, play
;
216 if (!PyArg_ParseTuple(args
, "iiiii:playtrackabs", &track
, &min
, &sec
,
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");
225 PyErr_SetString(CdError
, "playtrackabs failed");
234 CD_readda(cdplayerobject
*self
, PyObject
*args
)
239 if (!PyArg_ParseTuple(args
, "i:readda", &numframes
))
242 result
= PyString_FromStringAndSize(NULL
, numframes
* sizeof(CDFRAME
));
246 n
= CDreadda(self
->ob_cdplayer
,
247 (CDFRAME
*) PyString_AsString(result
), numframes
);
250 PyErr_SetFromErrno(CdError
);
254 if (_PyString_Resize(&result
, n
* sizeof(CDFRAME
)))
261 CD_seek(cdplayerobject
*self
, PyObject
*args
)
266 if (!PyArg_ParseTuple(args
, "iii:seek", &min
, &sec
, &frame
))
269 PyTryBlock
= CDseek(self
->ob_cdplayer
, min
, sec
, frame
);
270 if (PyTryBlock
== -1) {
271 PyErr_SetFromErrno(CdError
);
275 return PyInt_FromLong(PyTryBlock
);
279 CD_seektrack(cdplayerobject
*self
, PyObject
*args
)
284 if (!PyArg_ParseTuple(args
, "i:seektrack", &track
))
287 PyTryBlock
= CDseektrack(self
->ob_cdplayer
, track
);
288 if (PyTryBlock
== -1) {
289 PyErr_SetFromErrno(CdError
);
293 return PyInt_FromLong(PyTryBlock
);
297 CD_seekblock(cdplayerobject
*self
, PyObject
*args
)
299 unsigned long PyTryBlock
;
301 if (!PyArg_ParseTuple(args
, "l:seekblock", &PyTryBlock
))
304 PyTryBlock
= CDseekblock(self
->ob_cdplayer
, PyTryBlock
);
305 if (PyTryBlock
== (unsigned long) -1) {
306 PyErr_SetFromErrno(CdError
);
310 return PyInt_FromLong(PyTryBlock
);
314 CD_stop(cdplayerobject
*self
, PyObject
*args
)
318 if (!PyArg_ParseTuple(args
, ":stop"))
321 if (!CDstop(self
->ob_cdplayer
)) {
322 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
323 status
.state
== CD_NODISC
)
324 PyErr_SetString(CdError
, "no disc in player");
326 PyErr_SetString(CdError
, "stop failed");
335 CD_togglepause(cdplayerobject
*self
, PyObject
*args
)
339 if (!PyArg_ParseTuple(args
, ":togglepause"))
342 if (!CDtogglepause(self
->ob_cdplayer
)) {
343 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
344 status
.state
== CD_NODISC
)
345 PyErr_SetString(CdError
, "no disc in player");
347 PyErr_SetString(CdError
, "togglepause failed");
355 static PyMethodDef cdplayer_methods
[] = {
356 {"allowremoval", (PyCFunction
)CD_allowremoval
, 1},
357 {"bestreadsize", (PyCFunction
)CD_bestreadsize
, 1},
358 {"close", (PyCFunction
)CD_close
, 1},
359 {"eject", (PyCFunction
)CD_eject
, 1},
360 {"getstatus", (PyCFunction
)CD_getstatus
, 1},
361 {"gettrackinfo", (PyCFunction
)CD_gettrackinfo
, 1},
362 {"msftoblock", (PyCFunction
)CD_msftoblock
, 1},
363 {"play", (PyCFunction
)CD_play
, 1},
364 {"playabs", (PyCFunction
)CD_playabs
, 1},
365 {"playtrack", (PyCFunction
)CD_playtrack
, 1},
366 {"playtrackabs", (PyCFunction
)CD_playtrackabs
, 1},
367 {"preventremoval", (PyCFunction
)CD_preventremoval
, 1},
368 {"readda", (PyCFunction
)CD_readda
, 1},
369 {"seek", (PyCFunction
)CD_seek
, 1},
370 {"seekblock", (PyCFunction
)CD_seekblock
, 1},
371 {"seektrack", (PyCFunction
)CD_seektrack
, 1},
372 {"stop", (PyCFunction
)CD_stop
, 1},
373 {"togglepause", (PyCFunction
)CD_togglepause
, 1},
374 {NULL
, NULL
} /* sentinel */
378 cdplayer_dealloc(cdplayerobject
*self
)
380 if (self
->ob_cdplayer
!= NULL
)
381 CDclose(self
->ob_cdplayer
);
386 cdplayer_getattr(cdplayerobject
*self
, char *name
)
388 if (self
->ob_cdplayer
== NULL
) {
389 PyErr_SetString(PyExc_RuntimeError
, "no player active");
392 return Py_FindMethod(cdplayer_methods
, (PyObject
*)self
, name
);
395 PyTypeObject CdPlayertype
= {
396 PyObject_HEAD_INIT(&PyType_Type
)
398 "cdplayer", /*tp_name*/
399 sizeof(cdplayerobject
), /*tp_size*/
402 (destructor
)cdplayer_dealloc
, /*tp_dealloc*/
404 (getattrfunc
)cdplayer_getattr
, /*tp_getattr*/
411 newcdplayerobject(CDPLAYER
*cdp
)
415 p
= PyObject_New(cdplayerobject
, &CdPlayertype
);
418 p
->ob_cdplayer
= cdp
;
419 return (PyObject
*) p
;
423 CD_open(PyObject
*self
, PyObject
*args
)
425 char *dev
, *direction
;
429 * Variable number of args.
430 * First defaults to "None", second defaults to "r".
434 if (!PyArg_ParseTuple(args
, "|zs:open", &dev
, &direction
))
437 cdp
= CDopen(dev
, direction
);
439 PyErr_SetFromErrno(CdError
);
443 return newcdplayerobject(cdp
);
448 CDPARSER
*ob_cdparser
;
450 PyObject
*ob_cdcallback
;
451 PyObject
*ob_cdcallbackarg
;
452 } ob_cdcallbacks
[NCALLBACKS
];
456 CD_callback(void *arg
, CDDATATYPES type
, void *data
)
458 PyObject
*result
, *args
, *v
= NULL
;
461 cdparserobject
*self
;
463 self
= (cdparserobject
*) arg
;
464 args
= PyTuple_New(3);
467 Py_INCREF(self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
468 PyTuple_SetItem(args
, 0, self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
469 PyTuple_SetItem(args
, 1, PyInt_FromLong((long) type
));
472 v
= PyString_FromStringAndSize(data
, CDDA_DATASIZE
);
476 v
= PyInt_FromLong(((CDPROGNUM
*) data
)->value
);
480 #define ptr ((struct cdtimecode *) data)
481 v
= Py_BuildValue("(iii)",
482 ptr
->mhi
* 10 + ptr
->mlo
,
483 ptr
->shi
* 10 + ptr
->slo
,
484 ptr
->fhi
* 10 + ptr
->flo
);
488 v
= PyString_FromStringAndSize(NULL
, 13);
489 p
= PyString_AsString(v
);
490 for (i
= 0; i
< 13; i
++)
491 *p
++ = ((char *) data
)[i
] + '0';
494 #define ptr ((struct cdident *) data)
495 v
= PyString_FromStringAndSize(NULL
, 12);
496 p
= PyString_AsString(v
);
497 CDsbtoa(p
, ptr
->country
, 2);
499 CDsbtoa(p
, ptr
->owner
, 3);
501 *p
++ = ptr
->year
[0] + '0';
502 *p
++ = ptr
->year
[1] + '0';
503 *p
++ = ptr
->serial
[0] + '0';
504 *p
++ = ptr
->serial
[1] + '0';
505 *p
++ = ptr
->serial
[2] + '0';
506 *p
++ = ptr
->serial
[3] + '0';
507 *p
++ = ptr
->serial
[4] + '0';
511 v
= PyInt_FromLong((long) *((unchar
*) data
));
514 PyTuple_SetItem(args
, 2, v
);
515 if (PyErr_Occurred()) {
520 result
= PyEval_CallObject(self
->ob_cdcallbacks
[type
].ob_cdcallback
,
527 CD_deleteparser(cdparserobject
*self
, PyObject
*args
)
531 if (!PyArg_ParseTuple(args
, ":deleteparser"))
534 CDdeleteparser(self
->ob_cdparser
);
535 self
->ob_cdparser
= NULL
;
537 /* no sense in keeping the callbacks, so remove them */
538 for (i
= 0; i
< NCALLBACKS
; i
++) {
539 Py_XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallback
);
540 self
->ob_cdcallbacks
[i
].ob_cdcallback
= NULL
;
541 Py_XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
);
542 self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
= NULL
;
550 CD_parseframe(cdparserobject
*self
, PyObject
*args
)
556 if (!PyArg_ParseTuple(args
, "s#:parseframe", &cdfp
, &length
))
559 if (length
% sizeof(CDFRAME
) != 0) {
560 PyErr_SetString(PyExc_TypeError
, "bad length");
564 p
= (CDFRAME
*) cdfp
;
566 CDparseframe(self
->ob_cdparser
, p
);
567 length
-= sizeof(CDFRAME
);
569 if (PyErr_Occurred())
578 CD_removecallback(cdparserobject
*self
, PyObject
*args
)
582 if (!PyArg_ParseTuple(args
, "i:removecallback", &type
))
585 if (type
< 0 || type
>= NCALLBACKS
) {
586 PyErr_SetString(PyExc_TypeError
, "bad type");
590 CDremovecallback(self
->ob_cdparser
, (CDDATATYPES
) type
);
592 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallback
);
593 self
->ob_cdcallbacks
[type
].ob_cdcallback
= NULL
;
595 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
596 self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
= NULL
;
603 CD_resetparser(cdparserobject
*self
, PyObject
*args
)
605 if (!PyArg_ParseTuple(args
, ":resetparser"))
608 CDresetparser(self
->ob_cdparser
);
615 CD_addcallback(cdparserobject
*self
, PyObject
*args
)
618 PyObject
*func
, *funcarg
;
620 /* XXX - more work here */
621 if (!PyArg_ParseTuple(args
, "iOO:addcallback", &type
, &func
, &funcarg
))
624 if (type
< 0 || type
>= NCALLBACKS
) {
625 PyErr_SetString(PyExc_TypeError
, "argument out of range");
630 CDaddcallback(self
->ob_cdparser
, (CDDATATYPES
) type
, CD_callback
,
633 CDsetcallback(self
->ob_cdparser
, (CDDATATYPES
) type
, CD_callback
,
636 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallback
);
638 self
->ob_cdcallbacks
[type
].ob_cdcallback
= func
;
639 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
641 self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
= funcarg
;
644 if (type == cd_audio) {
645 sigfpe_[_UNDERFL].repls = _ZERO;
646 handle_sigfpes(_ON, _EN_UNDERFL, NULL,
647 _ABORT_ON_ERROR, NULL);
655 static PyMethodDef cdparser_methods
[] = {
656 {"addcallback", (PyCFunction
)CD_addcallback
, 1},
657 {"deleteparser", (PyCFunction
)CD_deleteparser
, 1},
658 {"parseframe", (PyCFunction
)CD_parseframe
, 1},
659 {"removecallback", (PyCFunction
)CD_removecallback
, 1},
660 {"resetparser", (PyCFunction
)CD_resetparser
, 1},
661 /* backward compatibility */
662 {"setcallback", (PyCFunction
)CD_addcallback
, 1},
663 {NULL
, NULL
} /* sentinel */
667 cdparser_dealloc(cdparserobject
*self
)
671 for (i
= 0; i
< NCALLBACKS
; i
++) {
672 Py_XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallback
);
673 self
->ob_cdcallbacks
[i
].ob_cdcallback
= NULL
;
674 Py_XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
);
675 self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
= NULL
;
677 CDdeleteparser(self
->ob_cdparser
);
682 cdparser_getattr(cdparserobject
*self
, char *name
)
684 if (self
->ob_cdparser
== NULL
) {
685 PyErr_SetString(PyExc_RuntimeError
, "no parser active");
689 return Py_FindMethod(cdparser_methods
, (PyObject
*)self
, name
);
692 PyTypeObject CdParsertype
= {
693 PyObject_HEAD_INIT(&PyType_Type
)
695 "cdparser", /*tp_name*/
696 sizeof(cdparserobject
), /*tp_size*/
699 (destructor
)cdparser_dealloc
, /*tp_dealloc*/
701 (getattrfunc
)cdparser_getattr
, /*tp_getattr*/
708 newcdparserobject(CDPARSER
*cdp
)
713 p
= PyObject_New(cdparserobject
, &CdParsertype
);
716 p
->ob_cdparser
= cdp
;
717 for (i
= 0; i
< NCALLBACKS
; i
++) {
718 p
->ob_cdcallbacks
[i
].ob_cdcallback
= NULL
;
719 p
->ob_cdcallbacks
[i
].ob_cdcallbackarg
= NULL
;
721 return (PyObject
*) p
;
725 CD_createparser(PyObject
*self
, PyObject
*args
)
729 if (!PyArg_ParseTuple(args
, ":createparser"))
731 cdp
= CDcreateparser();
733 PyErr_SetString(CdError
, "createparser failed");
737 return newcdparserobject(cdp
);
741 CD_msftoframe(PyObject
*self
, PyObject
*args
)
745 if (!PyArg_ParseTuple(args
, "iii:msftoframe", &min
, &sec
, &frame
))
748 return PyInt_FromLong((long) CDmsftoframe(min
, sec
, frame
));
751 static PyMethodDef CD_methods
[] = {
752 {"open", (PyCFunction
)CD_open
, 1},
753 {"createparser", (PyCFunction
)CD_createparser
, 1},
754 {"msftoframe", (PyCFunction
)CD_msftoframe
, 1},
755 {NULL
, NULL
} /* Sentinel */
763 m
= Py_InitModule("cd", CD_methods
);
764 d
= PyModule_GetDict(m
);
766 CdError
= PyErr_NewException("cd.error", NULL
, NULL
);
767 PyDict_SetItemString(d
, "error", CdError
);
769 /* Identifiers for the different types of callbacks from the parser */
770 PyDict_SetItemString(d
, "audio", PyInt_FromLong((long) cd_audio
));
771 PyDict_SetItemString(d
, "pnum", PyInt_FromLong((long) cd_pnum
));
772 PyDict_SetItemString(d
, "index", PyInt_FromLong((long) cd_index
));
773 PyDict_SetItemString(d
, "ptime", PyInt_FromLong((long) cd_ptime
));
774 PyDict_SetItemString(d
, "atime", PyInt_FromLong((long) cd_atime
));
775 PyDict_SetItemString(d
, "catalog", PyInt_FromLong((long) cd_catalog
));
776 PyDict_SetItemString(d
, "ident", PyInt_FromLong((long) cd_ident
));
777 PyDict_SetItemString(d
, "control", PyInt_FromLong((long) cd_control
));
779 /* Block size information for digital audio data */
780 PyDict_SetItemString(d
, "DATASIZE",
781 PyInt_FromLong((long) CDDA_DATASIZE
));
782 PyDict_SetItemString(d
, "BLOCKSIZE",
783 PyInt_FromLong((long) CDDA_BLOCKSIZE
));
785 /* Possible states for the cd player */
786 PyDict_SetItemString(d
, "ERROR", PyInt_FromLong((long) CD_ERROR
));
787 PyDict_SetItemString(d
, "NODISC", PyInt_FromLong((long) CD_NODISC
));
788 PyDict_SetItemString(d
, "READY", PyInt_FromLong((long) CD_READY
));
789 PyDict_SetItemString(d
, "PLAYING", PyInt_FromLong((long) CD_PLAYING
));
790 PyDict_SetItemString(d
, "PAUSED", PyInt_FromLong((long) CD_PAUSED
));
791 PyDict_SetItemString(d
, "STILL", PyInt_FromLong((long) CD_STILL
));
792 #ifdef CD_CDROM /* only newer versions of the library */
793 PyDict_SetItemString(d
, "CDROM", PyInt_FromLong((long) CD_CDROM
));