/Mac/Modules/snd/sndsupport.py

http://unladen-swallow.googlecode.com/ · Python · 319 lines · 239 code · 54 blank · 26 comment · 2 complexity · 336ef4a7bd7facfd0afe6fb5bf5393e7 MD5 · raw file

  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. from macsupport import *
  6. # define our own function and module generators
  7. class SndMixIn: pass
  8. class SndFunction(SndMixIn, OSErrFunctionGenerator): pass
  9. class SndMethod(SndMixIn, OSErrMethodGenerator): pass
  10. # includestuff etc. are imported from macsupport
  11. includestuff = includestuff + """
  12. #include <Carbon/Carbon.h>
  13. """
  14. initstuff = initstuff + """
  15. """
  16. # define types used for arguments (in addition to standard and macsupport types)
  17. class SndChannelPtrType(OpaqueByValueType):
  18. def declare(self, name):
  19. # Initializing all SndChannelPtr objects to 0 saves
  20. # special-casing NewSndChannel(), where it is formally an
  21. # input-output parameter but we treat it as output-only
  22. # (since Python users are not supposed to allocate memory)
  23. Output("SndChannelPtr %s = 0;", name)
  24. SndChannelPtr = SndChannelPtrType('SndChannelPtr', 'SndCh')
  25. SndCommand = OpaqueType('SndCommand', 'SndCmd')
  26. SndCommand_ptr = OpaqueType('SndCommand', 'SndCmd')
  27. SndListHandle = OpaqueByValueType("SndListHandle", "ResObj")
  28. SPBPtr = OpaqueByValueType("SPBPtr", "SPBObj")
  29. ModalFilterUPP = FakeType("(ModalFilterUPP)0")
  30. #
  31. # NOTE: the following is pretty dangerous. For void pointers we pass buffer addresses
  32. # but we have no way to check that the buffer is big enough. This is the same problem
  33. # as in C, though (but Pythoneers may not be suspecting this...)
  34. void_ptr = Type("void *", "w")
  35. class SndCallBackType(InputOnlyType):
  36. def __init__(self):
  37. Type.__init__(self, 'PyObject*', 'O')
  38. def getargsCheck(self, name):
  39. Output("if (%s != Py_None && !PyCallable_Check(%s))", name, name)
  40. OutLbrace()
  41. Output('PyErr_SetString(PyExc_TypeError, "callback must be callable");')
  42. Output("goto %s__error__;", name)
  43. OutRbrace()
  44. def passInput(self, name):
  45. return "NewSndCallBackUPP(SndCh_UserRoutine)"
  46. def cleanup(self, name):
  47. # XXX This knows it is executing inside the SndNewChannel wrapper
  48. Output("if (_res != NULL && %s != Py_None)", name)
  49. OutLbrace()
  50. Output("SndChannelObject *p = (SndChannelObject *)_res;")
  51. Output("p->ob_itself->userInfo = (long)p;")
  52. Output("Py_INCREF(%s);", name)
  53. Output("p->ob_callback = %s;", name)
  54. OutRbrace()
  55. DedentLevel()
  56. Output(" %s__error__: ;", name)
  57. IndentLevel()
  58. SndCallBackProcPtr = SndCallBackType()
  59. SndCallBackUPP = SndCallBackProcPtr
  60. SndCompletionProcPtr = FakeType('(SndCompletionProcPtr)0') # XXX
  61. SndCompletionUPP = SndCompletionProcPtr
  62. ##InOutBuf128 = FixedInputOutputBufferType(128)
  63. StateBlock = StructInputOutputBufferType('StateBlock')
  64. AudioSelectionPtr = FakeType('0') # XXX
  65. ProcPtr = FakeType('0') # XXX
  66. FilePlayCompletionUPP = FakeType('0') # XXX
  67. SCStatus = StructOutputBufferType('SCStatus')
  68. SMStatus = StructOutputBufferType('SMStatus')
  69. CompressionInfo = StructOutputBufferType('CompressionInfo')
  70. includestuff = includestuff + """
  71. /* Convert a SndCommand argument */
  72. static int
  73. SndCmd_Convert(PyObject *v, SndCommand *pc)
  74. {
  75. int len;
  76. pc->param1 = 0;
  77. pc->param2 = 0;
  78. if (PyTuple_Check(v)) {
  79. if (PyArg_ParseTuple(v, "h|hl", &pc->cmd, &pc->param1, &pc->param2))
  80. return 1;
  81. PyErr_Clear();
  82. return PyArg_ParseTuple(v, "Hhs#", &pc->cmd, &pc->param1, &pc->param2, &len);
  83. }
  84. return PyArg_Parse(v, "H", &pc->cmd);
  85. }
  86. static pascal void SndCh_UserRoutine(SndChannelPtr chan, SndCommand *cmd); /* Forward */
  87. static pascal void SPB_completion(SPBPtr my_spb); /* Forward */
  88. """
  89. finalstuff = finalstuff + """
  90. /* Routine passed to Py_AddPendingCall -- call the Python callback */
  91. static int
  92. SndCh_CallCallBack(void *arg)
  93. {
  94. SndChannelObject *p = (SndChannelObject *)arg;
  95. PyObject *args;
  96. PyObject *res;
  97. args = Py_BuildValue("(O(hhl))",
  98. p, p->ob_cmd.cmd, p->ob_cmd.param1, p->ob_cmd.param2);
  99. res = PyEval_CallObject(p->ob_callback, args);
  100. Py_DECREF(args);
  101. if (res == NULL)
  102. return -1;
  103. Py_DECREF(res);
  104. return 0;
  105. }
  106. /* Routine passed to NewSndChannel -- schedule a call to SndCh_CallCallBack */
  107. static pascal void
  108. SndCh_UserRoutine(SndChannelPtr chan, SndCommand *cmd)
  109. {
  110. SndChannelObject *p = (SndChannelObject *)(chan->userInfo);
  111. if (p->ob_callback != NULL) {
  112. long A5 = SetA5(p->ob_A5);
  113. p->ob_cmd = *cmd;
  114. Py_AddPendingCall(SndCh_CallCallBack, (void *)p);
  115. SetA5(A5);
  116. }
  117. }
  118. /* SPB callbacks - Schedule callbacks to Python */
  119. static int
  120. SPB_CallCallBack(void *arg)
  121. {
  122. SPBObject *p = (SPBObject *)arg;
  123. PyObject *args;
  124. PyObject *res;
  125. if ( p->ob_thiscallback == 0 ) return 0;
  126. args = Py_BuildValue("(O)", p);
  127. res = PyEval_CallObject(p->ob_thiscallback, args);
  128. p->ob_thiscallback = 0;
  129. Py_DECREF(args);
  130. if (res == NULL)
  131. return -1;
  132. Py_DECREF(res);
  133. return 0;
  134. }
  135. static pascal void
  136. SPB_completion(SPBPtr my_spb)
  137. {
  138. SPBObject *p = (SPBObject *)(my_spb->userLong);
  139. if (p && p->ob_completion) {
  140. long A5 = SetA5(p->ob_A5);
  141. p->ob_thiscallback = p->ob_completion; /* Hope we cannot get two at the same time */
  142. Py_AddPendingCall(SPB_CallCallBack, (void *)p);
  143. SetA5(A5);
  144. }
  145. }
  146. """
  147. # create the module and object definition and link them
  148. class SndObjectDefinition(PEP252Mixin, ObjectDefinition):
  149. def outputStructMembers(self):
  150. ObjectDefinition.outputStructMembers(self)
  151. Output("/* Members used to implement callbacks: */")
  152. Output("PyObject *ob_callback;")
  153. Output("long ob_A5;");
  154. Output("SndCommand ob_cmd;")
  155. def outputInitStructMembers(self):
  156. ObjectDefinition.outputInitStructMembers(self)
  157. Output("it->ob_callback = NULL;")
  158. Output("it->ob_A5 = SetCurrentA5();");
  159. def outputCleanupStructMembers(self):
  160. ObjectDefinition.outputCleanupStructMembers(self)
  161. Output("Py_XDECREF(self->ob_callback);")
  162. def outputFreeIt(self, itselfname):
  163. Output("SndDisposeChannel(%s, 1);", itselfname)
  164. def outputConvert(self):
  165. pass # Not needed
  166. #
  167. class SpbObjectDefinition(PEP252Mixin, ObjectDefinition):
  168. getsetlist = [
  169. (
  170. 'inRefNum',
  171. 'return Py_BuildValue("l", self->ob_spb.inRefNum);',
  172. 'return -1 + PyArg_Parse(v, "l", &self->ob_spb.inRefNum);',
  173. None,
  174. ), (
  175. 'count',
  176. 'return Py_BuildValue("l", self->ob_spb.count);',
  177. 'return -1 + PyArg_Parse(v, "l", &self->ob_spb.count);',
  178. None
  179. ), (
  180. 'milliseconds',
  181. 'return Py_BuildValue("l", self->ob_spb.milliseconds);',
  182. 'return -1 + PyArg_Parse(v, "l", &self->ob_spb.milliseconds);',
  183. None,
  184. ), (
  185. 'error',
  186. 'return Py_BuildValue("h", self->ob_spb.error);',
  187. None,
  188. None
  189. ), (
  190. 'completionRoutine',
  191. None,
  192. """self->ob_spb.completionRoutine = NewSICompletionUPP(SPB_completion);
  193. self->ob_completion = v;
  194. Py_INCREF(v);
  195. return 0;""",
  196. None,
  197. )]
  198. def outputStructMembers(self):
  199. Output("/* Members used to implement callbacks: */")
  200. Output("PyObject *ob_completion;")
  201. Output("PyObject *ob_interrupt;")
  202. Output("PyObject *ob_thiscallback;");
  203. Output("long ob_A5;")
  204. Output("SPB ob_spb;")
  205. def outputNew(self):
  206. Output()
  207. Output("%sPyObject *%s_New(void)", self.static, self.prefix)
  208. OutLbrace()
  209. Output("%s *it;", self.objecttype)
  210. self.outputCheckNewArg()
  211. Output("it = PyObject_NEW(%s, &%s);", self.objecttype, self.typename)
  212. Output("if (it == NULL) return NULL;")
  213. self.outputInitStructMembers()
  214. Output("return (PyObject *)it;")
  215. OutRbrace()
  216. def outputInitStructMembers(self):
  217. Output("it->ob_completion = NULL;")
  218. Output("it->ob_interrupt = NULL;")
  219. Output("it->ob_thiscallback = NULL;")
  220. Output("it->ob_A5 = SetCurrentA5();")
  221. Output("memset((char *)&it->ob_spb, 0, sizeof(it->ob_spb));")
  222. Output("it->ob_spb.userLong = (long)it;")
  223. def outputCleanupStructMembers(self):
  224. ObjectDefinition.outputCleanupStructMembers(self)
  225. Output("self->ob_spb.userLong = 0;")
  226. Output("self->ob_thiscallback = 0;")
  227. Output("Py_XDECREF(self->ob_completion);")
  228. Output("Py_XDECREF(self->ob_interrupt);")
  229. def outputConvert(self):
  230. Output("%sint %s_Convert(PyObject *v, %s *p_itself)", self.static, self.prefix, self.itselftype)
  231. OutLbrace()
  232. self.outputCheckConvertArg()
  233. Output("if (!%s_Check(v))", self.prefix)
  234. OutLbrace()
  235. Output('PyErr_SetString(PyExc_TypeError, "%s required");', self.name)
  236. Output("return 0;")
  237. OutRbrace()
  238. Output("*p_itself = &((%s *)v)->ob_spb;", self.objecttype)
  239. Output("return 1;")
  240. OutRbrace()
  241. sndobject = SndObjectDefinition('SndChannel', 'SndCh', 'SndChannelPtr')
  242. spbobject = SpbObjectDefinition('SPB', 'SPBObj', 'SPBPtr')
  243. spbgenerator = ManualGenerator("SPB", "_res = SPBObj_New(); return _res;")
  244. module = MacModule('_Snd', 'Snd', includestuff, finalstuff, initstuff)
  245. module.addobject(sndobject)
  246. module.addobject(spbobject)
  247. module.add(spbgenerator)
  248. # create lists of functions and object methods
  249. functions = []
  250. sndmethods = []
  251. # populate the lists
  252. execfile('sndgen.py')
  253. # add the functions and methods to the module and object, respectively
  254. for f in functions: module.add(f)
  255. for f in sndmethods: sndobject.add(f)
  256. # generate output
  257. SetOutputFileName('_Sndmodule.c')
  258. module.generate()