home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 15 / AACD15.ISO / AACD / Programming / Python2 / Python20_source / Modules / cdmodule.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-25  |  18.5 KB  |  796 lines

  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.         if (_PyString_Resize(&result, n * sizeof(CDFRAME)))
  255.             return NULL;
  256.  
  257.     return result;
  258. }
  259.  
  260. static PyObject *
  261. CD_seek(cdplayerobject *self, PyObject *args)
  262. {
  263.     int min, sec, frame;
  264.     long PyTryBlock;
  265.  
  266.     if (!PyArg_ParseTuple(args, "iii:seek", &min, &sec, &frame))
  267.         return NULL;
  268.  
  269.     PyTryBlock = CDseek(self->ob_cdplayer, min, sec, frame);
  270.     if (PyTryBlock == -1) {
  271.         PyErr_SetFromErrno(CdError);
  272.         return NULL;
  273.     }
  274.  
  275.     return PyInt_FromLong(PyTryBlock);
  276. }
  277.     
  278. static PyObject *
  279. CD_seektrack(cdplayerobject *self, PyObject *args)
  280. {
  281.     int track;
  282.     long PyTryBlock;
  283.  
  284.     if (!PyArg_ParseTuple(args, "i:seektrack", &track))
  285.         return NULL;
  286.  
  287.     PyTryBlock = CDseektrack(self->ob_cdplayer, track);
  288.     if (PyTryBlock == -1) {
  289.         PyErr_SetFromErrno(CdError);
  290.         return NULL;
  291.     }
  292.  
  293.     return PyInt_FromLong(PyTryBlock);
  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.         return NULL;
  303.  
  304.     PyTryBlock = CDseekblock(self->ob_cdplayer, PyTryBlock);
  305.     if (PyTryBlock == (unsigned long) -1) {
  306.         PyErr_SetFromErrno(CdError);
  307.         return NULL;
  308.     }
  309.  
  310.     return PyInt_FromLong(PyTryBlock);
  311. }
  312.     
  313. static PyObject *
  314. CD_stop(cdplayerobject *self, PyObject *args)
  315. {
  316.     CDSTATUS status;
  317.  
  318.     if (!PyArg_ParseTuple(args, ":stop"))
  319.         return NULL;
  320.  
  321.     if (!CDstop(self->ob_cdplayer)) {
  322.         if (CDgetstatus(self->ob_cdplayer, &status) &&
  323.             status.state == CD_NODISC)
  324.             PyErr_SetString(CdError, "no disc in player");
  325.         else
  326.             PyErr_SetString(CdError, "stop failed");
  327.         return NULL;
  328.     }
  329.  
  330.     Py_INCREF(Py_None);
  331.     return Py_None;
  332. }
  333.     
  334. static PyObject *
  335. CD_togglepause(cdplayerobject *self, PyObject *args)
  336. {
  337.     CDSTATUS status;
  338.  
  339.     if (!PyArg_ParseTuple(args, ":togglepause"))
  340.         return NULL;
  341.  
  342.     if (!CDtogglepause(self->ob_cdplayer)) {
  343.         if (CDgetstatus(self->ob_cdplayer, &status) &&
  344.             status.state == CD_NODISC)
  345.             PyErr_SetString(CdError, "no disc in player");
  346.         else
  347.             PyErr_SetString(CdError, "togglepause failed");
  348.         return NULL;
  349.     }
  350.  
  351.     Py_INCREF(Py_None);
  352.     return Py_None;
  353. }
  354.     
  355. static PyMethodDef cdplayer_methods[] = {
  356.     {"allowremoval",    (PyCFunction)CD_allowremoval,    1},
  357.     {"bestreadsize",    (PyCFunction)CD_bestreadsize,    1},
  358.     {"close",        (PyCFunction)CD_close,        1},
  359.     {"eject",        (PyCFunction)CD_eject,        1},
  360.     {"getstatus",        (PyCFunction)CD_getstatus,        1},
  361.     {"gettrackinfo",    (PyCFunction)CD_gettrackinfo,    1},
  362.     {"msftoblock",        (PyCFunction)CD_msftoblock,        1},
  363.     {"play",        (PyCFunction)CD_play,        1},
  364.     {"playabs",        (PyCFunction)CD_playabs,        1},
  365.     {"playtrack",        (PyCFunction)CD_playtrack,        1},
  366.     {"playtrackabs",    (PyCFunction)CD_playtrackabs,    1},
  367.     {"preventremoval",    (PyCFunction)CD_preventremoval,    1},
  368.     {"readda",        (PyCFunction)CD_readda,        1},
  369.     {"seek",        (PyCFunction)CD_seek,        1},
  370.     {"seekblock",        (PyCFunction)CD_seekblock,        1},
  371.     {"seektrack",        (PyCFunction)CD_seektrack,        1},
  372.     {"stop",        (PyCFunction)CD_stop,        1},
  373.     {"togglepause",        (PyCFunction)CD_togglepause,       1},
  374.     {NULL,            NULL}         /* sentinel */
  375. };
  376.  
  377. static void
  378. cdplayer_dealloc(cdplayerobject *self)
  379. {
  380.     if (self->ob_cdplayer != NULL)
  381.         CDclose(self->ob_cdplayer);
  382.     PyObject_Del(self);
  383. }
  384.  
  385. static PyObject *
  386. cdplayer_getattr(cdplayerobject *self, char *name)
  387. {
  388.     if (self->ob_cdplayer == NULL) {
  389.         PyErr_SetString(PyExc_RuntimeError, "no player active");
  390.         return NULL;
  391.     }
  392.     return Py_FindMethod(cdplayer_methods, (PyObject *)self, name);
  393. }
  394.  
  395. PyTypeObject CdPlayertype = {
  396.     PyObject_HEAD_INIT(&PyType_Type)
  397.     0,            /*ob_size*/
  398.     "cdplayer",        /*tp_name*/
  399.     sizeof(cdplayerobject),    /*tp_size*/
  400.     0,            /*tp_itemsize*/
  401.     /* methods */
  402.     (destructor)cdplayer_dealloc, /*tp_dealloc*/
  403.     0,            /*tp_print*/
  404.     (getattrfunc)cdplayer_getattr, /*tp_getattr*/
  405.     0,            /*tp_setattr*/
  406.     0,            /*tp_compare*/
  407.     0,            /*tp_repr*/
  408. };
  409.  
  410. static PyObject *
  411. newcdplayerobject(CDPLAYER *cdp)
  412. {
  413.     cdplayerobject *p;
  414.  
  415.     p = PyObject_New(cdplayerobject, &CdPlayertype);
  416.     if (p == NULL)
  417.         return NULL;
  418.     p->ob_cdplayer = cdp;
  419.     return (PyObject *) p;
  420. }
  421.  
  422. static PyObject *
  423. CD_open(PyObject *self, PyObject *args)
  424. {
  425.     char *dev, *direction;
  426.     CDPLAYER *cdp;
  427.  
  428.     /*
  429.      * Variable number of args.
  430.      * First defaults to "None", second defaults to "r".
  431.      */
  432.     dev = NULL;
  433.     direction = "r";
  434.     if (!PyArg_ParseTuple(args, "|zs:open", &dev, &direction))
  435.         return NULL;
  436.  
  437.     cdp = CDopen(dev, direction);
  438.     if (cdp == NULL) {
  439.         PyErr_SetFromErrno(CdError);
  440.         return NULL;
  441.     }
  442.  
  443.     return newcdplayerobject(cdp);
  444. }
  445.  
  446. typedef struct {
  447.     PyObject_HEAD
  448.     CDPARSER *ob_cdparser;
  449.     struct {
  450.         PyObject *ob_cdcallback;
  451.         PyObject *ob_cdcallbackarg;
  452.     } ob_cdcallbacks[NCALLBACKS];
  453. } cdparserobject;
  454.  
  455. static void
  456. CD_callback(void *arg, CDDATATYPES type, void *data)
  457. {
  458.     PyObject *result, *args, *v = NULL;
  459.     char *p;
  460.     int i;
  461.     cdparserobject *self;
  462.  
  463.     self = (cdparserobject *) arg;
  464.     args = PyTuple_New(3);
  465.     if (args == NULL)
  466.         return;
  467.     Py_INCREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
  468.     PyTuple_SetItem(args, 0, self->ob_cdcallbacks[type].ob_cdcallbackarg);
  469.     PyTuple_SetItem(args, 1, PyInt_FromLong((long) type));
  470.     switch (type) {
  471.     case cd_audio:
  472.         v = PyString_FromStringAndSize(data, CDDA_DATASIZE);
  473.         break;
  474.     case cd_pnum:
  475.     case cd_index:
  476.         v = PyInt_FromLong(((CDPROGNUM *) data)->value);
  477.         break;
  478.     case cd_ptime:
  479.     case cd_atime:
  480. #define ptr ((struct cdtimecode *) data)
  481.         v = Py_BuildValue("(iii)",
  482.                 ptr->mhi * 10 + ptr->mlo,
  483.                 ptr->shi * 10 + ptr->slo,
  484.                 ptr->fhi * 10 + ptr->flo);
  485. #undef ptr
  486.         break;
  487.     case cd_catalog:
  488.         v = PyString_FromStringAndSize(NULL, 13);
  489.         p = PyString_AsString(v);
  490.         for (i = 0; i < 13; i++)
  491.             *p++ = ((char *) data)[i] + '0';
  492.         break;
  493.     case cd_ident:
  494. #define ptr ((struct cdident *) data)
  495.         v = PyString_FromStringAndSize(NULL, 12);
  496.         p = PyString_AsString(v);
  497.         CDsbtoa(p, ptr->country, 2);
  498.         p += 2;
  499.         CDsbtoa(p, ptr->owner, 3);
  500.         p += 3;
  501.         *p++ = ptr->year[0] + '0';
  502.         *p++ = ptr->year[1] + '0';
  503.         *p++ = ptr->serial[0] + '0';
  504.         *p++ = ptr->serial[1] + '0';
  505.         *p++ = ptr->serial[2] + '0';
  506.         *p++ = ptr->serial[3] + '0';
  507.         *p++ = ptr->serial[4] + '0';
  508. #undef ptr
  509.         break;
  510.     case cd_control:
  511.         v = PyInt_FromLong((long) *((unchar *) data));
  512.         break;
  513.     }
  514.     PyTuple_SetItem(args, 2, v);
  515.     if (PyErr_Occurred()) {
  516.         Py_DECREF(args);
  517.         return;
  518.     }
  519.     
  520.     result = PyEval_CallObject(self->ob_cdcallbacks[type].ob_cdcallback,
  521.                    args);
  522.     Py_DECREF(args);
  523.     Py_XDECREF(result);
  524. }
  525.  
  526. static PyObject *
  527. CD_deleteparser(cdparserobject *self, PyObject *args)
  528. {
  529.     int i;
  530.  
  531.     if (!PyArg_ParseTuple(args, ":deleteparser"))
  532.         return NULL;
  533.  
  534.     CDdeleteparser(self->ob_cdparser);
  535.     self->ob_cdparser = NULL;
  536.  
  537.     /* no sense in keeping the callbacks, so remove them */
  538.     for (i = 0; i < NCALLBACKS; i++) {
  539.         Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
  540.         self->ob_cdcallbacks[i].ob_cdcallback = NULL;
  541.         Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
  542.         self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
  543.     }
  544.  
  545.     Py_INCREF(Py_None);
  546.     return Py_None;
  547. }
  548.  
  549. static PyObject *
  550. CD_parseframe(cdparserobject *self, PyObject *args)
  551. {
  552.     char *cdfp;
  553.     int length;
  554.     CDFRAME *p;
  555.  
  556.     if (!PyArg_ParseTuple(args, "s#:parseframe", &cdfp, &length))
  557.         return NULL;
  558.  
  559.     if (length % sizeof(CDFRAME) != 0) {
  560.         PyErr_SetString(PyExc_TypeError, "bad length");
  561.         return NULL;
  562.     }
  563.  
  564.     p = (CDFRAME *) cdfp;
  565.     while (length > 0) {
  566.         CDparseframe(self->ob_cdparser, p);
  567.         length -= sizeof(CDFRAME);
  568.         p++;
  569.         if (PyErr_Occurred())
  570.             return NULL;
  571.     }
  572.  
  573.     Py_INCREF(Py_None);
  574.     return Py_None;
  575. }
  576.  
  577. static PyObject *
  578. CD_removecallback(cdparserobject *self, PyObject *args)
  579. {
  580.     int type;
  581.  
  582.     if (!PyArg_ParseTuple(args, "i:removecallback", &type))
  583.         return NULL;
  584.  
  585.     if (type < 0 || type >= NCALLBACKS) {
  586.         PyErr_SetString(PyExc_TypeError, "bad type");
  587.         return NULL;
  588.     }
  589.  
  590.     CDremovecallback(self->ob_cdparser, (CDDATATYPES) type);
  591.  
  592.     Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
  593.     self->ob_cdcallbacks[type].ob_cdcallback = NULL;
  594.  
  595.     Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
  596.     self->ob_cdcallbacks[type].ob_cdcallbackarg = NULL;
  597.  
  598.     Py_INCREF(Py_None);
  599.     return Py_None;
  600. }
  601.  
  602. static PyObject *
  603. CD_resetparser(cdparserobject *self, PyObject *args)
  604. {
  605.     if (!PyArg_ParseTuple(args, ":resetparser"))
  606.         return NULL;
  607.  
  608.     CDresetparser(self->ob_cdparser);
  609.  
  610.     Py_INCREF(Py_None);
  611.     return Py_None;
  612. }
  613.  
  614. static PyObject *
  615. CD_addcallback(cdparserobject *self, PyObject *args)
  616. {
  617.     int type;
  618.     PyObject *func, *funcarg;
  619.  
  620.     /* XXX - more work here */
  621.     if (!PyArg_ParseTuple(args, "iOO:addcallback", &type, &func, &funcarg))
  622.         return NULL;
  623.  
  624.     if (type < 0 || type >= NCALLBACKS) {
  625.         PyErr_SetString(PyExc_TypeError, "argument out of range");
  626.         return NULL;
  627.     }
  628.  
  629. #ifdef CDsetcallback
  630.     CDaddcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
  631.               (void *) self);
  632. #else
  633.     CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
  634.               (void *) self);
  635. #endif
  636.     Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
  637.     Py_INCREF(func);
  638.     self->ob_cdcallbacks[type].ob_cdcallback = func;
  639.     Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
  640.     Py_INCREF(funcarg);
  641.     self->ob_cdcallbacks[type].ob_cdcallbackarg = funcarg;
  642.  
  643. /*
  644.     if (type == cd_audio) {
  645.         sigfpe_[_UNDERFL].repls = _ZERO;
  646.         handle_sigfpes(_ON, _EN_UNDERFL, NULL,
  647.                                 _ABORT_ON_ERROR, NULL);
  648.     }
  649. */
  650.  
  651.     Py_INCREF(Py_None);
  652.     return Py_None;
  653. }
  654.  
  655. static PyMethodDef cdparser_methods[] = {
  656.     {"addcallback",        (PyCFunction)CD_addcallback,       1},
  657.     {"deleteparser",    (PyCFunction)CD_deleteparser,    1},
  658.     {"parseframe",        (PyCFunction)CD_parseframe,    1},
  659.     {"removecallback",    (PyCFunction)CD_removecallback,    1},
  660.     {"resetparser",        (PyCFunction)CD_resetparser,    1},
  661.                                         /* backward compatibility */
  662.     {"setcallback",        (PyCFunction)CD_addcallback,       1},
  663.     {NULL,            NULL}         /* sentinel */
  664. };
  665.  
  666. static void
  667. cdparser_dealloc(cdparserobject *self)
  668. {
  669.     int i;
  670.  
  671.     for (i = 0; i < NCALLBACKS; i++) {
  672.         Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
  673.         self->ob_cdcallbacks[i].ob_cdcallback = NULL;
  674.         Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
  675.         self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
  676.     }
  677.     CDdeleteparser(self->ob_cdparser);
  678.     PyObject_Del(self);
  679. }
  680.  
  681. static PyObject *
  682. cdparser_getattr(cdparserobject *self, char *name)
  683. {
  684.     if (self->ob_cdparser == NULL) {
  685.         PyErr_SetString(PyExc_RuntimeError, "no parser active");
  686.         return NULL;
  687.     }
  688.  
  689.     return Py_FindMethod(cdparser_methods, (PyObject *)self, name);
  690. }
  691.  
  692. PyTypeObject CdParsertype = {
  693.     PyObject_HEAD_INIT(&PyType_Type)
  694.     0,            /*ob_size*/
  695.     "cdparser",        /*tp_name*/
  696.     sizeof(cdparserobject),    /*tp_size*/
  697.     0,            /*tp_itemsize*/
  698.     /* methods */
  699.     (destructor)cdparser_dealloc, /*tp_dealloc*/
  700.     0,            /*tp_print*/
  701.     (getattrfunc)cdparser_getattr, /*tp_getattr*/
  702.     0,            /*tp_setattr*/
  703.     0,            /*tp_compare*/
  704.     0,            /*tp_repr*/
  705. };
  706.  
  707. static PyObject *
  708. newcdparserobject(CDPARSER *cdp)
  709. {
  710.     cdparserobject *p;
  711.     int i;
  712.  
  713.     p = PyObject_New(cdparserobject, &CdParsertype);
  714.     if (p == NULL)
  715.         return NULL;
  716.     p->ob_cdparser = cdp;
  717.     for (i = 0; i < NCALLBACKS; i++) {
  718.         p->ob_cdcallbacks[i].ob_cdcallback = NULL;
  719.         p->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
  720.     }
  721.     return (PyObject *) p;
  722. }
  723.  
  724. static PyObject *
  725. CD_createparser(PyObject *self, PyObject *args)
  726. {
  727.     CDPARSER *cdp;
  728.  
  729.     if (!PyArg_ParseTuple(args, ":createparser"))
  730.         return NULL;
  731.     cdp = CDcreateparser();
  732.     if (cdp == NULL) {
  733.         PyErr_SetString(CdError, "createparser failed");
  734.         return NULL;
  735.     }
  736.  
  737.     return newcdparserobject(cdp);
  738. }
  739.  
  740. static PyObject *
  741. CD_msftoframe(PyObject *self, PyObject *args)
  742. {
  743.     int min, sec, frame;
  744.  
  745.     if (!PyArg_ParseTuple(args, "iii:msftoframe", &min, &sec, &frame))
  746.         return NULL;
  747.  
  748.     return PyInt_FromLong((long) CDmsftoframe(min, sec, frame));
  749. }
  750.     
  751. static PyMethodDef CD_methods[] = {
  752.     {"open",        (PyCFunction)CD_open,        1},
  753.     {"createparser",    (PyCFunction)CD_createparser,    1},
  754.     {"msftoframe",        (PyCFunction)CD_msftoframe,    1},
  755.     {NULL,        NULL}    /* Sentinel */
  756. };
  757.  
  758. void
  759. initcd(void)
  760. {
  761.     PyObject *m, *d;
  762.  
  763.     m = Py_InitModule("cd", CD_methods);
  764.     d = PyModule_GetDict(m);
  765.  
  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.     PyDict_SetItemString(d, "audio", PyInt_FromLong((long) cd_audio));
  771.     PyDict_SetItemString(d, "pnum", PyInt_FromLong((long) cd_pnum));
  772.     PyDict_SetItemString(d, "index", PyInt_FromLong((long) cd_index));
  773.     PyDict_SetItemString(d, "ptime", PyInt_FromLong((long) cd_ptime));
  774.     PyDict_SetItemString(d, "atime", PyInt_FromLong((long) cd_atime));
  775.     PyDict_SetItemString(d, "catalog", PyInt_FromLong((long) cd_catalog));
  776.     PyDict_SetItemString(d, "ident", PyInt_FromLong((long) cd_ident));
  777.     PyDict_SetItemString(d, "control", PyInt_FromLong((long) cd_control));
  778.  
  779.     /* Block size information for digital audio data */
  780.     PyDict_SetItemString(d, "DATASIZE",
  781.                PyInt_FromLong((long) CDDA_DATASIZE));
  782.     PyDict_SetItemString(d, "BLOCKSIZE",
  783.                PyInt_FromLong((long) CDDA_BLOCKSIZE));
  784.  
  785.     /* Possible states for the cd player */
  786.     PyDict_SetItemString(d, "ERROR", PyInt_FromLong((long) CD_ERROR));
  787.     PyDict_SetItemString(d, "NODISC", PyInt_FromLong((long) CD_NODISC));
  788.     PyDict_SetItemString(d, "READY", PyInt_FromLong((long) CD_READY));
  789.     PyDict_SetItemString(d, "PLAYING", PyInt_FromLong((long) CD_PLAYING));
  790.     PyDict_SetItemString(d, "PAUSED", PyInt_FromLong((long) CD_PAUSED));
  791.     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
  795. }
  796.