• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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