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 6from macsupport import * 7 8 9# define our own function and module generators 10 11class SndMixIn: pass 12 13class SndFunction(SndMixIn, OSErrFunctionGenerator): pass 14class SndMethod(SndMixIn, OSErrMethodGenerator): pass 15 16 17# includestuff etc. are imported from macsupport 18 19includestuff = includestuff + """ 20#include <Carbon/Carbon.h> 21""" 22 23initstuff = initstuff + """ 24""" 25 26 27# define types used for arguments (in addition to standard and macsupport types) 28 29class 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 37SndChannelPtr = SndChannelPtrType('SndChannelPtr', 'SndCh') 38 39SndCommand = OpaqueType('SndCommand', 'SndCmd') 40SndCommand_ptr = OpaqueType('SndCommand', 'SndCmd') 41SndListHandle = OpaqueByValueType("SndListHandle", "ResObj") 42SPBPtr = OpaqueByValueType("SPBPtr", "SPBObj") 43ModalFilterUPP = 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...) 49void_ptr = Type("void *", "w") 50 51class 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 75SndCallBackProcPtr = SndCallBackType() 76SndCallBackUPP = SndCallBackProcPtr 77 78SndCompletionProcPtr = FakeType('(SndCompletionProcPtr)0') # XXX 79SndCompletionUPP = SndCompletionProcPtr 80 81##InOutBuf128 = FixedInputOutputBufferType(128) 82StateBlock = StructInputOutputBufferType('StateBlock') 83 84AudioSelectionPtr = FakeType('0') # XXX 85 86ProcPtr = FakeType('0') # XXX 87FilePlayCompletionUPP = FakeType('0') # XXX 88 89SCStatus = StructOutputBufferType('SCStatus') 90SMStatus = StructOutputBufferType('SMStatus') 91CompressionInfo = StructOutputBufferType('CompressionInfo') 92 93includestuff = includestuff + """ 94/* Convert a SndCommand argument */ 95static int 96SndCmd_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 110static pascal void SndCh_UserRoutine(SndChannelPtr chan, SndCommand *cmd); /* Forward */ 111static pascal void SPB_completion(SPBPtr my_spb); /* Forward */ 112""" 113 114 115finalstuff = finalstuff + """ 116/* Routine passed to Py_AddPendingCall -- call the Python callback */ 117static int 118SndCh_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 */ 134static pascal void 135SndCh_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 */ 147static int 148SPB_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 165static pascal void 166SPB_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 183class 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 209class 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 290sndobject = SndObjectDefinition('SndChannel', 'SndCh', 'SndChannelPtr') 291spbobject = SpbObjectDefinition('SPB', 'SPBObj', 'SPBPtr') 292spbgenerator = ManualGenerator("SPB", "_res = SPBObj_New(); return _res;") 293module = MacModule('_Snd', 'Snd', includestuff, finalstuff, initstuff) 294module.addobject(sndobject) 295module.addobject(spbobject) 296module.add(spbgenerator) 297 298 299# create lists of functions and object methods 300 301functions = [] 302sndmethods = [] 303 304 305# populate the lists 306 307execfile('sndgen.py') 308 309 310# add the functions and methods to the module and object, respectively 311 312for f in functions: module.add(f) 313for f in sndmethods: sndobject.add(f) 314 315 316# generate output 317 318SetOutputFileName('_Sndmodule.c') 319module.generate() 320