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).
6 from macsupport
import *
9 # define our own function and module generators
13 class SndFunction(SndMixIn
, OSErrFunctionGenerator
): pass
14 class SndMethod(SndMixIn
, OSErrMethodGenerator
): pass
17 # includestuff etc. are imported from macsupport
19 includestuff
= includestuff
+ """
22 #ifndef HAVE_UNIVERSAL_HEADERS
23 #define SndCallBackUPP ProcPtr
24 #define NewSndCallBackProc(x) ((SndCallBackProcPtr)(x))
25 #define SndListHandle Handle
29 initstuff
= initstuff
+ """
33 # define types used for arguments (in addition to standard and macsupport types)
35 class SndChannelPtrType(OpaqueByValueType
):
36 def declare(self
, name
):
37 # Initializing all SndChannelPtr objects to 0 saves
38 # special-casing NewSndChannel(), where it is formally an
39 # input-output parameter but we treat it as output-only
40 # (since Python users are not supposed to allocate memory)
41 Output("SndChannelPtr %s = 0;", name
)
43 SndChannelPtr
= SndChannelPtrType('SndChannelPtr', 'SndCh')
45 SndCommand
= OpaqueType('SndCommand', 'SndCmd')
46 SndCommand_ptr
= OpaqueType('SndCommand', 'SndCmd')
47 SndListHandle
= OpaqueByValueType("SndListHandle", "ResObj")
48 SPBPtr
= OpaqueByValueType("SPBPtr", "SPBObj")
51 # NOTE: the following is pretty dangerous. For void pointers we pass buffer addresses
52 # but we have no way to check that the buffer is big enough. This is the same problem
53 # as in C, though (but Pythoneers may not be suspecting this...)
54 void_ptr
= Type("void *", "w")
56 class SndCallBackType(InputOnlyType
):
58 Type
.__init
__(self
, 'PyObject*', 'O')
59 def getargsCheck(self
, name
):
60 Output("if (%s != Py_None && !PyCallable_Check(%s))", name
, name
)
62 Output('PyErr_SetString(PyExc_TypeError, "callback must be callable");')
63 Output("goto %s__error__;", name
)
65 def passInput(self
, name
):
66 return "NewSndCallBackProc(SndCh_UserRoutine)"
67 def cleanup(self
, name
):
68 # XXX This knows it is executing inside the SndNewChannel wrapper
69 Output("if (_res != NULL && %s != Py_None)", name
)
71 Output("SndChannelObject *p = (SndChannelObject *)_res;")
72 Output("p->ob_itself->userInfo = (long)p;")
73 Output("Py_INCREF(%s);", name
)
74 Output("p->ob_callback = %s;", name
)
77 Output(" %s__error__: ;", name
)
80 SndCallBackProcPtr
= SndCallBackType()
81 SndCallBackUPP
= SndCallBackProcPtr
83 SndCompletionProcPtr
= FakeType('(SndCompletionProcPtr)0') # XXX
84 SndCompletionUPP
= SndCompletionProcPtr
86 ##InOutBuf128 = FixedInputOutputBufferType(128)
87 StateBlock
= StructInputOutputBufferType('StateBlock')
89 AudioSelectionPtr
= FakeType('0') # XXX
91 ProcPtr
= FakeType('0') # XXX
92 FilePlayCompletionUPP
= FakeType('0') # XXX
94 SCStatus
= StructOutputBufferType('SCStatus')
95 SMStatus
= StructOutputBufferType('SMStatus')
96 CompressionInfo
= StructOutputBufferType('CompressionInfo')
98 includestuff
= includestuff
+ """
99 #include <OSUtils.h> /* for Set(Current)A5 */
101 /* Create a SndCommand object (an (int, int, int) tuple) */
103 SndCmd_New(SndCommand *pc)
105 return Py_BuildValue("hhl", pc->cmd, pc->param1, pc->param2);
108 /* Convert a SndCommand argument */
110 SndCmd_Convert(PyObject *v, SndCommand *pc)
115 if (PyTuple_Check(v)) {
116 if (PyArg_ParseTuple(v, "h|hl", &pc->cmd, &pc->param1, &pc->param2))
119 return PyArg_ParseTuple(v, "hhs#", &pc->cmd, &pc->param1, &pc->param2, &len);
121 return PyArg_Parse(v, "h", &pc->cmd);
124 static pascal void SndCh_UserRoutine(SndChannelPtr chan, SndCommand *cmd); /* Forward */
125 static pascal void SPB_completion(SPBPtr my_spb); /* Forward */
126 static pascal void SPB_interrupt(SPBPtr my_spb); /* Forward */
130 finalstuff
= finalstuff
+ """
131 /* Routine passed to Py_AddPendingCall -- call the Python callback */
133 SndCh_CallCallBack(arg)
136 SndChannelObject *p = (SndChannelObject *)arg;
139 args = Py_BuildValue("(O(hhl))",
140 p, p->ob_cmd.cmd, p->ob_cmd.param1, p->ob_cmd.param2);
141 res = PyEval_CallObject(p->ob_callback, args);
149 /* Routine passed to NewSndChannel -- schedule a call to SndCh_CallCallBack */
151 SndCh_UserRoutine(SndChannelPtr chan, SndCommand *cmd)
153 SndChannelObject *p = (SndChannelObject *)(chan->userInfo);
154 if (p->ob_callback != NULL) {
155 long A5 = SetA5(p->ob_A5);
157 Py_AddPendingCall(SndCh_CallCallBack, (void *)p);
162 /* SPB callbacks - Schedule callbacks to Python */
164 SPB_CallCallBack(arg)
167 SPBObject *p = (SPBObject *)arg;
171 if ( p->ob_thiscallback == 0 ) return 0;
172 args = Py_BuildValue("(O)", p);
173 res = PyEval_CallObject(p->ob_thiscallback, args);
174 p->ob_thiscallback = 0;
183 SPB_completion(SPBPtr my_spb)
185 SPBObject *p = (SPBObject *)(my_spb->userLong);
187 if (p && p->ob_completion) {
188 long A5 = SetA5(p->ob_A5);
189 p->ob_thiscallback = p->ob_completion; /* Hope we cannot get two at the same time */
190 Py_AddPendingCall(SPB_CallCallBack, (void *)p);
196 SPB_interrupt(SPBPtr my_spb)
198 SPBObject *p = (SPBObject *)(my_spb->userLong);
200 if (p && p->ob_interrupt) {
201 long A5 = SetA5(p->ob_A5);
202 p->ob_thiscallback = p->ob_interrupt; /* Hope we cannot get two at the same time */
203 Py_AddPendingCall(SPB_CallCallBack, (void *)p);
210 # create the module and object definition and link them
212 class SndObjectDefinition(ObjectDefinition
):
214 def outputStructMembers(self
):
215 ObjectDefinition
.outputStructMembers(self
)
216 Output("/* Members used to implement callbacks: */")
217 Output("PyObject *ob_callback;")
218 Output("long ob_A5;");
219 Output("SndCommand ob_cmd;")
221 def outputInitStructMembers(self
):
222 ObjectDefinition
.outputInitStructMembers(self
)
223 Output("it->ob_callback = NULL;")
224 Output("it->ob_A5 = SetCurrentA5();");
226 def outputCleanupStructMembers(self
):
227 ObjectDefinition
.outputCleanupStructMembers(self
)
228 Output("Py_XDECREF(self->ob_callback);")
230 def outputFreeIt(self
, itselfname
):
231 Output("SndDisposeChannel(%s, 1);", itselfname
)
235 class SpbObjectDefinition(ObjectDefinition
):
237 def outputStructMembers(self
):
238 Output("/* Members used to implement callbacks: */")
239 Output("PyObject *ob_completion;")
240 Output("PyObject *ob_interrupt;")
241 Output("PyObject *ob_thiscallback;");
242 Output("long ob_A5;")
243 Output("SPB ob_spb;")
247 Output("%sPyObject *%s_New()", self
.static
, self
.prefix
)
249 Output("%s *it;", self
.objecttype
)
250 self
.outputCheckNewArg()
251 Output("it = PyObject_NEW(%s, &%s);", self
.objecttype
, self
.typename
)
252 Output("if (it == NULL) return NULL;")
253 self
.outputInitStructMembers()
254 Output("return (PyObject *)it;")
257 def outputInitStructMembers(self
):
258 Output("it->ob_completion = NULL;")
259 Output("it->ob_interrupt = NULL;")
260 Output("it->ob_thiscallback = NULL;")
261 Output("it->ob_A5 = SetCurrentA5();")
262 Output("memset((char *)&it->ob_spb, 0, sizeof(it->ob_spb));")
263 Output("it->ob_spb.userLong = (long)it;")
265 def outputCleanupStructMembers(self
):
266 ObjectDefinition
.outputCleanupStructMembers(self
)
267 Output("self->ob_spb.userLong = 0;")
268 Output("self->ob_thiscallback = 0;")
269 Output("Py_XDECREF(self->ob_completion);")
270 Output("Py_XDECREF(self->ob_interrupt);")
272 def outputConvert(self
):
273 Output("%s%s_Convert(v, p_itself)", self
.static
, self
.prefix
)
275 Output("PyObject *v;")
276 Output("%s *p_itself;", self
.itselftype
)
279 self
.outputCheckConvertArg()
280 Output("if (!%s_Check(v))", self
.prefix
)
282 Output('PyErr_SetString(PyExc_TypeError, "%s required");', self
.name
)
285 Output("*p_itself = &((%s *)v)->ob_spb;", self
.objecttype
)
289 def outputSetattr(self
):
291 Output("static int %s_setattr(self, name, value)", self
.prefix
)
293 Output("%s *self;", self
.objecttype
)
294 Output("char *name;")
295 Output("PyObject *value;")
298 self
.outputSetattrBody()
301 def outputSetattrBody(self
):
305 if (strcmp(name, "inRefNum") == 0)
306 rv = PyArg_Parse(value, "l", &self->ob_spb.inRefNum);
307 else if (strcmp(name, "count") == 0)
308 rv = PyArg_Parse(value, "l", &self->ob_spb.count);
309 else if (strcmp(name, "milliseconds") == 0)
310 rv = PyArg_Parse(value, "l", &self->ob_spb.milliseconds);
311 else if (strcmp(name, "buffer") == 0)
312 rv = PyArg_Parse(value, "w#", &self->ob_spb.bufferPtr, &self->ob_spb.bufferLength);
313 else if (strcmp(name, "completionRoutine") == 0) {
314 self->ob_spb.completionRoutine = NewSICompletionProc(SPB_completion);
315 self->ob_completion = value;
318 } else if (strcmp(name, "interruptRoutine") == 0) {
319 self->ob_spb.completionRoutine = NewSIInterruptProc(SPB_interrupt);
320 self->ob_interrupt = value;
327 def outputGetattrHook(self
):
329 if (strcmp(name, "inRefNum") == 0)
330 return Py_BuildValue("l", self->ob_spb.inRefNum);
331 else if (strcmp(name, "count") == 0)
332 return Py_BuildValue("l", self->ob_spb.count);
333 else if (strcmp(name, "milliseconds") == 0)
334 return Py_BuildValue("l", self->ob_spb.milliseconds);
335 else if (strcmp(name, "error") == 0)
336 return Py_BuildValue("h", self->ob_spb.error);""")
340 sndobject
= SndObjectDefinition('SndChannel', 'SndCh', 'SndChannelPtr')
341 spbobject
= SpbObjectDefinition('SPB', 'SPBObj', 'SPBPtr')
342 spbgenerator
= ManualGenerator("SPB", "return SPBObj_New();")
343 module
= MacModule('Snd', 'Snd', includestuff
, finalstuff
, initstuff
)
344 module
.addobject(sndobject
)
345 module
.addobject(spbobject
)
346 module
.add(spbgenerator
)
349 # create lists of functions and object methods
357 execfile('sndgen.py')
360 # add the functions and methods to the module and object, respectively
362 for f
in functions
: module
.add(f
)
363 for f
in sndmethods
: sndobject
.add(f
)
368 SetOutputFileName('Sndmodule.c')