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 _PyString_Resize(&result
, n
* sizeof(CDFRAME
));
260 CD_seek(cdplayerobject
*self
, PyObject
*args
)
265 if (!PyArg_ParseTuple(args
, "iii:seek", &min
, &sec
, &frame
))
268 PyTryBlock
= CDseek(self
->ob_cdplayer
, min
, sec
, frame
);
269 if (PyTryBlock
== -1) {
270 PyErr_SetFromErrno(CdError
);
274 return PyInt_FromLong(PyTryBlock
);
278 CD_seektrack(cdplayerobject
*self
, PyObject
*args
)
283 if (!PyArg_ParseTuple(args
, "i:seektrack", &track
))
286 PyTryBlock
= CDseektrack(self
->ob_cdplayer
, track
);
287 if (PyTryBlock
== -1) {
288 PyErr_SetFromErrno(CdError
);
292 return PyInt_FromLong(PyTryBlock
);
296 CD_seekblock(cdplayerobject
*self
, PyObject
*args
)
298 unsigned long PyTryBlock
;
300 if (!PyArg_ParseTuple(args
, "l:seekblock", &PyTryBlock
))
303 PyTryBlock
= CDseekblock(self
->ob_cdplayer
, PyTryBlock
);
304 if (PyTryBlock
== (unsigned long) -1) {
305 PyErr_SetFromErrno(CdError
);
309 return PyInt_FromLong(PyTryBlock
);
313 CD_stop(cdplayerobject
*self
, PyObject
*args
)
317 if (!PyArg_ParseTuple(args
, ":stop"))
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");
325 PyErr_SetString(CdError
, "stop failed");
334 CD_togglepause(cdplayerobject
*self
, PyObject
*args
)
338 if (!PyArg_ParseTuple(args
, ":togglepause"))
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");
346 PyErr_SetString(CdError
, "togglepause failed");
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 */
377 cdplayer_dealloc(cdplayerobject
*self
)
379 if (self
->ob_cdplayer
!= NULL
)
380 CDclose(self
->ob_cdplayer
);
385 cdplayer_getattr(cdplayerobject
*self
, char *name
)
387 if (self
->ob_cdplayer
== NULL
) {
388 PyErr_SetString(PyExc_RuntimeError
, "no player active");
391 return Py_FindMethod(cdplayer_methods
, (PyObject
*)self
, name
);
394 PyTypeObject CdPlayertype
= {
395 PyObject_HEAD_INIT(&PyType_Type
)
397 "cd.cdplayer", /*tp_name*/
398 sizeof(cdplayerobject
), /*tp_size*/
401 (destructor
)cdplayer_dealloc
, /*tp_dealloc*/
403 (getattrfunc
)cdplayer_getattr
, /*tp_getattr*/
410 newcdplayerobject(CDPLAYER
*cdp
)
414 p
= PyObject_New(cdplayerobject
, &CdPlayertype
);
417 p
->ob_cdplayer
= cdp
;
418 return (PyObject
*) p
;
422 CD_open(PyObject
*self
, PyObject
*args
)
424 char *dev
, *direction
;
428 * Variable number of args.
429 * First defaults to "None", second defaults to "r".
433 if (!PyArg_ParseTuple(args
, "|zs:open", &dev
, &direction
))
436 cdp
= CDopen(dev
, direction
);
438 PyErr_SetFromErrno(CdError
);
442 return newcdplayerobject(cdp
);
447 CDPARSER
*ob_cdparser
;
449 PyObject
*ob_cdcallback
;
450 PyObject
*ob_cdcallbackarg
;
451 } ob_cdcallbacks
[NCALLBACKS
];
455 CD_callback(void *arg
, CDDATATYPES type
, void *data
)
457 PyObject
*result
, *args
, *v
= NULL
;
460 cdparserobject
*self
;
462 self
= (cdparserobject
*) arg
;
463 args
= PyTuple_New(3);
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
));
471 v
= PyString_FromStringAndSize(data
, CDDA_DATASIZE
);
475 v
= PyInt_FromLong(((CDPROGNUM
*) data
)->value
);
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
);
487 v
= PyString_FromStringAndSize(NULL
, 13);
488 p
= PyString_AsString(v
);
489 for (i
= 0; i
< 13; i
++)
490 *p
++ = ((char *) data
)[i
] + '0';
493 #define ptr ((struct cdident *) data)
494 v
= PyString_FromStringAndSize(NULL
, 12);
495 p
= PyString_AsString(v
);
496 CDsbtoa(p
, ptr
->country
, 2);
498 CDsbtoa(p
, ptr
->owner
, 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';
510 v
= PyInt_FromLong((long) *((unchar
*) data
));
513 PyTuple_SetItem(args
, 2, v
);
514 if (PyErr_Occurred()) {
519 result
= PyEval_CallObject(self
->ob_cdcallbacks
[type
].ob_cdcallback
,
526 CD_deleteparser(cdparserobject
*self
, PyObject
*args
)
530 if (!PyArg_ParseTuple(args
, ":deleteparser"))
533 CDdeleteparser(self
->ob_cdparser
);
534 self
->ob_cdparser
= NULL
;
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
;
549 CD_parseframe(cdparserobject
*self
, PyObject
*args
)
555 if (!PyArg_ParseTuple(args
, "s#:parseframe", &cdfp
, &length
))
558 if (length
% sizeof(CDFRAME
) != 0) {
559 PyErr_SetString(PyExc_TypeError
, "bad length");
563 p
= (CDFRAME
*) cdfp
;
565 CDparseframe(self
->ob_cdparser
, p
);
566 length
-= sizeof(CDFRAME
);
568 if (PyErr_Occurred())
577 CD_removecallback(cdparserobject
*self
, PyObject
*args
)
581 if (!PyArg_ParseTuple(args
, "i:removecallback", &type
))
584 if (type
< 0 || type
>= NCALLBACKS
) {
585 PyErr_SetString(PyExc_TypeError
, "bad type");
589 CDremovecallback(self
->ob_cdparser
, (CDDATATYPES
) type
);
591 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallback
);
592 self
->ob_cdcallbacks
[type
].ob_cdcallback
= NULL
;
594 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
595 self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
= NULL
;
602 CD_resetparser(cdparserobject
*self
, PyObject
*args
)
604 if (!PyArg_ParseTuple(args
, ":resetparser"))
607 CDresetparser(self
->ob_cdparser
);
614 CD_addcallback(cdparserobject
*self
, PyObject
*args
)
617 PyObject
*func
, *funcarg
;
619 /* XXX - more work here */
620 if (!PyArg_ParseTuple(args
, "iOO:addcallback", &type
, &func
, &funcarg
))
623 if (type
< 0 || type
>= NCALLBACKS
) {
624 PyErr_SetString(PyExc_TypeError
, "argument out of range");
629 CDaddcallback(self
->ob_cdparser
, (CDDATATYPES
) type
, CD_callback
,
632 CDsetcallback(self
->ob_cdparser
, (CDDATATYPES
) type
, CD_callback
,
635 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallback
);
637 self
->ob_cdcallbacks
[type
].ob_cdcallback
= func
;
638 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
640 self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
= funcarg
;
643 if (type == cd_audio) {
644 sigfpe_[_UNDERFL].repls = _ZERO;
645 handle_sigfpes(_ON, _EN_UNDERFL, NULL,
646 _ABORT_ON_ERROR, NULL);
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 */
666 cdparser_dealloc(cdparserobject
*self
)
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
;
676 CDdeleteparser(self
->ob_cdparser
);
681 cdparser_getattr(cdparserobject
*self
, char *name
)
683 if (self
->ob_cdparser
== NULL
) {
684 PyErr_SetString(PyExc_RuntimeError
, "no parser active");
688 return Py_FindMethod(cdparser_methods
, (PyObject
*)self
, name
);
691 PyTypeObject CdParsertype
= {
692 PyObject_HEAD_INIT(&PyType_Type
)
694 "cd.cdparser", /*tp_name*/
695 sizeof(cdparserobject
), /*tp_size*/
698 (destructor
)cdparser_dealloc
, /*tp_dealloc*/
700 (getattrfunc
)cdparser_getattr
, /*tp_getattr*/
707 newcdparserobject(CDPARSER
*cdp
)
712 p
= PyObject_New(cdparserobject
, &CdParsertype
);
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
;
720 return (PyObject
*) p
;
724 CD_createparser(PyObject
*self
, PyObject
*args
)
728 if (!PyArg_ParseTuple(args
, ":createparser"))
730 cdp
= CDcreateparser();
732 PyErr_SetString(CdError
, "createparser failed");
736 return newcdparserobject(cdp
);
740 CD_msftoframe(PyObject
*self
, PyObject
*args
)
744 if (!PyArg_ParseTuple(args
, "iii:msftoframe", &min
, &sec
, &frame
))
747 return PyInt_FromLong((long) CDmsftoframe(min
, sec
, frame
));
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 */
762 m
= Py_InitModule("cd", CD_methods
);
765 d
= PyModule_GetDict(m
);
767 CdError
= PyErr_NewException("cd.error", NULL
, NULL
);
768 PyDict_SetItemString(d
, "error", CdError
);
770 /* Identifiers for the different types of callbacks from the parser */
771 PyDict_SetItemString(d
, "audio", PyInt_FromLong((long) cd_audio
));
772 PyDict_SetItemString(d
, "pnum", PyInt_FromLong((long) cd_pnum
));
773 PyDict_SetItemString(d
, "index", PyInt_FromLong((long) cd_index
));
774 PyDict_SetItemString(d
, "ptime", PyInt_FromLong((long) cd_ptime
));
775 PyDict_SetItemString(d
, "atime", PyInt_FromLong((long) cd_atime
));
776 PyDict_SetItemString(d
, "catalog", PyInt_FromLong((long) cd_catalog
));
777 PyDict_SetItemString(d
, "ident", PyInt_FromLong((long) cd_ident
));
778 PyDict_SetItemString(d
, "control", PyInt_FromLong((long) cd_control
));
780 /* Block size information for digital audio data */
781 PyDict_SetItemString(d
, "DATASIZE",
782 PyInt_FromLong((long) CDDA_DATASIZE
));
783 PyDict_SetItemString(d
, "BLOCKSIZE",
784 PyInt_FromLong((long) CDDA_BLOCKSIZE
));
786 /* Possible states for the cd player */
787 PyDict_SetItemString(d
, "ERROR", PyInt_FromLong((long) CD_ERROR
));
788 PyDict_SetItemString(d
, "NODISC", PyInt_FromLong((long) CD_NODISC
));
789 PyDict_SetItemString(d
, "READY", PyInt_FromLong((long) CD_READY
));
790 PyDict_SetItemString(d
, "PLAYING", PyInt_FromLong((long) CD_PLAYING
));
791 PyDict_SetItemString(d
, "PAUSED", PyInt_FromLong((long) CD_PAUSED
));
792 PyDict_SetItemString(d
, "STILL", PyInt_FromLong((long) CD_STILL
));
793 #ifdef CD_CDROM /* only newer versions of the library */
794 PyDict_SetItemString(d
, "CDROM", PyInt_FromLong((long) CD_CDROM
));