|
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() |