PageRenderTime 137ms CodeModel.GetById 30ms app.highlight 85ms RepoModel.GetById 16ms app.codeStats 0ms

/Modules/cdmodule.c

http://unladen-swallow.googlecode.com/
C | 800 lines | 646 code | 133 blank | 21 comment | 96 complexity | 011cbefc1db862a58526c6edcf2d2cac MD5 | raw file
  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
 10typedef struct {
 11	PyObject_HEAD
 12	CDPLAYER *ob_cdplayer;
 13} cdplayerobject;
 14
 15static PyObject *CdError;		/* exception cd.error */
 16
 17static PyObject *
 18CD_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
 29static PyObject *
 30CD_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
 41static PyObject *
 42CD_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
 50static PyObject *
 51CD_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
 66static PyObject *
 67CD_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	
 87static PyObject *
 88CD_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	
108static PyObject *
109CD_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	
132static PyObject *
133CD_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	
144static PyObject *
145CD_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	
166static PyObject *
167CD_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	
188static PyObject *
189CD_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	
210static PyObject *
211CD_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	
233static PyObject *
234CD_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
259static PyObject *
260CD_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	
277static PyObject *
278CD_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	
295static PyObject *
296CD_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	
312static PyObject *
313CD_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	
333static PyObject *
334CD_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	
354static 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
376static void
377cdplayer_dealloc(cdplayerobject *self)
378{
379	if (self->ob_cdplayer != NULL)
380		CDclose(self->ob_cdplayer);
381	PyObject_Del(self);
382}
383
384static PyObject *
385cdplayer_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
394PyTypeObject 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
409static PyObject *
410newcdplayerobject(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
421static PyObject *
422CD_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
445typedef 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
454static void
455CD_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
525static PyObject *
526CD_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
548static PyObject *
549CD_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
576static PyObject *
577CD_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
601static PyObject *
602CD_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
613static PyObject *
614CD_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
654static 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
665static void
666cdparser_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
680static PyObject *
681cdparser_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
691PyTypeObject 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
706static PyObject *
707newcdparserobject(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
723static PyObject *
724CD_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
739static PyObject *
740CD_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	
750static 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
757void
758initcd(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}