Home | History | Annotate | Download | only in snd
      1 # This script generates the Sound interface for Python.
      2 # It uses the "bgen" package to generate C code.
      3 # It execs the file sndgen.py which contain the function definitions
      4 # (sndgen.py was generated by sndscan.py, scanning the <Sound.h> header file).
      5 
      6 from macsupport import *
      7 
      8 
      9 # define our own function and module generators
     10 
     11 class SndMixIn: pass
     12 
     13 class SndFunction(SndMixIn, OSErrFunctionGenerator): pass
     14 class SndMethod(SndMixIn, OSErrMethodGenerator): pass
     15 
     16 
     17 # includestuff etc. are imported from macsupport
     18 
     19 includestuff = includestuff + """
     20 #include <Carbon/Carbon.h>
     21 """
     22 
     23 initstuff = initstuff + """
     24 """
     25 
     26 
     27 # define types used for arguments (in addition to standard and macsupport types)
     28 
     29 class SndChannelPtrType(OpaqueByValueType):
     30     def declare(self, name):
     31         # Initializing all SndChannelPtr objects to 0 saves
     32         # special-casing NewSndChannel(), where it is formally an
     33         # input-output parameter but we treat it as output-only
     34         # (since Python users are not supposed to allocate memory)
     35         Output("SndChannelPtr %s = 0;", name)
     36 
     37 SndChannelPtr = SndChannelPtrType('SndChannelPtr', 'SndCh')
     38 
     39 SndCommand = OpaqueType('SndCommand', 'SndCmd')
     40 SndCommand_ptr = OpaqueType('SndCommand', 'SndCmd')
     41 SndListHandle = OpaqueByValueType("SndListHandle", "ResObj")
     42 SPBPtr = OpaqueByValueType("SPBPtr", "SPBObj")
     43 ModalFilterUPP = FakeType("(ModalFilterUPP)0")
     44 
     45 #
     46 # NOTE: the following is pretty dangerous. For void pointers we pass buffer addresses
     47 # but we have no way to check that the buffer is big enough. This is the same problem
     48 # as in C, though (but Pythoneers may not be suspecting this...)
     49 void_ptr = Type("void *", "w")
     50 
     51 class SndCallBackType(InputOnlyType):
     52     def __init__(self):
     53         Type.__init__(self, 'PyObject*', 'O')
     54     def getargsCheck(self, name):
     55         Output("if (%s != Py_None && !PyCallable_Check(%s))", name, name)
     56         OutLbrace()
     57         Output('PyErr_SetString(PyExc_TypeError, "callback must be callable");')
     58         Output("goto %s__error__;", name)
     59         OutRbrace()
     60     def passInput(self, name):
     61         return "NewSndCallBackUPP(SndCh_UserRoutine)"
     62     def cleanup(self, name):
     63         # XXX This knows it is executing inside the SndNewChannel wrapper
     64         Output("if (_res != NULL && %s != Py_None)", name)
     65         OutLbrace()
     66         Output("SndChannelObject *p = (SndChannelObject *)_res;")
     67         Output("p->ob_itself->userInfo = (long)p;")
     68         Output("Py_INCREF(%s);", name)
     69         Output("p->ob_callback = %s;", name)
     70         OutRbrace()
     71         DedentLevel()
     72         Output(" %s__error__: ;", name)
     73         IndentLevel()
     74 
     75 SndCallBackProcPtr = SndCallBackType()
     76 SndCallBackUPP = SndCallBackProcPtr
     77 
     78 SndCompletionProcPtr = FakeType('(SndCompletionProcPtr)0') # XXX
     79 SndCompletionUPP = SndCompletionProcPtr
     80 
     81 ##InOutBuf128 = FixedInputOutputBufferType(128)
     82 StateBlock = StructInputOutputBufferType('StateBlock')
     83 
     84 AudioSelectionPtr = FakeType('0') # XXX
     85 
     86 ProcPtr = FakeType('0') # XXX
     87 FilePlayCompletionUPP = FakeType('0') # XXX
     88 
     89 SCStatus = StructOutputBufferType('SCStatus')
     90 SMStatus = StructOutputBufferType('SMStatus')
     91 CompressionInfo = StructOutputBufferType('CompressionInfo')
     92 
     93 includestuff = includestuff + """
     94 /* Convert a SndCommand argument */
     95 static int
     96 SndCmd_Convert(PyObject *v, SndCommand *pc)
     97 {
     98         int len;
     99         pc->param1 = 0;
    100         pc->param2 = 0;
    101         if (PyTuple_Check(v)) {
    102                 if (PyArg_ParseTuple(v, "h|hl", &pc->cmd, &pc->param1, &pc->param2))
    103                         return 1;
    104                 PyErr_Clear();
    105                 return PyArg_ParseTuple(v, "Hhs#", &pc->cmd, &pc->param1, &pc->param2, &len);
    106         }
    107         return PyArg_Parse(v, "H", &pc->cmd);
    108 }
    109 
    110 static pascal void SndCh_UserRoutine(SndChannelPtr chan, SndCommand *cmd); /* Forward */
    111 static pascal void SPB_completion(SPBPtr my_spb); /* Forward */
    112 """
    113 
    114 
    115 finalstuff = finalstuff + """
    116 /* Routine passed to Py_AddPendingCall -- call the Python callback */
    117 static int
    118 SndCh_CallCallBack(void *arg)
    119 {
    120         SndChannelObject *p = (SndChannelObject *)arg;
    121         PyObject *args;
    122         PyObject *res;
    123         args = Py_BuildValue("(O(hhl))",
    124                              p, p->ob_cmd.cmd, p->ob_cmd.param1, p->ob_cmd.param2);
    125         res = PyEval_CallObject(p->ob_callback, args);
    126         Py_DECREF(args);
    127         if (res == NULL)
    128                 return -1;
    129         Py_DECREF(res);
    130         return 0;
    131 }
    132 
    133 /* Routine passed to NewSndChannel -- schedule a call to SndCh_CallCallBack */
    134 static pascal void
    135 SndCh_UserRoutine(SndChannelPtr chan, SndCommand *cmd)
    136 {
    137         SndChannelObject *p = (SndChannelObject *)(chan->userInfo);
    138         if (p->ob_callback != NULL) {
    139                 long A5 = SetA5(p->ob_A5);
    140                 p->ob_cmd = *cmd;
    141                 Py_AddPendingCall(SndCh_CallCallBack, (void *)p);
    142                 SetA5(A5);
    143         }
    144 }
    145 
    146 /* SPB callbacks - Schedule callbacks to Python */
    147 static int
    148 SPB_CallCallBack(void *arg)
    149 {
    150         SPBObject *p = (SPBObject *)arg;
    151         PyObject *args;
    152         PyObject *res;
    153 
    154         if ( p->ob_thiscallback == 0 ) return 0;
    155         args = Py_BuildValue("(O)", p);
    156         res = PyEval_CallObject(p->ob_thiscallback, args);
    157         p->ob_thiscallback = 0;
    158         Py_DECREF(args);
    159         if (res == NULL)
    160                 return -1;
    161         Py_DECREF(res);
    162         return 0;
    163 }
    164 
    165 static pascal void
    166 SPB_completion(SPBPtr my_spb)
    167 {
    168         SPBObject *p = (SPBObject *)(my_spb->userLong);
    169 
    170         if (p && p->ob_completion) {
    171                 long A5 = SetA5(p->ob_A5);
    172                 p->ob_thiscallback = p->ob_completion;  /* Hope we cannot get two at the same time */
    173                 Py_AddPendingCall(SPB_CallCallBack, (void *)p);
    174                 SetA5(A5);
    175         }
    176 }
    177 
    178 """
    179 
    180 
    181 # create the module and object definition and link them
    182 
    183 class SndObjectDefinition(PEP252Mixin, ObjectDefinition):
    184 
    185     def outputStructMembers(self):
    186         ObjectDefinition.outputStructMembers(self)
    187         Output("/* Members used to implement callbacks: */")
    188         Output("PyObject *ob_callback;")
    189         Output("long ob_A5;");
    190         Output("SndCommand ob_cmd;")
    191 
    192     def outputInitStructMembers(self):
    193         ObjectDefinition.outputInitStructMembers(self)
    194         Output("it->ob_callback = NULL;")
    195         Output("it->ob_A5 = SetCurrentA5();");
    196 
    197     def outputCleanupStructMembers(self):
    198         ObjectDefinition.outputCleanupStructMembers(self)
    199         Output("Py_XDECREF(self->ob_callback);")
    200 
    201     def outputFreeIt(self, itselfname):
    202         Output("SndDisposeChannel(%s, 1);", itselfname)
    203 
    204     def outputConvert(self):
    205         pass # Not needed
    206 
    207 #
    208 
    209 class SpbObjectDefinition(PEP252Mixin, ObjectDefinition):
    210     getsetlist = [
    211             (
    212             'inRefNum',
    213             'return Py_BuildValue("l", self->ob_spb.inRefNum);',
    214             'return -1 + PyArg_Parse(v, "l", &self->ob_spb.inRefNum);',
    215             None,
    216             ), (
    217             'count',
    218             'return Py_BuildValue("l", self->ob_spb.count);',
    219             'return -1 + PyArg_Parse(v, "l", &self->ob_spb.count);',
    220             None
    221             ), (
    222             'milliseconds',
    223             'return Py_BuildValue("l", self->ob_spb.milliseconds);',
    224             'return -1 + PyArg_Parse(v, "l", &self->ob_spb.milliseconds);',
    225             None,
    226             ), (
    227             'error',
    228             'return Py_BuildValue("h", self->ob_spb.error);',
    229             None,
    230             None
    231             ), (
    232             'completionRoutine',
    233             None,
    234             """self->ob_spb.completionRoutine = NewSICompletionUPP(SPB_completion);
    235             self->ob_completion = v;
    236             Py_INCREF(v);
    237             return 0;""",
    238             None,
    239             )]
    240 
    241     def outputStructMembers(self):
    242         Output("/* Members used to implement callbacks: */")
    243         Output("PyObject *ob_completion;")
    244         Output("PyObject *ob_interrupt;")
    245         Output("PyObject *ob_thiscallback;");
    246         Output("long ob_A5;")
    247         Output("SPB ob_spb;")
    248 
    249     def outputNew(self):
    250         Output()
    251         Output("%sPyObject *%s_New(void)", self.static, self.prefix)
    252         OutLbrace()
    253         Output("%s *it;", self.objecttype)
    254         self.outputCheckNewArg()
    255         Output("it = PyObject_NEW(%s, &%s);", self.objecttype, self.typename)
    256         Output("if (it == NULL) return NULL;")
    257         self.outputInitStructMembers()
    258         Output("return (PyObject *)it;")
    259         OutRbrace()
    260 
    261     def outputInitStructMembers(self):
    262         Output("it->ob_completion = NULL;")
    263         Output("it->ob_interrupt = NULL;")
    264         Output("it->ob_thiscallback = NULL;")
    265         Output("it->ob_A5 = SetCurrentA5();")
    266         Output("memset((char *)&it->ob_spb, 0, sizeof(it->ob_spb));")
    267         Output("it->ob_spb.userLong = (long)it;")
    268 
    269     def outputCleanupStructMembers(self):
    270         ObjectDefinition.outputCleanupStructMembers(self)
    271         Output("self->ob_spb.userLong = 0;")
    272         Output("self->ob_thiscallback = 0;")
    273         Output("Py_XDECREF(self->ob_completion);")
    274         Output("Py_XDECREF(self->ob_interrupt);")
    275 
    276     def outputConvert(self):
    277         Output("%sint %s_Convert(PyObject *v, %s *p_itself)", self.static, self.prefix, self.itselftype)
    278         OutLbrace()
    279         self.outputCheckConvertArg()
    280         Output("if (!%s_Check(v))", self.prefix)
    281         OutLbrace()
    282         Output('PyErr_SetString(PyExc_TypeError, "%s required");', self.name)
    283         Output("return 0;")
    284         OutRbrace()
    285         Output("*p_itself = &((%s *)v)->ob_spb;", self.objecttype)
    286         Output("return 1;")
    287         OutRbrace()
    288 
    289 
    290 sndobject = SndObjectDefinition('SndChannel', 'SndCh', 'SndChannelPtr')
    291 spbobject = SpbObjectDefinition('SPB', 'SPBObj', 'SPBPtr')
    292 spbgenerator = ManualGenerator("SPB", "_res = SPBObj_New(); return _res;")
    293 module = MacModule('_Snd', 'Snd', includestuff, finalstuff, initstuff)
    294 module.addobject(sndobject)
    295 module.addobject(spbobject)
    296 module.add(spbgenerator)
    297 
    298 
    299 # create lists of functions and object methods
    300 
    301 functions = []
    302 sndmethods = []
    303 
    304 
    305 # populate the lists
    306 
    307 execfile('sndgen.py')
    308 
    309 
    310 # add the functions and methods to the module and object, respectively
    311 
    312 for f in functions: module.add(f)
    313 for f in sndmethods: sndobject.add(f)
    314 
    315 
    316 # generate output
    317 
    318 SetOutputFileName('_Sndmodule.c')
    319 module.generate()
    320