cdmodule.c 18.5 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1 2 3 4 5
/* CD module -- interface to Mark Callow's and Roger Chickering's */
 /* CD Audio Library (CD). */

#include <sys/types.h>
#include <cdaudio.h>
6
#include "Python.h"
Guido van Rossum's avatar
Guido van Rossum committed
7 8 9 10

#define NCALLBACKS	8

typedef struct {
11
	PyObject_HEAD
Guido van Rossum's avatar
Guido van Rossum committed
12 13 14
	CDPLAYER *ob_cdplayer;
} cdplayerobject;

15
static PyObject *CdError;		/* exception cd.error */
16

17
static PyObject *
18
CD_allowremoval(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
19
{
20
	if (!PyArg_ParseTuple(args, ":allowremoval"))
Guido van Rossum's avatar
Guido van Rossum committed
21 22 23 24
		return NULL;

	CDallowremoval(self->ob_cdplayer);

25 26
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
27 28
}

29
static PyObject *
30
CD_preventremoval(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
31
{
32
	if (!PyArg_ParseTuple(args, ":preventremoval"))
Guido van Rossum's avatar
Guido van Rossum committed
33 34 35 36
		return NULL;

	CDpreventremoval(self->ob_cdplayer);

37 38
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
39 40
}

41
static PyObject *
42
CD_bestreadsize(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
43
{
44
	if (!PyArg_ParseTuple(args, ":bestreadsize"))
Guido van Rossum's avatar
Guido van Rossum committed
45 46
		return NULL;

47
	return PyInt_FromLong((long) CDbestreadsize(self->ob_cdplayer));
Guido van Rossum's avatar
Guido van Rossum committed
48 49
}

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

	if (!CDclose(self->ob_cdplayer)) {
57
		PyErr_SetFromErrno(CdError); /* XXX - ??? */
Guido van Rossum's avatar
Guido van Rossum committed
58 59 60 61
		return NULL;
	}
	self->ob_cdplayer = NULL;

62 63
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
64 65
}

66
static PyObject *
67
CD_eject(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
68
{
69 70
	CDSTATUS status;

71
	if (!PyArg_ParseTuple(args, ":eject"))
Guido van Rossum's avatar
Guido van Rossum committed
72 73 74
		return NULL;

	if (!CDeject(self->ob_cdplayer)) {
75 76
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
77
			PyErr_SetString(CdError, "no disc in player");
78
		else
79
			PyErr_SetString(CdError, "eject failed");
Guido van Rossum's avatar
Guido van Rossum committed
80 81 82
		return NULL;
	}

83 84
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
85 86
}
	
87
static PyObject *
88
CD_getstatus(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
89 90 91
{
	CDSTATUS status;

92
	if (!PyArg_ParseTuple(args, ":getstatus"))
Guido van Rossum's avatar
Guido van Rossum committed
93 94 95
		return NULL;

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

100
	return Py_BuildValue("(ii(iii)(iii)(iii)iiii)", status.state,
101 102 103 104
		       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,
105
		       status.cur_block);
Guido van Rossum's avatar
Guido van Rossum committed
106 107
}
	
108
static PyObject *
109
CD_gettrackinfo(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
110 111 112
{
	int track;
	CDTRACKINFO info;
113
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
114

115
	if (!PyArg_ParseTuple(args, "i:gettrackinfo", &track))
Guido van Rossum's avatar
Guido van Rossum committed
116 117 118
		return NULL;

	if (!CDgettrackinfo(self->ob_cdplayer, track, &info)) {
119 120
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
121
			PyErr_SetString(CdError, "no disc in player");
122
		else
123
			PyErr_SetString(CdError, "gettrackinfo failed");
Guido van Rossum's avatar
Guido van Rossum committed
124 125 126
		return NULL;
	}

127
	return Py_BuildValue("((iii)(iii))",
Guido van Rossum's avatar
Guido van Rossum committed
128 129 130 131
		       info.start_min, info.start_sec, info.start_frame,
		       info.total_min, info.total_sec, info.total_frame);
}
	
132
static PyObject *
133
CD_msftoblock(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
134 135 136
{
	int min, sec, frame;

137
	if (!PyArg_ParseTuple(args, "iii:msftoblock", &min, &sec, &frame))
Guido van Rossum's avatar
Guido van Rossum committed
138 139
		return NULL;

140
	return PyInt_FromLong((long) CDmsftoblock(self->ob_cdplayer,
141
						min, sec, frame));
Guido van Rossum's avatar
Guido van Rossum committed
142 143
}
	
144
static PyObject *
145
CD_play(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
146 147
{
	int start, play;
148
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
149

150
	if (!PyArg_ParseTuple(args, "ii:play", &start, &play))
Guido van Rossum's avatar
Guido van Rossum committed
151 152 153
		return NULL;

	if (!CDplay(self->ob_cdplayer, start, play)) {
154 155
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
156
			PyErr_SetString(CdError, "no disc in player");
157
		else
158
			PyErr_SetString(CdError, "play failed");
Guido van Rossum's avatar
Guido van Rossum committed
159 160 161
		return NULL;
	}

162 163
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
164 165
}
	
166
static PyObject *
167
CD_playabs(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
168 169
{
	int min, sec, frame, play;
170
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
171

172
	if (!PyArg_ParseTuple(args, "iiii:playabs", &min, &sec, &frame, &play))
Guido van Rossum's avatar
Guido van Rossum committed
173 174 175
		return NULL;

	if (!CDplayabs(self->ob_cdplayer, min, sec, frame, play)) {
176 177
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
178
			PyErr_SetString(CdError, "no disc in player");
179
		else
180
			PyErr_SetString(CdError, "playabs failed");
Guido van Rossum's avatar
Guido van Rossum committed
181 182 183
		return NULL;
	}

184 185
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
186 187
}
	
188
static PyObject *
189
CD_playtrack(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
190 191
{
	int start, play;
192
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
193

194
	if (!PyArg_ParseTuple(args, "ii:playtrack", &start, &play))
Guido van Rossum's avatar
Guido van Rossum committed
195 196 197
		return NULL;

	if (!CDplaytrack(self->ob_cdplayer, start, play)) {
198 199
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
200
			PyErr_SetString(CdError, "no disc in player");
201
		else
202
			PyErr_SetString(CdError, "playtrack failed");
Guido van Rossum's avatar
Guido van Rossum committed
203 204 205
		return NULL;
	}

206 207
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
208 209
}
	
210
static PyObject *
211
CD_playtrackabs(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
212 213
{
	int track, min, sec, frame, play;
214
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
215

216
	if (!PyArg_ParseTuple(args, "iiiii:playtrackabs", &track, &min, &sec,
217
			      &frame, &play))
Guido van Rossum's avatar
Guido van Rossum committed
218 219 220
		return NULL;

	if (!CDplaytrackabs(self->ob_cdplayer, track, min, sec, frame, play)) {
221 222
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
223
			PyErr_SetString(CdError, "no disc in player");
224
		else
225
			PyErr_SetString(CdError, "playtrackabs failed");
Guido van Rossum's avatar
Guido van Rossum committed
226 227 228
		return NULL;
	}

229 230
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
231 232
}
	
233
static PyObject *
234
CD_readda(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
235 236
{
	int numframes, n;
237
	PyObject *result;
Guido van Rossum's avatar
Guido van Rossum committed
238

239
	if (!PyArg_ParseTuple(args, "i:readda", &numframes))
Guido van Rossum's avatar
Guido van Rossum committed
240 241
		return NULL;

242
	result = PyString_FromStringAndSize(NULL, numframes * sizeof(CDFRAME));
Guido van Rossum's avatar
Guido van Rossum committed
243 244 245
	if (result == NULL)
		return NULL;

246 247
	n = CDreadda(self->ob_cdplayer,
		       (CDFRAME *) PyString_AsString(result), numframes);
Guido van Rossum's avatar
Guido van Rossum committed
248
	if (n == -1) {
249 250
		Py_DECREF(result);
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
251 252 253
		return NULL;
	}
	if (n < numframes)
254
		if (_PyString_Resize(&result, n * sizeof(CDFRAME)))
Guido van Rossum's avatar
Guido van Rossum committed
255 256 257 258 259
			return NULL;

	return result;
}

260
static PyObject *
261
CD_seek(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
262 263
{
	int min, sec, frame;
264
	long PyTryBlock;
Guido van Rossum's avatar
Guido van Rossum committed
265

266
	if (!PyArg_ParseTuple(args, "iii:seek", &min, &sec, &frame))
Guido van Rossum's avatar
Guido van Rossum committed
267 268
		return NULL;

269 270 271
	PyTryBlock = CDseek(self->ob_cdplayer, min, sec, frame);
	if (PyTryBlock == -1) {
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
272 273 274
		return NULL;
	}

275
	return PyInt_FromLong(PyTryBlock);
Guido van Rossum's avatar
Guido van Rossum committed
276 277
}
	
278
static PyObject *
279
CD_seektrack(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
280 281
{
	int track;
282
	long PyTryBlock;
Guido van Rossum's avatar
Guido van Rossum committed
283

284
	if (!PyArg_ParseTuple(args, "i:seektrack", &track))
Guido van Rossum's avatar
Guido van Rossum committed
285 286
		return NULL;

287 288 289
	PyTryBlock = CDseektrack(self->ob_cdplayer, track);
	if (PyTryBlock == -1) {
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
290 291 292
		return NULL;
	}

293
	return PyInt_FromLong(PyTryBlock);
Guido van Rossum's avatar
Guido van Rossum committed
294 295
}
	
296
static PyObject *
297
CD_seekblock(cdplayerobject *self, PyObject *args)
298
{
299
	unsigned long PyTryBlock;
300

301
	if (!PyArg_ParseTuple(args, "l:seekblock", &PyTryBlock))
302 303
		return NULL;

304 305 306
	PyTryBlock = CDseekblock(self->ob_cdplayer, PyTryBlock);
	if (PyTryBlock == (unsigned long) -1) {
		PyErr_SetFromErrno(CdError);
307 308 309
		return NULL;
	}

310
	return PyInt_FromLong(PyTryBlock);
311 312
}
	
313
static PyObject *
314
CD_stop(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
315
{
316 317
	CDSTATUS status;

318
	if (!PyArg_ParseTuple(args, ":stop"))
Guido van Rossum's avatar
Guido van Rossum committed
319 320 321
		return NULL;

	if (!CDstop(self->ob_cdplayer)) {
322 323
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
324
			PyErr_SetString(CdError, "no disc in player");
325
		else
326
			PyErr_SetString(CdError, "stop failed");
Guido van Rossum's avatar
Guido van Rossum committed
327 328 329
		return NULL;
	}

330 331
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
332 333
}
	
334
static PyObject *
335
CD_togglepause(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
336
{
337 338
	CDSTATUS status;

339
	if (!PyArg_ParseTuple(args, ":togglepause"))
Guido van Rossum's avatar
Guido van Rossum committed
340 341 342
		return NULL;

	if (!CDtogglepause(self->ob_cdplayer)) {
343 344
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
345
			PyErr_SetString(CdError, "no disc in player");
346
		else
347
			PyErr_SetString(CdError, "togglepause failed");
Guido van Rossum's avatar
Guido van Rossum committed
348 349 350
		return NULL;
	}

351 352
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
353 354
}
	
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
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
374 375 376 377
	{NULL,			NULL} 		/* sentinel */
};

static void
378
cdplayer_dealloc(cdplayerobject *self)
Guido van Rossum's avatar
Guido van Rossum committed
379 380 381
{
	if (self->ob_cdplayer != NULL)
		CDclose(self->ob_cdplayer);
382
	PyObject_Del(self);
Guido van Rossum's avatar
Guido van Rossum committed
383 384
}

385
static PyObject *
386
cdplayer_getattr(cdplayerobject *self, char *name)
Guido van Rossum's avatar
Guido van Rossum committed
387
{
388
	if (self->ob_cdplayer == NULL) {
389
		PyErr_SetString(PyExc_RuntimeError, "no player active");
390 391
		return NULL;
	}
392
	return Py_FindMethod(cdplayer_methods, (PyObject *)self, name);
Guido van Rossum's avatar
Guido van Rossum committed
393 394
}

395 396
PyTypeObject CdPlayertype = {
	PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossum's avatar
Guido van Rossum committed
397 398 399 400 401
	0,			/*ob_size*/
	"cdplayer",		/*tp_name*/
	sizeof(cdplayerobject),	/*tp_size*/
	0,			/*tp_itemsize*/
	/* methods */
402
	(destructor)cdplayer_dealloc, /*tp_dealloc*/
Guido van Rossum's avatar
Guido van Rossum committed
403
	0,			/*tp_print*/
404
	(getattrfunc)cdplayer_getattr, /*tp_getattr*/
Guido van Rossum's avatar
Guido van Rossum committed
405 406 407 408 409
	0,			/*tp_setattr*/
	0,			/*tp_compare*/
	0,			/*tp_repr*/
};

410
static PyObject *
411
newcdplayerobject(CDPLAYER *cdp)
Guido van Rossum's avatar
Guido van Rossum committed
412 413 414
{
	cdplayerobject *p;

415
	p = PyObject_New(cdplayerobject, &CdPlayertype);
Guido van Rossum's avatar
Guido van Rossum committed
416 417 418
	if (p == NULL)
		return NULL;
	p->ob_cdplayer = cdp;
419
	return (PyObject *) p;
Guido van Rossum's avatar
Guido van Rossum committed
420 421
}

422
static PyObject *
423
CD_open(PyObject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
424 425 426 427 428 429 430 431 432 433
{
	char *dev, *direction;
	CDPLAYER *cdp;

	/*
	 * Variable number of args.
	 * First defaults to "None", second defaults to "r".
	 */
	dev = NULL;
	direction = "r";
434
	if (!PyArg_ParseTuple(args, "|zs:open", &dev, &direction))
435
		return NULL;
Guido van Rossum's avatar
Guido van Rossum committed
436 437 438

	cdp = CDopen(dev, direction);
	if (cdp == NULL) {
439
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
440 441 442 443 444 445 446
		return NULL;
	}

	return newcdplayerobject(cdp);
}

typedef struct {
447
	PyObject_HEAD
Guido van Rossum's avatar
Guido van Rossum committed
448 449
	CDPARSER *ob_cdparser;
	struct {
450 451
		PyObject *ob_cdcallback;
		PyObject *ob_cdcallbackarg;
Guido van Rossum's avatar
Guido van Rossum committed
452 453 454 455
	} ob_cdcallbacks[NCALLBACKS];
} cdparserobject;

static void
456
CD_callback(void *arg, CDDATATYPES type, void *data)
Guido van Rossum's avatar
Guido van Rossum committed
457
{
458
	PyObject *result, *args, *v = NULL;
Guido van Rossum's avatar
Guido van Rossum committed
459 460 461 462 463
	char *p;
	int i;
	cdparserobject *self;

	self = (cdparserobject *) arg;
464
	args = PyTuple_New(3);
Guido van Rossum's avatar
Guido van Rossum committed
465 466
	if (args == NULL)
		return;
467 468 469
	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
470 471
	switch (type) {
	case cd_audio:
472
		v = PyString_FromStringAndSize(data, CDDA_DATASIZE);
Guido van Rossum's avatar
Guido van Rossum committed
473 474 475
		break;
	case cd_pnum:
	case cd_index:
476
		v = PyInt_FromLong(((CDPROGNUM *) data)->value);
Guido van Rossum's avatar
Guido van Rossum committed
477 478 479
		break;
	case cd_ptime:
	case cd_atime:
480
#define ptr ((struct cdtimecode *) data)
481
		v = Py_BuildValue("(iii)",
482
			    ptr->mhi * 10 + ptr->mlo,
483 484 485
			    ptr->shi * 10 + ptr->slo,
			    ptr->fhi * 10 + ptr->flo);
#undef ptr
Guido van Rossum's avatar
Guido van Rossum committed
486 487
		break;
	case cd_catalog:
488 489
		v = PyString_FromStringAndSize(NULL, 13);
		p = PyString_AsString(v);
Guido van Rossum's avatar
Guido van Rossum committed
490 491 492 493
		for (i = 0; i < 13; i++)
			*p++ = ((char *) data)[i] + '0';
		break;
	case cd_ident:
494
#define ptr ((struct cdident *) data)
495 496
		v = PyString_FromStringAndSize(NULL, 12);
		p = PyString_AsString(v);
497
		CDsbtoa(p, ptr->country, 2);
Guido van Rossum's avatar
Guido van Rossum committed
498
		p += 2;
499
		CDsbtoa(p, ptr->owner, 3);
Guido van Rossum's avatar
Guido van Rossum committed
500
		p += 3;
501 502 503 504 505 506 507 508
		*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
509 510
		break;
	case cd_control:
511
		v = PyInt_FromLong((long) *((unchar *) data));
Guido van Rossum's avatar
Guido van Rossum committed
512 513
		break;
	}
514 515 516
	PyTuple_SetItem(args, 2, v);
	if (PyErr_Occurred()) {
		Py_DECREF(args);
Guido van Rossum's avatar
Guido van Rossum committed
517 518 519
		return;
	}
	
520 521 522 523
	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
524 525
}

526
static PyObject *
527
CD_deleteparser(cdparserobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
528 529 530
{
	int i;

531
	if (!PyArg_ParseTuple(args, ":deleteparser"))
Guido van Rossum's avatar
Guido van Rossum committed
532 533 534 535 536 537 538
		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++) {
539
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
Guido van Rossum's avatar
Guido van Rossum committed
540
		self->ob_cdcallbacks[i].ob_cdcallback = NULL;
541
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
Guido van Rossum's avatar
Guido van Rossum committed
542 543 544
		self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
	}

545 546
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
547 548
}

549
static PyObject *
550
CD_parseframe(cdparserobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
551 552 553 554 555
{
	char *cdfp;
	int length;
	CDFRAME *p;

556
	if (!PyArg_ParseTuple(args, "s#:parseframe", &cdfp, &length))
Guido van Rossum's avatar
Guido van Rossum committed
557 558 559
		return NULL;

	if (length % sizeof(CDFRAME) != 0) {
560
		PyErr_SetString(PyExc_TypeError, "bad length");
Guido van Rossum's avatar
Guido van Rossum committed
561 562 563 564 565 566 567 568
		return NULL;
	}

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

573 574
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
575 576
}

577
static PyObject *
578
CD_removecallback(cdparserobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
579 580 581
{
	int type;

582
	if (!PyArg_ParseTuple(args, "i:removecallback", &type))
Guido van Rossum's avatar
Guido van Rossum committed
583 584
		return NULL;

585
	if (type < 0 || type >= NCALLBACKS) {
586
		PyErr_SetString(PyExc_TypeError, "bad type");
587 588 589
		return NULL;
	}

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

592
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
Guido van Rossum's avatar
Guido van Rossum committed
593 594
	self->ob_cdcallbacks[type].ob_cdcallback = NULL;

595
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
Guido van Rossum's avatar
Guido van Rossum committed
596 597
	self->ob_cdcallbacks[type].ob_cdcallbackarg = NULL;

598 599
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
600 601
}

602
static PyObject *
603
CD_resetparser(cdparserobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
604
{
605
	if (!PyArg_ParseTuple(args, ":resetparser"))
Guido van Rossum's avatar
Guido van Rossum committed
606 607 608 609
		return NULL;

	CDresetparser(self->ob_cdparser);

610 611
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
612 613
}

614
static PyObject *
615
CD_addcallback(cdparserobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
616 617
{
	int type;
618
	PyObject *func, *funcarg;
Guido van Rossum's avatar
Guido van Rossum committed
619 620

	/* XXX - more work here */
621
	if (!PyArg_ParseTuple(args, "iOO:addcallback", &type, &func, &funcarg))
Guido van Rossum's avatar
Guido van Rossum committed
622 623 624
		return NULL;

	if (type < 0 || type >= NCALLBACKS) {
625
		PyErr_SetString(PyExc_TypeError, "argument out of range");
Guido van Rossum's avatar
Guido van Rossum committed
626 627 628
		return NULL;
	}

629
#ifdef CDsetcallback
630 631
	CDaddcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
		      (void *) self);
632
#else
633 634
	CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
		      (void *) self);
635
#endif
636 637
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
	Py_INCREF(func);
638
	self->ob_cdcallbacks[type].ob_cdcallback = func;
639 640
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
	Py_INCREF(funcarg);
641
	self->ob_cdcallbacks[type].ob_cdcallbackarg = funcarg;
Guido van Rossum's avatar
Guido van Rossum committed
642

643 644 645
/*
	if (type == cd_audio) {
		sigfpe_[_UNDERFL].repls = _ZERO;
646 647
		handle_sigfpes(_ON, _EN_UNDERFL, NULL,
		                        _ABORT_ON_ERROR, NULL);
648 649 650
	}
*/

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

655 656 657 658 659 660 661 662
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
663 664 665 666
	{NULL,			NULL} 		/* sentinel */
};

static void
667
cdparser_dealloc(cdparserobject *self)
Guido van Rossum's avatar
Guido van Rossum committed
668 669 670 671
{
	int i;

	for (i = 0; i < NCALLBACKS; i++) {
672
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
Guido van Rossum's avatar
Guido van Rossum committed
673
		self->ob_cdcallbacks[i].ob_cdcallback = NULL;
674
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
Guido van Rossum's avatar
Guido van Rossum committed
675 676 677
		self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
	}
	CDdeleteparser(self->ob_cdparser);
678
	PyObject_Del(self);
Guido van Rossum's avatar
Guido van Rossum committed
679 680
}

681
static PyObject *
682
cdparser_getattr(cdparserobject *self, char *name)
Guido van Rossum's avatar
Guido van Rossum committed
683
{
684
	if (self->ob_cdparser == NULL) {
685
		PyErr_SetString(PyExc_RuntimeError, "no parser active");
686 687 688
		return NULL;
	}

689
	return Py_FindMethod(cdparser_methods, (PyObject *)self, name);
Guido van Rossum's avatar
Guido van Rossum committed
690 691
}

692 693
PyTypeObject CdParsertype = {
	PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossum's avatar
Guido van Rossum committed
694 695 696 697 698
	0,			/*ob_size*/
	"cdparser",		/*tp_name*/
	sizeof(cdparserobject),	/*tp_size*/
	0,			/*tp_itemsize*/
	/* methods */
699
	(destructor)cdparser_dealloc, /*tp_dealloc*/
Guido van Rossum's avatar
Guido van Rossum committed
700
	0,			/*tp_print*/
701
	(getattrfunc)cdparser_getattr, /*tp_getattr*/
Guido van Rossum's avatar
Guido van Rossum committed
702 703 704 705 706
	0,			/*tp_setattr*/
	0,			/*tp_compare*/
	0,			/*tp_repr*/
};

707
static PyObject *
708
newcdparserobject(CDPARSER *cdp)
Guido van Rossum's avatar
Guido van Rossum committed
709 710 711 712
{
	cdparserobject *p;
	int i;

713
	p = PyObject_New(cdparserobject, &CdParsertype);
Guido van Rossum's avatar
Guido van Rossum committed
714 715 716 717 718 719 720
	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;
	}
721
	return (PyObject *) p;
Guido van Rossum's avatar
Guido van Rossum committed
722 723
}

724
static PyObject *
725
CD_createparser(PyObject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
726 727 728
{
	CDPARSER *cdp;

729
	if (!PyArg_ParseTuple(args, ":createparser"))
Guido van Rossum's avatar
Guido van Rossum committed
730 731 732
		return NULL;
	cdp = CDcreateparser();
	if (cdp == NULL) {
733
		PyErr_SetString(CdError, "createparser failed");
Guido van Rossum's avatar
Guido van Rossum committed
734 735 736 737 738 739
		return NULL;
	}

	return newcdparserobject(cdp);
}

740
static PyObject *
741
CD_msftoframe(PyObject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
742
{
743
	int min, sec, frame;
Guido van Rossum's avatar
Guido van Rossum committed
744

745
	if (!PyArg_ParseTuple(args, "iii:msftoframe", &min, &sec, &frame))
Guido van Rossum's avatar
Guido van Rossum committed
746 747
		return NULL;

748
	return PyInt_FromLong((long) CDmsftoframe(min, sec, frame));
Guido van Rossum's avatar
Guido van Rossum committed
749
}
750
	
751 752 753 754
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
755 756 757 758
	{NULL,		NULL}	/* Sentinel */
};

void
759
initcd(void)
Guido van Rossum's avatar
Guido van Rossum committed
760
{
761
	PyObject *m, *d;
762

763 764
	m = Py_InitModule("cd", CD_methods);
	d = PyModule_GetDict(m);
765

Guido van Rossum's avatar
Guido van Rossum committed
766
	CdError = PyErr_NewException("cd.error", NULL, NULL);
767
	PyDict_SetItemString(d, "error", CdError);
768 769

	/* Identifiers for the different types of callbacks from the parser */
770 771 772 773 774 775 776 777
	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));
778 779

	/* Block size information for digital audio data */
780 781 782 783
	PyDict_SetItemString(d, "DATASIZE",
			   PyInt_FromLong((long) CDDA_DATASIZE));
	PyDict_SetItemString(d, "BLOCKSIZE",
			   PyInt_FromLong((long) CDDA_BLOCKSIZE));
784 785

	/* Possible states for the cd player */
786 787 788 789 790 791
	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));
792
#ifdef CD_CDROM			/* only newer versions of the library */
793
	PyDict_SetItemString(d, "CDROM", PyInt_FromLong((long) CD_CDROM));
794
#endif
Guido van Rossum's avatar
Guido van Rossum committed
795
}