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