Python synthesizer stuff
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

284 řádky
7.2KB

  1. #include <Python.h>
  2. #include <SDL/SDL.h>
  3. #include <numpy/arrayobject.h>
  4. /* SDL error handling */
  5. PyObject *SDLError;
  6. typedef struct {
  7. PyObject_HEAD
  8. int
  9. samplerate,
  10. channels;
  11. int active;
  12. PyObject *callback;
  13. } PyYSynthContext;
  14. void PyYSynthContext_Dealloc(PyYSynthContext *self)
  15. {
  16. puts("_ysynth: Dealloc context");
  17. if (self->active) {
  18. SDL_CloseAudio();
  19. self->active = 0;
  20. }
  21. Py_XDECREF(self->callback);
  22. return;
  23. }
  24. PyTypeObject PyYSynthContext_Type;
  25. PyTypeObject PyYSynthContext_Type = {
  26. PyVarObject_HEAD_INIT(NULL, 0)
  27. "_ysynth.ysynth context", /*tp_name*/
  28. sizeof(PyYSynthContext), /*tp_basicsize*/
  29. 0, /*tp_itemsize*/
  30. /* methods */
  31. (destructor)PyYSynthContext_Dealloc, /*tp_dealloc*/
  32. 0, /*tp_print*/
  33. 0, /*tp_getattr*/
  34. 0, /*tp_setattr*/
  35. 0, /*tp_compare*/
  36. 0, /*tp_repr*/
  37. 0, /*tp_as_number*/
  38. 0, /*tp_as_sequence*/
  39. 0, /*tp_as_mapping*/
  40. 0, /*tp_hash*/
  41. };
  42. /* SDL Audio callback */
  43. void _sdl_audio_callback(void *user, Uint8 *stream, int len)
  44. {
  45. PyYSynthContext *ctx = (PyYSynthContext*)user;
  46. PyObject *r, *args;
  47. NPY_AO *channels;
  48. PyGILState_STATE gstate;
  49. int local_len = len / sizeof(Sint16) / 2;
  50. Sint16 *local_stream = (Sint16*)stream;;
  51. npy_int dims[2] = {local_len, 2};
  52. /* This function is called from SDL's own thread, so we need to
  53. * register it with the Python interpreter before calling any
  54. * Python functions.
  55. */
  56. gstate = PyGILState_Ensure();
  57. /* Setup NumPy array for use within the Python synthesizer */
  58. channels = PyArray_New(&PyArray_Type, 2, dims, NPY_INT16, NULL, NULL, 2, 0, NULL);
  59. if (channels)
  60. args = Py_BuildValue("(O)", channels);
  61. /* Finally execute the callback */
  62. if (args)
  63. r = PyObject_CallObject(ctx->callback, (PyObject*)args);
  64. /* Print stacktrace if necessary */
  65. if (!r) {
  66. if (PyErr_Occurred())
  67. PyErr_Print();
  68. } else {
  69. /* Copy array data to local_stream */
  70. memcpy(local_stream, channels->data, len);
  71. /* Free the call's return value, probably Py_None */
  72. Py_DECREF(r);
  73. }
  74. /* Free arguments */
  75. Py_XDECREF(args);
  76. /* Free the channels */
  77. Py_XDECREF(channels);
  78. /* And leave the GIL */
  79. PyGILState_Release(gstate);
  80. return;
  81. }
  82. PyDoc_STRVAR(hello_doc, "Print hello message from Python module");
  83. /* Output hello message */
  84. static PyObject *pymod_hello(PyObject *self, PyObject *args)
  85. {
  86. PyObject *r = NULL;;
  87. if (PyArg_ParseTuple(args, "")) {
  88. printf("Hello from Python module\n");
  89. Py_INCREF(Py_None);
  90. r = Py_None;
  91. }
  92. return r;
  93. }
  94. PyDoc_STRVAR(_ysynth_init_doc, "Initialise SDL audio and return context");
  95. /* Initialise synthesizer */
  96. static PyObject *_ysynth_init(PyObject *self, PyObject *args)
  97. {
  98. PyObject *r = NULL;
  99. PyYSynthContext *ctx;
  100. int
  101. samplerate,
  102. channels;
  103. SDL_AudioSpec fmt, fmt_obtained;
  104. if (PyArg_ParseTuple(args, "ii;samplerate, channels", &samplerate, &channels)) {
  105. ctx = PyObject_NEW(PyYSynthContext, &PyYSynthContext_Type);
  106. r = (PyObject*)ctx;
  107. ctx->callback = NULL;
  108. /* Setup SDL Audio device */
  109. fmt.freq = samplerate;
  110. fmt.format = AUDIO_S16;
  111. fmt.channels = channels;
  112. fmt.samples = 512;
  113. fmt.callback = _sdl_audio_callback;
  114. fmt.userdata = r;
  115. /* Handle SDL error */
  116. if (SDL_OpenAudio(&fmt, &fmt_obtained) < 0) {
  117. PyErr_SetString(SDLError, SDL_GetError());
  118. Py_DECREF(r);
  119. return NULL;
  120. }
  121. SDL_PauseAudio(0);
  122. ctx->samplerate = fmt_obtained.freq;
  123. ctx->channels = fmt_obtained.channels;
  124. ctx->active = 1;
  125. }
  126. return r;
  127. }
  128. PyDoc_STRVAR(_ysynth_shutdown_doc, "Shutdown SDL audio device");
  129. /* Shutdown SDL audio */
  130. static PyObject *_ysynth_shutdown(PyObject *self, PyObject *args)
  131. {
  132. PyObject *r = NULL;
  133. PyYSynthContext *ctx;
  134. if (!PyArg_ParseTuple(args, "O!", &PyYSynthContext_Type, (PyObject**)&ctx))
  135. {
  136. ctx->active = 0;
  137. SDL_CloseAudio();
  138. Py_XDECREF(ctx->callback);
  139. r = Py_None;
  140. Py_INCREF(r);
  141. }
  142. return r;
  143. }
  144. PyDoc_STRVAR(_ysynth_set_callback_doc, "Set audio callback");
  145. /* Set Python audio callback */
  146. static PyObject *_ysynth_set_callback(PyObject *self, PyObject *args)
  147. {
  148. PyObject *r = NULL;
  149. PyYSynthContext *ctx;
  150. PyObject *callback;
  151. if (PyArg_ParseTuple(args, "O!O", &PyYSynthContext_Type, (PyObject**)&ctx,
  152. &callback)) {
  153. /* We don't have to lock SDL audio because Python's GIL will
  154. * have locked out the callback for us
  155. */
  156. Py_XDECREF(ctx->callback);
  157. ctx->callback = callback;
  158. Py_INCREF(callback);
  159. r = Py_None;
  160. Py_INCREF(r);
  161. }
  162. return r;
  163. }
  164. PyDoc_STRVAR(_ysynth_get_callback_doc, "Get audio callback");
  165. /* Get Python audio callback */
  166. static PyObject *_ysynth_get_callback(PyObject *self, PyObject *args)
  167. {
  168. PyObject *r = NULL;
  169. PyYSynthContext *ctx;
  170. if (PyArg_ParseTuple(args, "O!", PyYSynthContext_Type, (PyObject**)&ctx)) {
  171. if (ctx->callback) {
  172. Py_INCREF(ctx->callback);
  173. r = ctx->callback;
  174. } else {
  175. r = Py_None;
  176. Py_INCREF(r);
  177. }
  178. }
  179. return r;
  180. }
  181. /* Exported methods */
  182. static PyMethodDef pymod_methods[] = {
  183. {"_ysynth_init", (PyCFunction)_ysynth_init,
  184. METH_VARARGS, _ysynth_init_doc},
  185. {"_ysynth_shutdown", (PyCFunction)_ysynth_shutdown,
  186. METH_VARARGS, _ysynth_shutdown_doc},
  187. {"_ysynth_set_callback", (PyCFunction)_ysynth_set_callback,
  188. METH_VARARGS, _ysynth_set_callback_doc},
  189. {"_ysynth_get_callback", (PyCFunction)_ysynth_get_callback,
  190. METH_VARARGS, _ysynth_get_callback_doc},
  191. {"hello", (PyCFunction)pymod_hello,
  192. METH_VARARGS, hello_doc},
  193. {NULL, NULL} /* sentinel */
  194. };
  195. /* Shutdown SDL */
  196. void exitpymod(void)
  197. {
  198. SDL_Quit();
  199. }
  200. PyDoc_STRVAR(module_doc, "Simple test module");
  201. /* Module initialisation, called by Python on import */
  202. PyMODINIT_FUNC
  203. initpymod(void)
  204. {
  205. PyObject *m;
  206. /* Setup SDL audio without signal handlers */
  207. if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE) < 0)
  208. return;
  209. /* Register exit handler
  210. * XXX: Later on try to use Python's atexit module?
  211. */
  212. atexit(exitpymod);
  213. puts("Hoi, module pymod loaded.");
  214. m = Py_InitModule3("pymod", pymod_methods, module_doc);
  215. if (m == NULL)
  216. return;
  217. /* Setup exceptions */
  218. SDLError = PyErr_NewException("_ysynth.SDLError", NULL, NULL);
  219. Py_INCREF(SDLError);
  220. PyModule_AddObject(m, "SDLError", SDLError);
  221. /* Our module requires the GIL to be available */
  222. if (!PyEval_ThreadsInitialized()) {
  223. puts("Initialising multithreading for Python");
  224. PyEval_InitThreads();
  225. }
  226. import_array();
  227. return;
  228. }