1 /**********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI or Corporation for National Research Initiatives or
13 CNRI not be used in advertising or publicity pertaining to
14 distribution of the software without specific, written prior
17 While CWI is the initial source for this software, a modified version
18 is made available by the Corporation for National Research Initiatives
19 (CNRI) at the Internet address ftp://ftp.python.org.
21 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28 PERFORMANCE OF THIS SOFTWARE.
30 ******************************************************************/
32 /* CD module -- interface to Mark Callow's and Roger Chickering's */
33 /* CD Audio Library (CD). */
35 #include <sys/types.h>
43 CDPLAYER
*ob_cdplayer
;
46 static PyObject
*CdError
; /* exception cd.error */
49 CD_allowremoval(self
, args
)
53 if (!PyArg_ParseTuple(args
, ""))
56 CDallowremoval(self
->ob_cdplayer
);
63 CD_preventremoval(self
, args
)
67 if (!PyArg_ParseTuple(args
, ""))
70 CDpreventremoval(self
->ob_cdplayer
);
77 CD_bestreadsize(self
, args
)
81 if (!PyArg_ParseTuple(args
, ""))
84 return PyInt_FromLong((long) CDbestreadsize(self
->ob_cdplayer
));
92 if (!PyArg_ParseTuple(args
, ""))
95 if (!CDclose(self
->ob_cdplayer
)) {
96 PyErr_SetFromErrno(CdError
); /* XXX - ??? */
99 self
->ob_cdplayer
= NULL
;
107 cdplayerobject
*self
;
112 if (!PyArg_ParseTuple(args
, ""))
115 if (!CDeject(self
->ob_cdplayer
)) {
116 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
117 status
.state
== CD_NODISC
)
118 PyErr_SetString(CdError
, "no disc in player");
120 PyErr_SetString(CdError
, "eject failed");
129 CD_getstatus(self
, args
)
130 cdplayerobject
*self
;
135 if (!PyArg_ParseTuple(args
, ""))
138 if (!CDgetstatus(self
->ob_cdplayer
, &status
)) {
139 PyErr_SetFromErrno(CdError
); /* XXX - ??? */
143 return Py_BuildValue("(ii(iii)(iii)(iii)iiii)", status
.state
,
144 status
.track
, status
.min
, status
.sec
, status
.frame
,
145 status
.abs_min
, status
.abs_sec
, status
.abs_frame
,
146 status
.total_min
, status
.total_sec
, status
.total_frame
,
147 status
.first
, status
.last
, status
.scsi_audio
,
152 CD_gettrackinfo(self
, args
)
153 cdplayerobject
*self
;
160 if (!PyArg_ParseTuple(args
, "i", &track
))
163 if (!CDgettrackinfo(self
->ob_cdplayer
, track
, &info
)) {
164 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
165 status
.state
== CD_NODISC
)
166 PyErr_SetString(CdError
, "no disc in player");
168 PyErr_SetString(CdError
, "gettrackinfo failed");
172 return Py_BuildValue("((iii)(iii))",
173 info
.start_min
, info
.start_sec
, info
.start_frame
,
174 info
.total_min
, info
.total_sec
, info
.total_frame
);
178 CD_msftoblock(self
, args
)
179 cdplayerobject
*self
;
184 if (!PyArg_ParseTuple(args
, "iii", &min
, &sec
, &frame
))
187 return PyInt_FromLong((long) CDmsftoblock(self
->ob_cdplayer
,
193 cdplayerobject
*self
;
199 if (!PyArg_ParseTuple(args
, "ii", &start
, &play
))
202 if (!CDplay(self
->ob_cdplayer
, start
, play
)) {
203 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
204 status
.state
== CD_NODISC
)
205 PyErr_SetString(CdError
, "no disc in player");
207 PyErr_SetString(CdError
, "play failed");
216 CD_playabs(self
, args
)
217 cdplayerobject
*self
;
220 int min
, sec
, frame
, play
;
223 if (!PyArg_ParseTuple(args
, "iiii", &min
, &sec
, &frame
, &play
))
226 if (!CDplayabs(self
->ob_cdplayer
, min
, sec
, frame
, play
)) {
227 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
228 status
.state
== CD_NODISC
)
229 PyErr_SetString(CdError
, "no disc in player");
231 PyErr_SetString(CdError
, "playabs failed");
240 CD_playtrack(self
, args
)
241 cdplayerobject
*self
;
247 if (!PyArg_ParseTuple(args
, "ii", &start
, &play
))
250 if (!CDplaytrack(self
->ob_cdplayer
, start
, play
)) {
251 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
252 status
.state
== CD_NODISC
)
253 PyErr_SetString(CdError
, "no disc in player");
255 PyErr_SetString(CdError
, "playtrack failed");
264 CD_playtrackabs(self
, args
)
265 cdplayerobject
*self
;
268 int track
, min
, sec
, frame
, play
;
271 if (!PyArg_ParseTuple(args
, "iiiii", &track
, &min
, &sec
,
275 if (!CDplaytrackabs(self
->ob_cdplayer
, track
, min
, sec
, frame
, play
)) {
276 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
277 status
.state
== CD_NODISC
)
278 PyErr_SetString(CdError
, "no disc in player");
280 PyErr_SetString(CdError
, "playtrackabs failed");
289 CD_readda(self
, args
)
290 cdplayerobject
*self
;
296 if (!PyArg_ParseTuple(args
, "i", &numframes
))
299 result
= PyString_FromStringAndSize(NULL
, numframes
* sizeof(CDFRAME
));
303 n
= CDreadda(self
->ob_cdplayer
,
304 (CDFRAME
*) PyString_AsString(result
), numframes
);
307 PyErr_SetFromErrno(CdError
);
311 if (_PyString_Resize(&result
, n
* sizeof(CDFRAME
)))
319 cdplayerobject
*self
;
325 if (!PyArg_ParseTuple(args
, "iii", &min
, &sec
, &frame
))
328 PyTryBlock
= CDseek(self
->ob_cdplayer
, min
, sec
, frame
);
329 if (PyTryBlock
== -1) {
330 PyErr_SetFromErrno(CdError
);
334 return PyInt_FromLong(PyTryBlock
);
338 CD_seektrack(self
, args
)
339 cdplayerobject
*self
;
345 if (!PyArg_ParseTuple(args
, "i", &track
))
348 PyTryBlock
= CDseektrack(self
->ob_cdplayer
, track
);
349 if (PyTryBlock
== -1) {
350 PyErr_SetFromErrno(CdError
);
354 return PyInt_FromLong(PyTryBlock
);
358 CD_seekblock(self
, args
)
359 cdplayerobject
*self
;
362 unsigned long PyTryBlock
;
364 if (!PyArg_ParseTuple(args
, "l", &PyTryBlock
))
367 PyTryBlock
= CDseekblock(self
->ob_cdplayer
, PyTryBlock
);
368 if (PyTryBlock
== (unsigned long) -1) {
369 PyErr_SetFromErrno(CdError
);
373 return PyInt_FromLong(PyTryBlock
);
378 cdplayerobject
*self
;
383 if (!PyArg_ParseTuple(args
, ""))
386 if (!CDstop(self
->ob_cdplayer
)) {
387 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
388 status
.state
== CD_NODISC
)
389 PyErr_SetString(CdError
, "no disc in player");
391 PyErr_SetString(CdError
, "stop failed");
400 CD_togglepause(self
, args
)
401 cdplayerobject
*self
;
406 if (!PyArg_ParseTuple(args
, ""))
409 if (!CDtogglepause(self
->ob_cdplayer
)) {
410 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
411 status
.state
== CD_NODISC
)
412 PyErr_SetString(CdError
, "no disc in player");
414 PyErr_SetString(CdError
, "togglepause failed");
422 static PyMethodDef cdplayer_methods
[] = {
423 {"allowremoval", (PyCFunction
)CD_allowremoval
, 1},
424 {"bestreadsize", (PyCFunction
)CD_bestreadsize
, 1},
425 {"close", (PyCFunction
)CD_close
, 1},
426 {"eject", (PyCFunction
)CD_eject
, 1},
427 {"getstatus", (PyCFunction
)CD_getstatus
, 1},
428 {"gettrackinfo", (PyCFunction
)CD_gettrackinfo
, 1},
429 {"msftoblock", (PyCFunction
)CD_msftoblock
, 1},
430 {"play", (PyCFunction
)CD_play
, 1},
431 {"playabs", (PyCFunction
)CD_playabs
, 1},
432 {"playtrack", (PyCFunction
)CD_playtrack
, 1},
433 {"playtrackabs", (PyCFunction
)CD_playtrackabs
, 1},
434 {"preventremoval", (PyCFunction
)CD_preventremoval
, 1},
435 {"readda", (PyCFunction
)CD_readda
, 1},
436 {"seek", (PyCFunction
)CD_seek
, 1},
437 {"seekblock", (PyCFunction
)CD_seekblock
, 1},
438 {"seektrack", (PyCFunction
)CD_seektrack
, 1},
439 {"stop", (PyCFunction
)CD_stop
, 1},
440 {"togglepause", (PyCFunction
)CD_togglepause
, 1},
441 {NULL
, NULL
} /* sentinel */
445 cdplayer_dealloc(self
)
446 cdplayerobject
*self
;
448 if (self
->ob_cdplayer
!= NULL
)
449 CDclose(self
->ob_cdplayer
);
454 cdplayer_getattr(self
, name
)
455 cdplayerobject
*self
;
458 if (self
->ob_cdplayer
== NULL
) {
459 PyErr_SetString(PyExc_RuntimeError
, "no player active");
462 return Py_FindMethod(cdplayer_methods
, (PyObject
*)self
, name
);
465 PyTypeObject CdPlayertype
= {
466 PyObject_HEAD_INIT(&PyType_Type
)
468 "cdplayer", /*tp_name*/
469 sizeof(cdplayerobject
), /*tp_size*/
472 (destructor
)cdplayer_dealloc
, /*tp_dealloc*/
474 (getattrfunc
)cdplayer_getattr
, /*tp_getattr*/
481 newcdplayerobject(cdp
)
486 p
= PyObject_NEW(cdplayerobject
, &CdPlayertype
);
489 p
->ob_cdplayer
= cdp
;
490 return (PyObject
*) p
;
495 PyObject
*self
, *args
;
497 char *dev
, *direction
;
501 * Variable number of args.
502 * First defaults to "None", second defaults to "r".
506 if (!PyArg_ParseTuple(args
, "|zs", &dev
, &direction
))
509 cdp
= CDopen(dev
, direction
);
511 PyErr_SetFromErrno(CdError
);
515 return newcdplayerobject(cdp
);
520 CDPARSER
*ob_cdparser
;
522 PyObject
*ob_cdcallback
;
523 PyObject
*ob_cdcallbackarg
;
524 } ob_cdcallbacks
[NCALLBACKS
];
528 CD_callback(arg
, type
, data
)
533 PyObject
*result
, *args
, *v
= NULL
;
536 cdparserobject
*self
;
538 self
= (cdparserobject
*) arg
;
539 args
= PyTuple_New(3);
542 Py_INCREF(self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
543 PyTuple_SetItem(args
, 0, self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
544 PyTuple_SetItem(args
, 1, PyInt_FromLong((long) type
));
547 v
= PyString_FromStringAndSize(data
, CDDA_DATASIZE
);
551 v
= PyInt_FromLong(((CDPROGNUM
*) data
)->value
);
555 #define ptr ((struct cdtimecode *) data)
556 v
= Py_BuildValue("(iii)",
557 ptr
->mhi
* 10 + ptr
->mlo
,
558 ptr
->shi
* 10 + ptr
->slo
,
559 ptr
->fhi
* 10 + ptr
->flo
);
563 v
= PyString_FromStringAndSize(NULL
, 13);
564 p
= PyString_AsString(v
);
565 for (i
= 0; i
< 13; i
++)
566 *p
++ = ((char *) data
)[i
] + '0';
569 #define ptr ((struct cdident *) data)
570 v
= PyString_FromStringAndSize(NULL
, 12);
571 p
= PyString_AsString(v
);
572 CDsbtoa(p
, ptr
->country
, 2);
574 CDsbtoa(p
, ptr
->owner
, 3);
576 *p
++ = ptr
->year
[0] + '0';
577 *p
++ = ptr
->year
[1] + '0';
578 *p
++ = ptr
->serial
[0] + '0';
579 *p
++ = ptr
->serial
[1] + '0';
580 *p
++ = ptr
->serial
[2] + '0';
581 *p
++ = ptr
->serial
[3] + '0';
582 *p
++ = ptr
->serial
[4] + '0';
586 v
= PyInt_FromLong((long) *((unchar
*) data
));
589 PyTuple_SetItem(args
, 2, v
);
590 if (PyErr_Occurred()) {
595 result
= PyEval_CallObject(self
->ob_cdcallbacks
[type
].ob_cdcallback
,
602 CD_deleteparser(self
, args
)
603 cdparserobject
*self
;
608 if (!PyArg_ParseTuple(args
, ""))
611 CDdeleteparser(self
->ob_cdparser
);
612 self
->ob_cdparser
= NULL
;
614 /* no sense in keeping the callbacks, so remove them */
615 for (i
= 0; i
< NCALLBACKS
; i
++) {
616 Py_XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallback
);
617 self
->ob_cdcallbacks
[i
].ob_cdcallback
= NULL
;
618 Py_XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
);
619 self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
= NULL
;
627 CD_parseframe(self
, args
)
628 cdparserobject
*self
;
635 if (!PyArg_ParseTuple(args
, "s#", &cdfp
, &length
))
638 if (length
% sizeof(CDFRAME
) != 0) {
639 PyErr_SetString(PyExc_TypeError
, "bad length");
643 p
= (CDFRAME
*) cdfp
;
645 CDparseframe(self
->ob_cdparser
, p
);
646 length
-= sizeof(CDFRAME
);
648 if (PyErr_Occurred())
657 CD_removecallback(self
, args
)
658 cdparserobject
*self
;
663 if (!PyArg_ParseTuple(args
, "i", &type
))
666 if (type
< 0 || type
>= NCALLBACKS
) {
667 PyErr_SetString(PyExc_TypeError
, "bad type");
671 CDremovecallback(self
->ob_cdparser
, (CDDATATYPES
) type
);
673 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallback
);
674 self
->ob_cdcallbacks
[type
].ob_cdcallback
= NULL
;
676 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
677 self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
= NULL
;
684 CD_resetparser(self
, args
)
685 cdparserobject
*self
;
688 if (!PyArg_ParseTuple(args
, ""))
691 CDresetparser(self
->ob_cdparser
);
698 CD_addcallback(self
, args
)
699 cdparserobject
*self
;
703 PyObject
*func
, *funcarg
;
705 /* XXX - more work here */
706 if (!PyArg_ParseTuple(args
, "iOO", &type
, &func
, &funcarg
))
709 if (type
< 0 || type
>= NCALLBACKS
) {
710 PyErr_SetString(PyExc_TypeError
, "argument out of range");
715 CDaddcallback(self
->ob_cdparser
, (CDDATATYPES
) type
, CD_callback
,
718 CDsetcallback(self
->ob_cdparser
, (CDDATATYPES
) type
, CD_callback
,
721 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallback
);
723 self
->ob_cdcallbacks
[type
].ob_cdcallback
= func
;
724 Py_XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
726 self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
= funcarg
;
729 if (type == cd_audio) {
730 sigfpe_[_UNDERFL].repls = _ZERO;
731 handle_sigfpes(_ON, _EN_UNDERFL, NULL,
732 _ABORT_ON_ERROR, NULL);
740 static PyMethodDef cdparser_methods
[] = {
741 {"addcallback", (PyCFunction
)CD_addcallback
, 1},
742 {"deleteparser", (PyCFunction
)CD_deleteparser
, 1},
743 {"parseframe", (PyCFunction
)CD_parseframe
, 1},
744 {"removecallback", (PyCFunction
)CD_removecallback
, 1},
745 {"resetparser", (PyCFunction
)CD_resetparser
, 1},
746 /* backward compatibility */
747 {"setcallback", (PyCFunction
)CD_addcallback
, 1},
748 {NULL
, NULL
} /* sentinel */
752 cdparser_dealloc(self
)
753 cdparserobject
*self
;
757 for (i
= 0; i
< NCALLBACKS
; i
++) {
758 Py_XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallback
);
759 self
->ob_cdcallbacks
[i
].ob_cdcallback
= NULL
;
760 Py_XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
);
761 self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
= NULL
;
763 CDdeleteparser(self
->ob_cdparser
);
768 cdparser_getattr(self
, name
)
769 cdparserobject
*self
;
772 if (self
->ob_cdparser
== NULL
) {
773 PyErr_SetString(PyExc_RuntimeError
, "no parser active");
777 return Py_FindMethod(cdparser_methods
, (PyObject
*)self
, name
);
780 PyTypeObject CdParsertype
= {
781 PyObject_HEAD_INIT(&PyType_Type
)
783 "cdparser", /*tp_name*/
784 sizeof(cdparserobject
), /*tp_size*/
787 (destructor
)cdparser_dealloc
, /*tp_dealloc*/
789 (getattrfunc
)cdparser_getattr
, /*tp_getattr*/
796 newcdparserobject(cdp
)
802 p
= PyObject_NEW(cdparserobject
, &CdParsertype
);
805 p
->ob_cdparser
= cdp
;
806 for (i
= 0; i
< NCALLBACKS
; i
++) {
807 p
->ob_cdcallbacks
[i
].ob_cdcallback
= NULL
;
808 p
->ob_cdcallbacks
[i
].ob_cdcallbackarg
= NULL
;
810 return (PyObject
*) p
;
814 CD_createparser(self
, args
)
815 PyObject
*self
, *args
;
819 if (!PyArg_ParseTuple(args
, ""))
821 cdp
= CDcreateparser();
823 PyErr_SetString(CdError
, "createparser failed");
827 return newcdparserobject(cdp
);
831 CD_msftoframe(self
, args
)
832 PyObject
*self
, *args
;
836 if (!PyArg_ParseTuple(args
, "iii", &min
, &sec
, &frame
))
839 return PyInt_FromLong((long) CDmsftoframe(min
, sec
, frame
));
842 static PyMethodDef CD_methods
[] = {
843 {"open", (PyCFunction
)CD_open
, 1},
844 {"createparser", (PyCFunction
)CD_createparser
, 1},
845 {"msftoframe", (PyCFunction
)CD_msftoframe
, 1},
846 {NULL
, NULL
} /* Sentinel */
854 m
= Py_InitModule("cd", CD_methods
);
855 d
= PyModule_GetDict(m
);
857 CdError
= PyErr_NewException("cd.error", NULL
, NULL
);
858 PyDict_SetItemString(d
, "error", CdError
);
860 /* Identifiers for the different types of callbacks from the parser */
861 PyDict_SetItemString(d
, "audio", PyInt_FromLong((long) cd_audio
));
862 PyDict_SetItemString(d
, "pnum", PyInt_FromLong((long) cd_pnum
));
863 PyDict_SetItemString(d
, "index", PyInt_FromLong((long) cd_index
));
864 PyDict_SetItemString(d
, "ptime", PyInt_FromLong((long) cd_ptime
));
865 PyDict_SetItemString(d
, "atime", PyInt_FromLong((long) cd_atime
));
866 PyDict_SetItemString(d
, "catalog", PyInt_FromLong((long) cd_catalog
));
867 PyDict_SetItemString(d
, "ident", PyInt_FromLong((long) cd_ident
));
868 PyDict_SetItemString(d
, "control", PyInt_FromLong((long) cd_control
));
870 /* Block size information for digital audio data */
871 PyDict_SetItemString(d
, "DATASIZE",
872 PyInt_FromLong((long) CDDA_DATASIZE
));
873 PyDict_SetItemString(d
, "BLOCKSIZE",
874 PyInt_FromLong((long) CDDA_BLOCKSIZE
));
876 /* Possible states for the cd player */
877 PyDict_SetItemString(d
, "ERROR", PyInt_FromLong((long) CD_ERROR
));
878 PyDict_SetItemString(d
, "NODISC", PyInt_FromLong((long) CD_NODISC
));
879 PyDict_SetItemString(d
, "READY", PyInt_FromLong((long) CD_READY
));
880 PyDict_SetItemString(d
, "PLAYING", PyInt_FromLong((long) CD_PLAYING
));
881 PyDict_SetItemString(d
, "PAUSED", PyInt_FromLong((long) CD_PAUSED
));
882 PyDict_SetItemString(d
, "STILL", PyInt_FromLong((long) CD_STILL
));
883 #ifdef CD_CDROM /* only newer versions of the library */
884 PyDict_SetItemString(d
, "CDROM", PyInt_FromLong((long) CD_CDROM
));
887 if (PyErr_Occurred())
888 Py_FatalError("can't initialize module cd");