Showing the changes to sys/src/cmd/python/Modules/cdmodule.c (1 of 3706 files). Show all
Unified · Split
| @@ -0,0 +1,796 @@ | ||
| 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 | + | |
| 10 | +typedef struct { | |
| 11 | + PyObject_HEAD | |
| 12 | + CDPLAYER *ob_cdplayer; | |
| 13 | +} cdplayerobject; | |
| 14 | + | |
| 15 | +static PyObject *CdError; /* exception cd.error */ | |
| 16 | + | |
| 17 | +static PyObject * | |
| 18 | +CD_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 | + | |
| 29 | +static PyObject * | |
| 30 | +CD_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 | + | |
| 41 | +static PyObject * | |
| 42 | +CD_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 | + | |
| 50 | +static PyObject * | |
| 51 | +CD_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 | + | |
| 66 | +static PyObject * | |
| 67 | +CD_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 | + | |
| 87 | +static PyObject * | |
| 88 | +CD_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 | + | |
| 108 | +static PyObject * | |
| 109 | +CD_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 | + | |
| 132 | +static PyObject * | |
| 133 | +CD_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 | + | |
| 144 | +static PyObject * | |
| 145 | +CD_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 | + | |
| 166 | +static PyObject * | |
| 167 | +CD_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 | + | |
| 188 | +static PyObject * | |
| 189 | +CD_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 | + | |
| 210 | +static PyObject * | |
| 211 | +CD_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 | + | |
| 233 | +static PyObject * | |
| 234 | +CD_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 | + | |
| 259 | +static PyObject * | |
| 260 | +CD_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 | + | |
| 277 | +static PyObject * | |
| 278 | +CD_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 | + | |
| 295 | +static PyObject * | |
| 296 | +CD_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 | + | |
| 312 | +static PyObject * | |
| 313 | +CD_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 | + | |
| 333 | +static PyObject * | |
| 334 | +CD_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 | + | |
| 354 | +static 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 | + | |
| 376 | +static void | |
| 377 | +cdplayer_dealloc(cdplayerobject *self) | |
| 378 | +{ | |
| 379 | + if (self->ob_cdplayer != NULL) | |
| 380 | + CDclose(self->ob_cdplayer); | |
| 381 | + PyObject_Del(self); | |
| 382 | +} | |
| 383 | + | |
| 384 | +static PyObject * | |
| 385 | +cdplayer_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 | + | |
| 394 | +PyTypeObject 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 | + | |
| 409 | +static PyObject * | |
| 410 | +newcdplayerobject(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 | + | |
| 421 | +static PyObject * | |
| 422 | +CD_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 | + | |
| 445 | +typedef 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 | + | |
| 454 | +static void | |
| 455 | +CD_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 | + | |
| 525 | +static PyObject * | |
| 526 | +CD_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 | + | |
| 548 | +static PyObject * | |
| 549 | +CD_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 | + | |
| 576 | +static PyObject * | |
| 577 | +CD_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 | + | |
| 601 | +static PyObject * | |
| 602 | +CD_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 | + | |
| 613 | +static PyObject * | |
| 614 | +CD_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 | + | |
| 654 | +static 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 | + | |
| 665 | +static void | |
| 666 | +cdparser_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 | + | |
| 680 | +static PyObject * | |
| 681 | +cdparser_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 | + | |
| 691 | +PyTypeObject 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 | + | |
| 706 | +static PyObject * | |
| 707 | +newcdparserobject(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 | + | |
| 723 | +static PyObject * | |
| 724 | +CD_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 | + | |
| 739 | +static PyObject * | |
| 740 | +CD_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 | + | |
| 750 | +static 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 | + | |
| 757 | +void | |
| 758 | +initcd(void) | |
| 759 | +{ | |
| 760 | + PyObject *m, *d; | |
| 761 | + | |
| 762 | + m = Py_InitModule("cd", CD_methods); | |
| 763 | + if (m == NULL) | |
| 764 | + return; | |
| 765 | + d = PyModule_GetDict(m); | |
| 766 | + | |
| 767 | + CdError = PyErr_NewException("cd.error", NULL, NULL); | |
| 768 | + PyDict_SetItemString(d, "error", CdError); | |
| 769 | + | |
| 770 | + /* Identifiers for the different types of callbacks from the parser */ | |
| 771 | + PyDict_SetItemString(d, "audio", PyInt_FromLong((long) cd_audio)); | |
| 772 | + PyDict_SetItemString(d, "pnum", PyInt_FromLong((long) cd_pnum)); | |
| 773 | + PyDict_SetItemString(d, "index", PyInt_FromLong((long) cd_index)); | |
| 774 | + PyDict_SetItemString(d, "ptime", PyInt_FromLong((long) cd_ptime)); | |
| 775 | + PyDict_SetItemString(d, "atime", PyInt_FromLong((long) cd_atime)); | |
| 776 | + PyDict_SetItemString(d, "catalog", PyInt_FromLong((long) cd_catalog)); | |
| 777 | + PyDict_SetItemString(d, "ident", PyInt_FromLong((long) cd_ident)); | |
| 778 | + PyDict_SetItemString(d, "control", PyInt_FromLong((long) cd_control)); | |
| 779 | + | |
| 780 | + /* Block size information for digital audio data */ | |
| 781 | + PyDict_SetItemString(d, "DATASIZE", | |
| 782 | + PyInt_FromLong((long) CDDA_DATASIZE)); | |
| 783 | + PyDict_SetItemString(d, "BLOCKSIZE", | |
| 784 | + PyInt_FromLong((long) CDDA_BLOCKSIZE)); | |
| 785 | + | |
| 786 | + /* Possible states for the cd player */ | |
| 787 | + PyDict_SetItemString(d, "ERROR", PyInt_FromLong((long) CD_ERROR)); | |
| 788 | + PyDict_SetItemString(d, "NODISC", PyInt_FromLong((long) CD_NODISC)); | |
| 789 | + PyDict_SetItemString(d, "READY", PyInt_FromLong((long) CD_READY)); | |
| 790 | + PyDict_SetItemString(d, "PLAYING", PyInt_FromLong((long) CD_PLAYING)); | |
| 791 | + PyDict_SetItemString(d, "PAUSED", PyInt_FromLong((long) CD_PAUSED)); | |
| 792 | + PyDict_SetItemString(d, "STILL", PyInt_FromLong((long) CD_STILL)); | |
| 793 | +#ifdef CD_CDROM /* only newer versions of the library */ | |
| 794 | + PyDict_SetItemString(d, "CDROM", PyInt_FromLong((long) CD_CDROM)); | |
| 795 | +#endif | |
| 796 | +} | |