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 not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* CD module -- interface to Mark Callow's and Roger Chickering's */
26 /* CD Audio Library (CD). */
28 #include <sys/types.h>
30 #include "allobjects.h"
32 #include "modsupport.h"
39 CDPLAYER
*ob_cdplayer
;
42 #define CheckPlayer(self) if ((self)->ob_cdplayer == NULL) { \
43 err_setstr(RuntimeError, "no player active"); \
46 #define CheckParser(self) if ((self)->ob_cdparser == NULL) { \
47 err_setstr(RuntimeError, "no parser active"); \
51 static object
*CdError
; /* exception cd.error */
54 CD_allowremoval(self
, args
)
63 CDallowremoval(self
->ob_cdplayer
);
70 CD_preventremoval(self
, args
)
79 CDpreventremoval(self
->ob_cdplayer
);
86 CD_bestreadsize(self
, args
)
95 return newintobject((long) CDbestreadsize(self
->ob_cdplayer
));
100 cdplayerobject
*self
;
108 if (!CDclose(self
->ob_cdplayer
)) {
109 err_errno(CdError
); /* XXX - ??? */
112 self
->ob_cdplayer
= NULL
;
120 cdplayerobject
*self
;
130 if (!CDeject(self
->ob_cdplayer
)) {
131 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
132 status
.state
== CD_NODISC
)
133 err_setstr(CdError
, "no disc in player");
135 err_setstr(CdError
, "eject failed");
144 CD_getstatus(self
, args
)
145 cdplayerobject
*self
;
155 if (!CDgetstatus(self
->ob_cdplayer
, &status
)) {
156 err_errno(CdError
); /* XXX - ??? */
160 return mkvalue("(ii(iii)(iii)(iii)iiii(iii))", status
.state
,
161 status
.track
, status
.min
, status
.sec
, status
.frame
,
162 status
.abs_min
, status
.abs_sec
, status
.abs_frame
,
163 status
.total_min
, status
.total_sec
, status
.total_frame
,
164 status
.first
, status
.last
, status
.scsi_audio
,
165 status
.cur_block
, status
.polyfilla
[0],
166 status
.polyfilla
[1], status
.polyfilla
[2]);
170 CD_gettrackinfo(self
, args
)
171 cdplayerobject
*self
;
180 if (!getargs(args
, "i", &track
))
183 if (!CDgettrackinfo(self
->ob_cdplayer
, track
, &info
)) {
184 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
185 status
.state
== CD_NODISC
)
186 err_setstr(CdError
, "no disc in player");
188 err_setstr(CdError
, "gettrackinfo failed");
192 return mkvalue("((iii)(iii))",
193 info
.start_min
, info
.start_sec
, info
.start_frame
,
194 info
.total_min
, info
.total_sec
, info
.total_frame
);
198 CD_msftoblock(self
, args
)
199 cdplayerobject
*self
;
207 if (!getargs(args
, "(iii)", &min
, &sec
, &frame
))
210 block
= CDmsftoblock(self
->ob_cdplayer
, min
, sec
, frame
);
211 return newintobject((long) block
);
216 cdplayerobject
*self
;
224 if (!getargs(args
, "(ii)", &start
, &play
))
227 if (!CDplay(self
->ob_cdplayer
, start
, play
)) {
228 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
229 status
.state
== CD_NODISC
)
230 err_setstr(CdError
, "no disc in player");
232 err_setstr(CdError
, "play failed");
241 CD_playabs(self
, args
)
242 cdplayerobject
*self
;
245 int min
, sec
, frame
, play
;
250 if (!getargs(args
, "(iiii)", &min
, &sec
, &frame
, &play
))
253 if (!CDplayabs(self
->ob_cdplayer
, min
, sec
, frame
, play
)) {
254 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
255 status
.state
== CD_NODISC
)
256 err_setstr(CdError
, "no disc in player");
258 err_setstr(CdError
, "playabs failed");
267 CD_playtrack(self
, args
)
268 cdplayerobject
*self
;
276 if (!getargs(args
, "(ii)", &start
, &play
))
279 if (!CDplaytrack(self
->ob_cdplayer
, start
, play
)) {
280 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
281 status
.state
== CD_NODISC
)
282 err_setstr(CdError
, "no disc in player");
284 err_setstr(CdError
, "playtrack failed");
293 CD_playtrackabs(self
, args
)
294 cdplayerobject
*self
;
297 int track
, min
, sec
, frame
, play
;
302 if (!getargs(args
, "(iiiii)", &track
, &min
, &sec
, &frame
, &play
))
305 if (!CDplaytrackabs(self
->ob_cdplayer
, track
, min
, sec
, frame
, play
)) {
306 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
307 status
.state
== CD_NODISC
)
308 err_setstr(CdError
, "no disc in player");
310 err_setstr(CdError
, "playtrackabs failed");
319 CD_readda(self
, args
)
320 cdplayerobject
*self
;
328 if (!getargs(args
, "i", &numframes
))
331 result
= newsizedstringobject(NULL
, numframes
* sizeof(CDFRAME
));
335 n
= CDreadda(self
->ob_cdplayer
, (CDFRAME
*) getstringvalue(result
), numframes
);
342 if (resizestring(&result
, n
* sizeof(CDFRAME
)))
350 cdplayerobject
*self
;
358 if (!getargs(args
, "(iii)", &min
, &sec
, &frame
))
361 block
= CDseek(self
->ob_cdplayer
, min
, sec
, frame
);
367 return newintobject(block
);
371 CD_seektrack(self
, args
)
372 cdplayerobject
*self
;
380 if (!getargs(args
, "i", &track
))
383 block
= CDseektrack(self
->ob_cdplayer
, track
);
389 return newintobject(block
);
394 cdplayerobject
*self
;
404 if (!CDstop(self
->ob_cdplayer
)) {
405 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
406 status
.state
== CD_NODISC
)
407 err_setstr(CdError
, "no disc in player");
409 err_setstr(CdError
, "stop failed");
418 CD_togglepause(self
, args
)
419 cdplayerobject
*self
;
429 if (!CDtogglepause(self
->ob_cdplayer
)) {
430 if (CDgetstatus(self
->ob_cdplayer
, &status
) &&
431 status
.state
== CD_NODISC
)
432 err_setstr(CdError
, "no disc in player");
434 err_setstr(CdError
, "togglepause failed");
442 static struct methodlist cdplayer_methods
[] = {
443 {"allowremoval", (method
)CD_allowremoval
},
444 {"bestreadsize", (method
)CD_bestreadsize
},
445 {"close", (method
)CD_close
},
446 {"eject", (method
)CD_eject
},
447 {"getstatus", (method
)CD_getstatus
},
448 {"gettrackinfo", (method
)CD_gettrackinfo
},
449 {"msftoblock", (method
)CD_msftoblock
},
450 {"play", (method
)CD_play
},
451 {"playabs", (method
)CD_playabs
},
452 {"playtrack", (method
)CD_playtrack
},
453 {"playtrackabs", (method
)CD_playtrackabs
},
454 {"preventremoval", (method
)CD_preventremoval
},
455 {"readda", (method
)CD_readda
},
456 {"seek", (method
)CD_seek
},
457 {"seektrack", (method
)CD_seektrack
},
458 {"stop", (method
)CD_stop
},
459 {"togglepause", (method
)CD_togglepause
},
460 {NULL
, NULL
} /* sentinel */
464 cdplayer_dealloc(self
)
465 cdplayerobject
*self
;
467 if (self
->ob_cdplayer
!= NULL
)
468 CDclose(self
->ob_cdplayer
);
473 cdplayer_getattr(cdp
, name
)
477 return findmethod(cdplayer_methods
, (object
*)cdp
, name
);
480 typeobject CdPlayertype
= {
481 OB_HEAD_INIT(&Typetype
)
483 "cdplayer", /*tp_name*/
484 sizeof(cdplayerobject
), /*tp_size*/
487 (destructor
)cdplayer_dealloc
, /*tp_dealloc*/
489 (getattrfunc
)cdplayer_getattr
, /*tp_getattr*/
496 newcdplayerobject(cdp
)
501 p
= NEWOBJ(cdplayerobject
, &CdPlayertype
);
504 p
->ob_cdplayer
= cdp
;
512 char *dev
, *direction
;
516 * Variable number of args.
517 * First defaults to "None", second defaults to "r".
521 if (!getnoarg(args
)) {
523 if (!getargs(args
, "z", &dev
)) {
525 if (!getargs(args
, "(zs)", &dev
, &direction
))
530 cdp
= CDopen(dev
, direction
);
536 return newcdplayerobject(cdp
);
541 CDPARSER
*ob_cdparser
;
543 object
*ob_cdcallback
;
544 object
*ob_cdcallbackarg
;
545 } ob_cdcallbacks
[NCALLBACKS
];
549 CD_callback(arg
, type
, data
)
554 object
*result
, *args
, *v
;
557 cdparserobject
*self
;
559 self
= (cdparserobject
*) arg
;
560 args
= newtupleobject(3);
563 INCREF(self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
564 settupleitem(args
, 0, self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
565 settupleitem(args
, 1, newintobject((long) type
));
568 v
= newsizedstringobject(data
, CDDA_DATASIZE
);
572 v
= newintobject(((CDPROGNUM
*) data
)->value
);
576 #define ptr ((struct cdtimecode *) data)
577 v
= mkvalue("(iii)", ptr
->mhi
* 10 + ptr
->mlo
,
578 ptr
->shi
* 10 + ptr
->slo
,
579 ptr
->fhi
* 10 + ptr
->flo
);
583 v
= newsizedstringobject(NULL
, 13);
584 p
= getstringvalue(v
);
585 for (i
= 0; i
< 13; i
++)
586 *p
++ = ((char *) data
)[i
] + '0';
589 v
= newsizedstringobject(NULL
, 12);
590 p
= getstringvalue(v
);
591 CDsbtoa(p
, ((struct cdident
*) data
)->country
, 2);
593 CDsbtoa(p
, ((struct cdident
*) data
)->owner
, 3);
595 *p
++ = ((struct cdident
*) data
)->year
[0] + '0';
596 *p
++ = ((struct cdident
*) data
)->year
[1] + '0';
597 *p
++ = ((struct cdident
*) data
)->serial
[0] + '0';
598 *p
++ = ((struct cdident
*) data
)->serial
[1] + '0';
599 *p
++ = ((struct cdident
*) data
)->serial
[2] + '0';
600 *p
++ = ((struct cdident
*) data
)->serial
[3] + '0';
601 *p
++ = ((struct cdident
*) data
)->serial
[4] + '0';
604 v
= newintobject((long) *((unchar
*) data
));
607 settupleitem(args
, 2, v
);
608 if (err_occurred()) {
613 result
= call_object(self
->ob_cdcallbacks
[type
].ob_cdcallback
, args
);
619 CD_deleteparser(self
, args
)
620 cdparserobject
*self
;
630 CDdeleteparser(self
->ob_cdparser
);
631 self
->ob_cdparser
= NULL
;
633 /* no sense in keeping the callbacks, so remove them */
634 for (i
= 0; i
< NCALLBACKS
; i
++) {
635 XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallback
);
636 self
->ob_cdcallbacks
[i
].ob_cdcallback
= NULL
;
637 XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
);
638 self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
= NULL
;
646 CD_parseframe(self
, args
)
647 cdparserobject
*self
;
656 if (!getargs(args
, "s#", &cdfp
, &length
))
659 if (length
% sizeof(CDFRAME
) != 0) {
660 err_setstr(TypeError
, "bad length");
664 p
= (CDFRAME
*) cdfp
;
666 CDparseframe(self
->ob_cdparser
, p
);
667 length
-= sizeof(CDFRAME
);
678 CD_removecallback(self
, args
)
679 cdparserobject
*self
;
686 if (!getargs(args
, "i", &type
))
689 if (type
< 0 || type
>= NCALLBACKS
) {
690 err_setstr(TypeError
, "bad type");
694 CDremovecallback(self
->ob_cdparser
, (CDDATATYPES
) type
);
696 XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallback
);
697 self
->ob_cdcallbacks
[type
].ob_cdcallback
= NULL
;
699 XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
700 self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
= NULL
;
707 CD_resetparser(self
, args
)
708 cdparserobject
*self
;
716 CDresetparser(self
->ob_cdparser
);
723 CD_addcallback(self
, args
)
724 cdparserobject
*self
;
728 object
*func
, *funcarg
;
732 /* XXX - more work here */
733 if (!getargs(args
, "(iOO)", &type
, &func
, &funcarg
))
736 if (type
< 0 || type
>= NCALLBACKS
) {
737 err_setstr(TypeError
, "argument out of range");
742 CDaddcallback(self
->ob_cdparser
, (CDDATATYPES
) type
, CD_callback
, (void *) self
);
744 CDsetcallback(self
->ob_cdparser
, (CDDATATYPES
) type
, CD_callback
, (void *) self
);
746 XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallback
);
748 self
->ob_cdcallbacks
[type
].ob_cdcallback
= func
;
749 XDECREF(self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
);
751 self
->ob_cdcallbacks
[type
].ob_cdcallbackarg
= funcarg
;
757 static struct methodlist cdparser_methods
[] = {
758 {"addcallback", (method
)CD_addcallback
},
759 {"deleteparser", (method
)CD_deleteparser
},
760 {"parseframe", (method
)CD_parseframe
},
761 {"removecallback", (method
)CD_removecallback
},
762 {"resetparser", (method
)CD_resetparser
},
763 {"setcallback", (method
)CD_addcallback
}, /* backward compatibility */
764 {NULL
, NULL
} /* sentinel */
768 cdparser_dealloc(self
)
769 cdparserobject
*self
;
773 for (i
= 0; i
< NCALLBACKS
; i
++) {
774 XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallback
);
775 self
->ob_cdcallbacks
[i
].ob_cdcallback
= NULL
;
776 XDECREF(self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
);
777 self
->ob_cdcallbacks
[i
].ob_cdcallbackarg
= NULL
;
779 CDdeleteparser(self
->ob_cdparser
);
784 cdparser_getattr(cdp
, name
)
788 return findmethod(cdparser_methods
, (object
*)cdp
, name
);
791 typeobject CdParsertype
= {
792 OB_HEAD_INIT(&Typetype
)
794 "cdparser", /*tp_name*/
795 sizeof(cdparserobject
), /*tp_size*/
798 (destructor
)cdparser_dealloc
, /*tp_dealloc*/
800 (getattrfunc
)cdparser_getattr
, /*tp_getattr*/
807 newcdparserobject(cdp
)
813 p
= NEWOBJ(cdparserobject
, &CdParsertype
);
816 p
->ob_cdparser
= cdp
;
817 for (i
= 0; i
< NCALLBACKS
; i
++) {
818 p
->ob_cdcallbacks
[i
].ob_cdcallback
= NULL
;
819 p
->ob_cdcallbacks
[i
].ob_cdcallbackarg
= NULL
;
825 CD_createparser(self
, args
)
832 cdp
= CDcreateparser();
834 err_setstr(CdError
, "createparser failed");
838 return newcdparserobject(cdp
);
850 if (!getargs(args
, "s#", &sb
, &length
))
852 result
= newsizedstringobject(NULL
, length
);
853 CDsbtoa(getstringvalue(result
), (unchar
*) sb
, length
);
858 CD_timetoa(self
, args
)
866 if (!getargs(args
, "s#", &tc
, &length
))
869 if (length
!= sizeof(struct cdtimecode
)) {
870 err_setstr(TypeError
, "bad length");
874 result
= newsizedstringobject(NULL
, 8);
875 CDtimetoa(getstringvalue(result
), (struct cdtimecode
*) tc
);
879 static struct methodlist CD_methods
[] = {
880 {"sbtoa", (method
)CD_sbtoa
},
881 {"open", (method
)CD_open
},
882 {"createparser",(method
)CD_createparser
},
883 {"timetoa", (method
)CD_timetoa
},
884 {NULL
, NULL
} /* Sentinel */
892 m
= initmodule("cd", CD_methods
);
893 d
= getmoduledict(m
);
895 CdError
= newstringobject("cd.error");
896 if (CdError
== NULL
|| dictinsert(d
, "error", CdError
) != 0)
897 fatal("can't define cd.error");