cdmodule.c 20.1 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1
/**********************************************************
2 3
Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
The Netherlands.
Guido van Rossum's avatar
Guido van Rossum committed
4 5 6

                        All Rights Reserved

7 8
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
Guido van Rossum's avatar
Guido van Rossum committed
9
provided that the above copyright notice appear in all copies and that
10
both that copyright notice and this permission notice appear in
Guido van Rossum's avatar
Guido van Rossum committed
11
supporting documentation, and that the names of Stichting Mathematisch
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
Centrum or CWI or Corporation for National Research Initiatives or
CNRI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.

While CWI is the initial source for this software, a modified version
is made available by the Corporation for National Research Initiatives
(CNRI) at the Internet address ftp://ftp.python.org.

STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
Guido van Rossum's avatar
Guido van Rossum committed
29 30 31 32 33 34 35 36

******************************************************************/

/* CD module -- interface to Mark Callow's and Roger Chickering's */
 /* CD Audio Library (CD). */

#include <sys/types.h>
#include <cdaudio.h>
37
#include "Python.h"
Guido van Rossum's avatar
Guido van Rossum committed
38 39 40 41

#define NCALLBACKS	8

typedef struct {
42
	PyObject_HEAD
Guido van Rossum's avatar
Guido van Rossum committed
43 44 45
	CDPLAYER *ob_cdplayer;
} cdplayerobject;

46
static PyObject *CdError;		/* exception cd.error */
47

48
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
49 50
CD_allowremoval(self, args)
	cdplayerobject *self;
51
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
52
{
53
	if (!PyArg_ParseTuple(args, ""))
Guido van Rossum's avatar
Guido van Rossum committed
54 55 56 57
		return NULL;

	CDallowremoval(self->ob_cdplayer);

58 59
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
60 61
}

62
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
63 64
CD_preventremoval(self, args)
	cdplayerobject *self;
65
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
66
{
67
	if (!PyArg_ParseTuple(args, ""))
Guido van Rossum's avatar
Guido van Rossum committed
68 69 70 71
		return NULL;

	CDpreventremoval(self->ob_cdplayer);

72 73
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
74 75
}

76
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
77 78
CD_bestreadsize(self, args)
	cdplayerobject *self;
79
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
80
{
81
	if (!PyArg_ParseTuple(args, ""))
Guido van Rossum's avatar
Guido van Rossum committed
82 83
		return NULL;

84
	return PyInt_FromLong((long) CDbestreadsize(self->ob_cdplayer));
Guido van Rossum's avatar
Guido van Rossum committed
85 86
}

87
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
88 89
CD_close(self, args)
	cdplayerobject *self;
90
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
91
{
92
	if (!PyArg_ParseTuple(args, ""))
Guido van Rossum's avatar
Guido van Rossum committed
93 94 95
		return NULL;

	if (!CDclose(self->ob_cdplayer)) {
96
		PyErr_SetFromErrno(CdError); /* XXX - ??? */
Guido van Rossum's avatar
Guido van Rossum committed
97 98 99 100
		return NULL;
	}
	self->ob_cdplayer = NULL;

101 102
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
103 104
}

105
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
106 107
CD_eject(self, args)
	cdplayerobject *self;
108
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
109
{
110 111
	CDSTATUS status;

112
	if (!PyArg_ParseTuple(args, ""))
Guido van Rossum's avatar
Guido van Rossum committed
113 114 115
		return NULL;

	if (!CDeject(self->ob_cdplayer)) {
116 117
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
118
			PyErr_SetString(CdError, "no disc in player");
119
		else
120
			PyErr_SetString(CdError, "eject failed");
Guido van Rossum's avatar
Guido van Rossum committed
121 122 123
		return NULL;
	}

124 125
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
126 127
}
	
128
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
129 130
CD_getstatus(self, args)
	cdplayerobject *self;
131
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
132 133 134
{
	CDSTATUS status;

135
	if (!PyArg_ParseTuple(args, ""))
Guido van Rossum's avatar
Guido van Rossum committed
136 137 138
		return NULL;

	if (!CDgetstatus(self->ob_cdplayer, &status)) {
139
		PyErr_SetFromErrno(CdError); /* XXX - ??? */
Guido van Rossum's avatar
Guido van Rossum committed
140 141 142
		return NULL;
	}

143
	return Py_BuildValue("(ii(iii)(iii)(iii)iiii)", status.state,
144 145 146 147
		       status.track, status.min, status.sec, status.frame,
		       status.abs_min, status.abs_sec, status.abs_frame,
		       status.total_min, status.total_sec, status.total_frame,
		       status.first, status.last, status.scsi_audio,
148
		       status.cur_block);
Guido van Rossum's avatar
Guido van Rossum committed
149 150
}
	
151
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
152 153
CD_gettrackinfo(self, args)
	cdplayerobject *self;
154
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
155 156 157
{
	int track;
	CDTRACKINFO info;
158
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
159

160
	if (!PyArg_ParseTuple(args, "i", &track))
Guido van Rossum's avatar
Guido van Rossum committed
161 162 163
		return NULL;

	if (!CDgettrackinfo(self->ob_cdplayer, track, &info)) {
164 165
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
166
			PyErr_SetString(CdError, "no disc in player");
167
		else
168
			PyErr_SetString(CdError, "gettrackinfo failed");
Guido van Rossum's avatar
Guido van Rossum committed
169 170 171
		return NULL;
	}

172
	return Py_BuildValue("((iii)(iii))",
Guido van Rossum's avatar
Guido van Rossum committed
173 174 175 176
		       info.start_min, info.start_sec, info.start_frame,
		       info.total_min, info.total_sec, info.total_frame);
}
	
177
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
178 179
CD_msftoblock(self, args)
	cdplayerobject *self;
180
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
181 182 183
{
	int min, sec, frame;

184
	if (!PyArg_ParseTuple(args, "iii", &min, &sec, &frame))
Guido van Rossum's avatar
Guido van Rossum committed
185 186
		return NULL;

187
	return PyInt_FromLong((long) CDmsftoblock(self->ob_cdplayer,
188
						min, sec, frame));
Guido van Rossum's avatar
Guido van Rossum committed
189 190
}
	
191
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
192 193
CD_play(self, args)
	cdplayerobject *self;
194
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
195 196
{
	int start, play;
197
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
198

199
	if (!PyArg_ParseTuple(args, "ii", &start, &play))
Guido van Rossum's avatar
Guido van Rossum committed
200 201 202
		return NULL;

	if (!CDplay(self->ob_cdplayer, start, play)) {
203 204
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
205
			PyErr_SetString(CdError, "no disc in player");
206
		else
207
			PyErr_SetString(CdError, "play failed");
Guido van Rossum's avatar
Guido van Rossum committed
208 209 210
		return NULL;
	}

211 212
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
213 214
}
	
215
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
216 217
CD_playabs(self, args)
	cdplayerobject *self;
218
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
219 220
{
	int min, sec, frame, play;
221
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
222

223
	if (!PyArg_ParseTuple(args, "iiii", &min, &sec, &frame, &play))
Guido van Rossum's avatar
Guido van Rossum committed
224 225 226
		return NULL;

	if (!CDplayabs(self->ob_cdplayer, min, sec, frame, play)) {
227 228
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
229
			PyErr_SetString(CdError, "no disc in player");
230
		else
231
			PyErr_SetString(CdError, "playabs failed");
Guido van Rossum's avatar
Guido van Rossum committed
232 233 234
		return NULL;
	}

235 236
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
237 238
}
	
239
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
240 241
CD_playtrack(self, args)
	cdplayerobject *self;
242
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
243 244
{
	int start, play;
245
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
246

247
	if (!PyArg_ParseTuple(args, "ii", &start, &play))
Guido van Rossum's avatar
Guido van Rossum committed
248 249 250
		return NULL;

	if (!CDplaytrack(self->ob_cdplayer, start, play)) {
251 252
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
253
			PyErr_SetString(CdError, "no disc in player");
254
		else
255
			PyErr_SetString(CdError, "playtrack failed");
Guido van Rossum's avatar
Guido van Rossum committed
256 257 258
		return NULL;
	}

259 260
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
261 262
}
	
263
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
264 265
CD_playtrackabs(self, args)
	cdplayerobject *self;
266
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
267 268
{
	int track, min, sec, frame, play;
269
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
270

271 272
	if (!PyArg_ParseTuple(args, "iiiii", &track, &min, &sec,
			      &frame, &play))
Guido van Rossum's avatar
Guido van Rossum committed
273 274 275
		return NULL;

	if (!CDplaytrackabs(self->ob_cdplayer, track, min, sec, frame, play)) {
276 277
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
278
			PyErr_SetString(CdError, "no disc in player");
279
		else
280
			PyErr_SetString(CdError, "playtrackabs failed");
Guido van Rossum's avatar
Guido van Rossum committed
281 282 283
		return NULL;
	}

284 285
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
286 287
}
	
288
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
289 290
CD_readda(self, args)
	cdplayerobject *self;
291
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
292 293
{
	int numframes, n;
294
	PyObject *result;
Guido van Rossum's avatar
Guido van Rossum committed
295

296
	if (!PyArg_ParseTuple(args, "i", &numframes))
Guido van Rossum's avatar
Guido van Rossum committed
297 298
		return NULL;

299
	result = PyString_FromStringAndSize(NULL, numframes * sizeof(CDFRAME));
Guido van Rossum's avatar
Guido van Rossum committed
300 301 302
	if (result == NULL)
		return NULL;

303 304
	n = CDreadda(self->ob_cdplayer,
		       (CDFRAME *) PyString_AsString(result), numframes);
Guido van Rossum's avatar
Guido van Rossum committed
305
	if (n == -1) {
306 307
		Py_DECREF(result);
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
308 309 310
		return NULL;
	}
	if (n < numframes)
311
		if (_PyString_Resize(&result, n * sizeof(CDFRAME)))
Guido van Rossum's avatar
Guido van Rossum committed
312 313 314 315 316
			return NULL;

	return result;
}

317
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
318 319
CD_seek(self, args)
	cdplayerobject *self;
320
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
321 322
{
	int min, sec, frame;
323
	long PyTryBlock;
Guido van Rossum's avatar
Guido van Rossum committed
324

325
	if (!PyArg_ParseTuple(args, "iii", &min, &sec, &frame))
Guido van Rossum's avatar
Guido van Rossum committed
326 327
		return NULL;

328 329 330
	PyTryBlock = CDseek(self->ob_cdplayer, min, sec, frame);
	if (PyTryBlock == -1) {
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
331 332 333
		return NULL;
	}

334
	return PyInt_FromLong(PyTryBlock);
Guido van Rossum's avatar
Guido van Rossum committed
335 336
}
	
337
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
338 339
CD_seektrack(self, args)
	cdplayerobject *self;
340
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
341 342
{
	int track;
343
	long PyTryBlock;
Guido van Rossum's avatar
Guido van Rossum committed
344

345
	if (!PyArg_ParseTuple(args, "i", &track))
Guido van Rossum's avatar
Guido van Rossum committed
346 347
		return NULL;

348 349 350
	PyTryBlock = CDseektrack(self->ob_cdplayer, track);
	if (PyTryBlock == -1) {
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
351 352 353
		return NULL;
	}

354
	return PyInt_FromLong(PyTryBlock);
Guido van Rossum's avatar
Guido van Rossum committed
355 356
}
	
357
static PyObject *
358 359
CD_seekblock(self, args)
	cdplayerobject *self;
360
	PyObject *args;
361
{
362
	unsigned long PyTryBlock;
363

364
	if (!PyArg_ParseTuple(args, "l", &PyTryBlock))
365 366
		return NULL;

367 368 369
	PyTryBlock = CDseekblock(self->ob_cdplayer, PyTryBlock);
	if (PyTryBlock == (unsigned long) -1) {
		PyErr_SetFromErrno(CdError);
370 371 372
		return NULL;
	}

373
	return PyInt_FromLong(PyTryBlock);
374 375
}
	
376
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
377 378
CD_stop(self, args)
	cdplayerobject *self;
379
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
380
{
381 382
	CDSTATUS status;

383
	if (!PyArg_ParseTuple(args, ""))
Guido van Rossum's avatar
Guido van Rossum committed
384 385 386
		return NULL;

	if (!CDstop(self->ob_cdplayer)) {
387 388
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
389
			PyErr_SetString(CdError, "no disc in player");
390
		else
391
			PyErr_SetString(CdError, "stop failed");
Guido van Rossum's avatar
Guido van Rossum committed
392 393 394
		return NULL;
	}

395 396
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
397 398
}
	
399
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
400 401
CD_togglepause(self, args)
	cdplayerobject *self;
402
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
403
{
404 405
	CDSTATUS status;

406
	if (!PyArg_ParseTuple(args, ""))
Guido van Rossum's avatar
Guido van Rossum committed
407 408 409
		return NULL;

	if (!CDtogglepause(self->ob_cdplayer)) {
410 411
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
412
			PyErr_SetString(CdError, "no disc in player");
413
		else
414
			PyErr_SetString(CdError, "togglepause failed");
Guido van Rossum's avatar
Guido van Rossum committed
415 416 417
		return NULL;
	}

418 419
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
420 421
}
	
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
static PyMethodDef cdplayer_methods[] = {
	{"allowremoval",	(PyCFunction)CD_allowremoval,	1},
	{"bestreadsize",	(PyCFunction)CD_bestreadsize,	1},
	{"close",		(PyCFunction)CD_close,		1},
	{"eject",		(PyCFunction)CD_eject,		1},
	{"getstatus",		(PyCFunction)CD_getstatus,		1},
	{"gettrackinfo",	(PyCFunction)CD_gettrackinfo,	1},
	{"msftoblock",		(PyCFunction)CD_msftoblock,		1},
	{"play",		(PyCFunction)CD_play,		1},
	{"playabs",		(PyCFunction)CD_playabs,		1},
	{"playtrack",		(PyCFunction)CD_playtrack,		1},
	{"playtrackabs",	(PyCFunction)CD_playtrackabs,	1},
	{"preventremoval",	(PyCFunction)CD_preventremoval,	1},
	{"readda",		(PyCFunction)CD_readda,		1},
	{"seek",		(PyCFunction)CD_seek,		1},
	{"seekblock",		(PyCFunction)CD_seekblock,		1},
	{"seektrack",		(PyCFunction)CD_seektrack,		1},
	{"stop",		(PyCFunction)CD_stop,		1},
	{"togglepause",		(PyCFunction)CD_togglepause,   	1},
Guido van Rossum's avatar
Guido van Rossum committed
441 442 443 444 445 446 447 448 449
	{NULL,			NULL} 		/* sentinel */
};

static void
cdplayer_dealloc(self)
	cdplayerobject *self;
{
	if (self->ob_cdplayer != NULL)
		CDclose(self->ob_cdplayer);
450
	PyMem_DEL(self);
Guido van Rossum's avatar
Guido van Rossum committed
451 452
}

453
static PyObject *
454 455
cdplayer_getattr(self, name)
	cdplayerobject *self;
Guido van Rossum's avatar
Guido van Rossum committed
456 457
	char *name;
{
458
	if (self->ob_cdplayer == NULL) {
459
		PyErr_SetString(PyExc_RuntimeError, "no player active");
460 461
		return NULL;
	}
462
	return Py_FindMethod(cdplayer_methods, (PyObject *)self, name);
Guido van Rossum's avatar
Guido van Rossum committed
463 464
}

465 466
PyTypeObject CdPlayertype = {
	PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossum's avatar
Guido van Rossum committed
467 468 469 470 471
	0,			/*ob_size*/
	"cdplayer",		/*tp_name*/
	sizeof(cdplayerobject),	/*tp_size*/
	0,			/*tp_itemsize*/
	/* methods */
472
	(destructor)cdplayer_dealloc, /*tp_dealloc*/
Guido van Rossum's avatar
Guido van Rossum committed
473
	0,			/*tp_print*/
474
	(getattrfunc)cdplayer_getattr, /*tp_getattr*/
Guido van Rossum's avatar
Guido van Rossum committed
475 476 477 478 479
	0,			/*tp_setattr*/
	0,			/*tp_compare*/
	0,			/*tp_repr*/
};

480
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
481 482 483 484 485
newcdplayerobject(cdp)
	CDPLAYER *cdp;
{
	cdplayerobject *p;

486
	p = PyObject_NEW(cdplayerobject, &CdPlayertype);
Guido van Rossum's avatar
Guido van Rossum committed
487 488 489
	if (p == NULL)
		return NULL;
	p->ob_cdplayer = cdp;
490
	return (PyObject *) p;
Guido van Rossum's avatar
Guido van Rossum committed
491 492
}

493
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
494
CD_open(self, args)
495
	PyObject *self, *args;
Guido van Rossum's avatar
Guido van Rossum committed
496 497 498 499 500 501 502 503 504 505
{
	char *dev, *direction;
	CDPLAYER *cdp;

	/*
	 * Variable number of args.
	 * First defaults to "None", second defaults to "r".
	 */
	dev = NULL;
	direction = "r";
506
	if (!PyArg_ParseTuple(args, "|zs", &dev, &direction))
507
		return NULL;
Guido van Rossum's avatar
Guido van Rossum committed
508 509 510

	cdp = CDopen(dev, direction);
	if (cdp == NULL) {
511
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
512 513 514 515 516 517 518
		return NULL;
	}

	return newcdplayerobject(cdp);
}

typedef struct {
519
	PyObject_HEAD
Guido van Rossum's avatar
Guido van Rossum committed
520 521
	CDPARSER *ob_cdparser;
	struct {
522 523
		PyObject *ob_cdcallback;
		PyObject *ob_cdcallbackarg;
Guido van Rossum's avatar
Guido van Rossum committed
524 525 526 527 528 529 530 531 532
	} ob_cdcallbacks[NCALLBACKS];
} cdparserobject;

static void
CD_callback(arg, type, data)
	void *arg;
	CDDATATYPES type;
	void *data;
{
533
	PyObject *result, *args, *v = NULL;
Guido van Rossum's avatar
Guido van Rossum committed
534 535 536 537 538
	char *p;
	int i;
	cdparserobject *self;

	self = (cdparserobject *) arg;
539
	args = PyTuple_New(3);
Guido van Rossum's avatar
Guido van Rossum committed
540 541
	if (args == NULL)
		return;
542 543 544
	Py_INCREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
	PyTuple_SetItem(args, 0, self->ob_cdcallbacks[type].ob_cdcallbackarg);
	PyTuple_SetItem(args, 1, PyInt_FromLong((long) type));
Guido van Rossum's avatar
Guido van Rossum committed
545 546
	switch (type) {
	case cd_audio:
547
		v = PyString_FromStringAndSize(data, CDDA_DATASIZE);
Guido van Rossum's avatar
Guido van Rossum committed
548 549 550
		break;
	case cd_pnum:
	case cd_index:
551
		v = PyInt_FromLong(((CDPROGNUM *) data)->value);
Guido van Rossum's avatar
Guido van Rossum committed
552 553 554
		break;
	case cd_ptime:
	case cd_atime:
555
#define ptr ((struct cdtimecode *) data)
556
		v = Py_BuildValue("(iii)",
557
			    ptr->mhi * 10 + ptr->mlo,
558 559 560
			    ptr->shi * 10 + ptr->slo,
			    ptr->fhi * 10 + ptr->flo);
#undef ptr
Guido van Rossum's avatar
Guido van Rossum committed
561 562
		break;
	case cd_catalog:
563 564
		v = PyString_FromStringAndSize(NULL, 13);
		p = PyString_AsString(v);
Guido van Rossum's avatar
Guido van Rossum committed
565 566 567 568
		for (i = 0; i < 13; i++)
			*p++ = ((char *) data)[i] + '0';
		break;
	case cd_ident:
569
#define ptr ((struct cdident *) data)
570 571
		v = PyString_FromStringAndSize(NULL, 12);
		p = PyString_AsString(v);
572
		CDsbtoa(p, ptr->country, 2);
Guido van Rossum's avatar
Guido van Rossum committed
573
		p += 2;
574
		CDsbtoa(p, ptr->owner, 3);
Guido van Rossum's avatar
Guido van Rossum committed
575
		p += 3;
576 577 578 579 580 581 582 583
		*p++ = ptr->year[0] + '0';
		*p++ = ptr->year[1] + '0';
		*p++ = ptr->serial[0] + '0';
		*p++ = ptr->serial[1] + '0';
		*p++ = ptr->serial[2] + '0';
		*p++ = ptr->serial[3] + '0';
		*p++ = ptr->serial[4] + '0';
#undef ptr
Guido van Rossum's avatar
Guido van Rossum committed
584 585
		break;
	case cd_control:
586
		v = PyInt_FromLong((long) *((unchar *) data));
Guido van Rossum's avatar
Guido van Rossum committed
587 588
		break;
	}
589 590 591
	PyTuple_SetItem(args, 2, v);
	if (PyErr_Occurred()) {
		Py_DECREF(args);
Guido van Rossum's avatar
Guido van Rossum committed
592 593 594
		return;
	}
	
595 596 597 598
	result = PyEval_CallObject(self->ob_cdcallbacks[type].ob_cdcallback,
				   args);
	Py_DECREF(args);
	Py_XDECREF(result);
Guido van Rossum's avatar
Guido van Rossum committed
599 600
}

601
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
602 603
CD_deleteparser(self, args)
	cdparserobject *self;
604
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
605 606 607
{
	int i;

608
	if (!PyArg_ParseTuple(args, ""))
Guido van Rossum's avatar
Guido van Rossum committed
609 610 611 612 613 614 615
		return NULL;

	CDdeleteparser(self->ob_cdparser);
	self->ob_cdparser = NULL;

	/* no sense in keeping the callbacks, so remove them */
	for (i = 0; i < NCALLBACKS; i++) {
616
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
Guido van Rossum's avatar
Guido van Rossum committed
617
		self->ob_cdcallbacks[i].ob_cdcallback = NULL;
618
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
Guido van Rossum's avatar
Guido van Rossum committed
619 620 621
		self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
	}

622 623
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
624 625
}

626
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
627 628
CD_parseframe(self, args)
	cdparserobject *self;
629
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
630 631 632 633 634
{
	char *cdfp;
	int length;
	CDFRAME *p;

635
	if (!PyArg_ParseTuple(args, "s#", &cdfp, &length))
Guido van Rossum's avatar
Guido van Rossum committed
636 637 638
		return NULL;

	if (length % sizeof(CDFRAME) != 0) {
639
		PyErr_SetString(PyExc_TypeError, "bad length");
Guido van Rossum's avatar
Guido van Rossum committed
640 641 642 643 644 645 646 647
		return NULL;
	}

	p = (CDFRAME *) cdfp;
	while (length > 0) {
		CDparseframe(self->ob_cdparser, p);
		length -= sizeof(CDFRAME);
		p++;
648
		if (PyErr_Occurred())
Guido van Rossum's avatar
Guido van Rossum committed
649 650 651
			return NULL;
	}

652 653
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
654 655
}

656
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
657 658
CD_removecallback(self, args)
	cdparserobject *self;
659
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
660 661 662
{
	int type;

663
	if (!PyArg_ParseTuple(args, "i", &type))
Guido van Rossum's avatar
Guido van Rossum committed
664 665
		return NULL;

666
	if (type < 0 || type >= NCALLBACKS) {
667
		PyErr_SetString(PyExc_TypeError, "bad type");
668 669 670
		return NULL;
	}

Guido van Rossum's avatar
Guido van Rossum committed
671 672
	CDremovecallback(self->ob_cdparser, (CDDATATYPES) type);

673
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
Guido van Rossum's avatar
Guido van Rossum committed
674 675
	self->ob_cdcallbacks[type].ob_cdcallback = NULL;

676
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
Guido van Rossum's avatar
Guido van Rossum committed
677 678
	self->ob_cdcallbacks[type].ob_cdcallbackarg = NULL;

679 680
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
681 682
}

683
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
684 685
CD_resetparser(self, args)
	cdparserobject *self;
686
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
687
{
688
	if (!PyArg_ParseTuple(args, ""))
Guido van Rossum's avatar
Guido van Rossum committed
689 690 691 692
		return NULL;

	CDresetparser(self->ob_cdparser);

693 694
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
695 696
}

697
static PyObject *
698
CD_addcallback(self, args)
Guido van Rossum's avatar
Guido van Rossum committed
699
	cdparserobject *self;
700
	PyObject *args;
Guido van Rossum's avatar
Guido van Rossum committed
701 702
{
	int type;
703
	PyObject *func, *funcarg;
Guido van Rossum's avatar
Guido van Rossum committed
704 705

	/* XXX - more work here */
706
	if (!PyArg_ParseTuple(args, "iOO", &type, &func, &funcarg))
Guido van Rossum's avatar
Guido van Rossum committed
707 708 709
		return NULL;

	if (type < 0 || type >= NCALLBACKS) {
710
		PyErr_SetString(PyExc_TypeError, "argument out of range");
Guido van Rossum's avatar
Guido van Rossum committed
711 712 713
		return NULL;
	}

714
#ifdef CDsetcallback
715 716
	CDaddcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
		      (void *) self);
717
#else
718 719
	CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
		      (void *) self);
720
#endif
721 722
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
	Py_INCREF(func);
723
	self->ob_cdcallbacks[type].ob_cdcallback = func;
724 725
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
	Py_INCREF(funcarg);
726
	self->ob_cdcallbacks[type].ob_cdcallbackarg = funcarg;
Guido van Rossum's avatar
Guido van Rossum committed
727

728 729 730
/*
	if (type == cd_audio) {
		sigfpe_[_UNDERFL].repls = _ZERO;
731 732
		handle_sigfpes(_ON, _EN_UNDERFL, NULL,
		                        _ABORT_ON_ERROR, NULL);
733 734 735
	}
*/

736 737
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
738 739
}

740 741 742 743 744 745 746 747
static PyMethodDef cdparser_methods[] = {
	{"addcallback",		(PyCFunction)CD_addcallback,   	1},
	{"deleteparser",	(PyCFunction)CD_deleteparser,	1},
	{"parseframe",		(PyCFunction)CD_parseframe,	1},
	{"removecallback",	(PyCFunction)CD_removecallback,	1},
	{"resetparser",		(PyCFunction)CD_resetparser,	1},
		                                /* backward compatibility */
	{"setcallback",		(PyCFunction)CD_addcallback,   	1},
Guido van Rossum's avatar
Guido van Rossum committed
748 749 750 751 752 753 754 755 756 757
	{NULL,			NULL} 		/* sentinel */
};

static void
cdparser_dealloc(self)
	cdparserobject *self;
{
	int i;

	for (i = 0; i < NCALLBACKS; i++) {
758
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
Guido van Rossum's avatar
Guido van Rossum committed
759
		self->ob_cdcallbacks[i].ob_cdcallback = NULL;
760
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
Guido van Rossum's avatar
Guido van Rossum committed
761 762 763
		self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
	}
	CDdeleteparser(self->ob_cdparser);
764
	PyMem_DEL(self);
Guido van Rossum's avatar
Guido van Rossum committed
765 766
}

767
static PyObject *
768 769
cdparser_getattr(self, name)
	cdparserobject *self;
Guido van Rossum's avatar
Guido van Rossum committed
770 771
	char *name;
{
772
	if (self->ob_cdparser == NULL) {
773
		PyErr_SetString(PyExc_RuntimeError, "no parser active");
774 775 776
		return NULL;
	}

777
	return Py_FindMethod(cdparser_methods, (PyObject *)self, name);
Guido van Rossum's avatar
Guido van Rossum committed
778 779
}

780 781
PyTypeObject CdParsertype = {
	PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossum's avatar
Guido van Rossum committed
782 783 784 785 786
	0,			/*ob_size*/
	"cdparser",		/*tp_name*/
	sizeof(cdparserobject),	/*tp_size*/
	0,			/*tp_itemsize*/
	/* methods */
787
	(destructor)cdparser_dealloc, /*tp_dealloc*/
Guido van Rossum's avatar
Guido van Rossum committed
788
	0,			/*tp_print*/
789
	(getattrfunc)cdparser_getattr, /*tp_getattr*/
Guido van Rossum's avatar
Guido van Rossum committed
790 791 792 793 794
	0,			/*tp_setattr*/
	0,			/*tp_compare*/
	0,			/*tp_repr*/
};

795
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
796 797 798 799 800 801
newcdparserobject(cdp)
	CDPARSER *cdp;
{
	cdparserobject *p;
	int i;

802
	p = PyObject_NEW(cdparserobject, &CdParsertype);
Guido van Rossum's avatar
Guido van Rossum committed
803 804 805 806 807 808 809
	if (p == NULL)
		return NULL;
	p->ob_cdparser = cdp;
	for (i = 0; i < NCALLBACKS; i++) {
		p->ob_cdcallbacks[i].ob_cdcallback = NULL;
		p->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
	}
810
	return (PyObject *) p;
Guido van Rossum's avatar
Guido van Rossum committed
811 812
}

813
static PyObject *
Guido van Rossum's avatar
Guido van Rossum committed
814
CD_createparser(self, args)
815
	PyObject *self, *args;
Guido van Rossum's avatar
Guido van Rossum committed
816 817 818
{
	CDPARSER *cdp;

819
	if (!PyArg_ParseTuple(args, ""))
Guido van Rossum's avatar
Guido van Rossum committed
820 821 822
		return NULL;
	cdp = CDcreateparser();
	if (cdp == NULL) {
823
		PyErr_SetString(CdError, "createparser failed");
Guido van Rossum's avatar
Guido van Rossum committed
824 825 826 827 828 829
		return NULL;
	}

	return newcdparserobject(cdp);
}

830
static PyObject *
831
CD_msftoframe(self, args)
832
	PyObject *self, *args;
Guido van Rossum's avatar
Guido van Rossum committed
833
{
834
	int min, sec, frame;
Guido van Rossum's avatar
Guido van Rossum committed
835

836
	if (!PyArg_ParseTuple(args, "iii", &min, &sec, &frame))
Guido van Rossum's avatar
Guido van Rossum committed
837 838
		return NULL;

839
	return PyInt_FromLong((long) CDmsftoframe(min, sec, frame));
Guido van Rossum's avatar
Guido van Rossum committed
840
}
841
	
842 843 844 845
static PyMethodDef CD_methods[] = {
	{"open",		(PyCFunction)CD_open,		1},
	{"createparser",	(PyCFunction)CD_createparser,	1},
	{"msftoframe",		(PyCFunction)CD_msftoframe,	1},
Guido van Rossum's avatar
Guido van Rossum committed
846 847 848 849 850 851
	{NULL,		NULL}	/* Sentinel */
};

void
initcd()
{
852
	PyObject *m, *d;
853

854 855
	m = Py_InitModule("cd", CD_methods);
	d = PyModule_GetDict(m);
856

857 858
	CdError = PyString_FromString("cd.error");
	PyDict_SetItemString(d, "error", CdError);
859 860

	/* Identifiers for the different types of callbacks from the parser */
861 862 863 864 865 866 867 868
	PyDict_SetItemString(d, "audio", PyInt_FromLong((long) cd_audio));
	PyDict_SetItemString(d, "pnum", PyInt_FromLong((long) cd_pnum));
	PyDict_SetItemString(d, "index", PyInt_FromLong((long) cd_index));
	PyDict_SetItemString(d, "ptime", PyInt_FromLong((long) cd_ptime));
	PyDict_SetItemString(d, "atime", PyInt_FromLong((long) cd_atime));
	PyDict_SetItemString(d, "catalog", PyInt_FromLong((long) cd_catalog));
	PyDict_SetItemString(d, "ident", PyInt_FromLong((long) cd_ident));
	PyDict_SetItemString(d, "control", PyInt_FromLong((long) cd_control));
869 870

	/* Block size information for digital audio data */
871 872 873 874
	PyDict_SetItemString(d, "DATASIZE",
			   PyInt_FromLong((long) CDDA_DATASIZE));
	PyDict_SetItemString(d, "BLOCKSIZE",
			   PyInt_FromLong((long) CDDA_BLOCKSIZE));
875 876

	/* Possible states for the cd player */
877 878 879 880 881 882
	PyDict_SetItemString(d, "ERROR", PyInt_FromLong((long) CD_ERROR));
	PyDict_SetItemString(d, "NODISC", PyInt_FromLong((long) CD_NODISC));
	PyDict_SetItemString(d, "READY", PyInt_FromLong((long) CD_READY));
	PyDict_SetItemString(d, "PLAYING", PyInt_FromLong((long) CD_PLAYING));
	PyDict_SetItemString(d, "PAUSED", PyInt_FromLong((long) CD_PAUSED));
	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));
885 886
#endif

887 888
	if (PyErr_Occurred())
		Py_FatalError("can't initialize module cd");
Guido van Rossum's avatar
Guido van Rossum committed
889
}