Python synthesizer stuff
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

338 satır
8.9KB

  1. #include <python2.7/Python.h>
  2. #include <SDL/SDL.h>
  3. /* SDL error handling */
  4. PyObject *SDLError;
  5. typedef struct {
  6. PyObject_HEAD
  7. int
  8. samplerate,
  9. channels;
  10. int active;
  11. PyObject *callback;
  12. } PyYSynthContext;
  13. void PyYSynthContext_Dealloc(PyYSynthContext *self)
  14. {
  15. puts("_ysynth: Dealloc context");
  16. if (self->active) {
  17. SDL_CloseAudio();
  18. self->active = 0;
  19. }
  20. Py_XDECREF(self->callback);
  21. return;
  22. }
  23. PyTypeObject PyYSynthContext_Type;
  24. PyTypeObject PyYSynthContext_Type = {
  25. PyVarObject_HEAD_INIT(NULL, 0)
  26. "_ysynth.ysynth context", /*tp_name*/
  27. sizeof(PyYSynthContext), /*tp_basicsize*/
  28. 0, /*tp_itemsize*/
  29. /* methods */
  30. (destructor)PyYSynthContext_Dealloc, /*tp_dealloc*/
  31. 0, /*tp_print*/
  32. 0, /*tp_getattr*/
  33. 0, /*tp_setattr*/
  34. 0, /*tp_compare*/
  35. 0, /*tp_repr*/
  36. 0, /*tp_as_number*/
  37. 0, /*tp_as_sequence*/
  38. 0, /*tp_as_mapping*/
  39. 0, /*tp_hash*/
  40. };
  41. PyDoc_STRVAR(hello_doc, "Print hello message from Python module");
  42. /* SDL Audio callback */
  43. void _sdl_audio_callback(void *user, Uint8 *stream, int len)
  44. {
  45. PyYSynthContext *ctx = (PyYSynthContext*)user;
  46. PyObject
  47. *channels,
  48. *chan,
  49. *py_sample,
  50. *left,
  51. *right,
  52. *r = NULL;
  53. PyGILState_STATE gstate;
  54. int i, j;
  55. int sample;
  56. int local_len = len / sizeof(Sint16) / 2;
  57. Sint16 *local_stream = (Sint16*)stream;;
  58. /* This function is called from SDL's own thread, so we need to
  59. * register it with the Python interpreter before calling any
  60. * Python functions.
  61. */
  62. gstate = PyGILState_Ensure();
  63. do {
  64. if (ctx->callback) {
  65. /* Build list of doubles */
  66. channels = PyTuple_New(ctx->channels);
  67. if (!channels)
  68. break;
  69. /* Fill tuple with channel lists */
  70. for (i = 0; i < ctx->channels; i++) {
  71. /* Allocate new channel list */
  72. chan = PyList_New(local_len);
  73. if (!chan) {
  74. Py_DECREF(channels);
  75. break;
  76. }
  77. PyTuple_SET_ITEM(channels, i, chan);
  78. /* Fill channel with 0.0 floats */
  79. for (j = 0; j < local_len; j++) {
  80. py_sample = PyFloat_FromDouble(0.0);
  81. if (!py_sample)
  82. break;
  83. PyList_SET_ITEM(chan, j, py_sample);
  84. }
  85. if (j != local_len)
  86. break;
  87. }
  88. if (i != ctx->channels)
  89. break;
  90. /* Finally execute the callback */
  91. r = PyObject_CallObject(ctx->callback, channels);
  92. }
  93. } while (0);
  94. /* Print stacktrace if necessary */
  95. if (!r) {
  96. if (PyErr_Occurred())
  97. PyErr_Print();
  98. } else {
  99. left = PyTuple_GetItem(channels, 0);
  100. right = PyTuple_GetItem(channels, 1);
  101. /* Make sure we won't exceed list length.. the callee shouldn't change
  102. * the list length though */
  103. local_len = local_len > PyList_Size(left) ?
  104. PyList_Size(left) : local_len;
  105. local_len = local_len > PyList_Size(right) ?
  106. PyList_Size(right) : local_len;
  107. /* Try to convert both lists to audio stream */
  108. for (i = 0; i < local_len; i++) {
  109. /* With the courtesy of microsynth, float to sample conversion ;-) */
  110. sample = (int)(32767.5 * PyFloat_AsDouble(PyList_GetItem(left, i)));
  111. /* Clip samples */
  112. if (sample > 32767) sample = 32767;
  113. if (sample < -32768) sample = -32768;
  114. local_stream[i * 2] = (Sint16)sample;
  115. sample = (int)(32767.5 * PyFloat_AsDouble(PyList_GetItem(right,
  116. i)));
  117. /* Clip samples */
  118. if (sample > 32767) sample = 32767;
  119. if (sample < -32768) sample = -32768;
  120. local_stream[i * 2 + 1] = (Sint16)sample;
  121. }
  122. /* Free the call's return value, probably Py_None */
  123. Py_DECREF(r);
  124. }
  125. /* Free the channels */
  126. Py_XDECREF(channels);
  127. /* And leave the GIL */
  128. PyGILState_Release(gstate);
  129. return;
  130. }
  131. /* Output hello message */
  132. static PyObject *pymod_hello(PyObject *self, PyObject *args)
  133. {
  134. PyObject *r = NULL;;
  135. if (PyArg_ParseTuple(args, "")) {
  136. printf("Hello from Python module\n");
  137. Py_INCREF(Py_None);
  138. r = Py_None;
  139. }
  140. return r;
  141. }
  142. PyDoc_STRVAR(_ysynth_init_doc, "Initialise SDL audio and return context");
  143. /* Initialise synthesizer */
  144. static PyObject *_ysynth_init(PyObject *self, PyObject *args)
  145. {
  146. PyObject *r = NULL;
  147. PyYSynthContext *ctx;
  148. int
  149. samplerate,
  150. channels;
  151. SDL_AudioSpec fmt, fmt_obtained;
  152. if (PyArg_ParseTuple(args, "ii;samplerate, channels", &samplerate, &channels)) {
  153. ctx = PyObject_NEW(PyYSynthContext, &PyYSynthContext_Type);
  154. r = (PyObject*)ctx;
  155. ctx->callback = NULL;
  156. /* Setup SDL Audio device */
  157. fmt.freq = samplerate;
  158. fmt.format = AUDIO_S16;
  159. fmt.channels = channels;
  160. fmt.samples = 512;
  161. fmt.callback = _sdl_audio_callback;
  162. fmt.userdata = r;
  163. /* Handle SDL error */
  164. if (SDL_OpenAudio(&fmt, &fmt_obtained) < 0) {
  165. PyErr_SetString(SDLError, SDL_GetError());
  166. Py_DECREF(r);
  167. return NULL;
  168. }
  169. SDL_PauseAudio(0);
  170. ctx->samplerate = fmt_obtained.freq;
  171. ctx->channels = fmt_obtained.channels;
  172. ctx->active = 1;
  173. }
  174. return r;
  175. }
  176. PyDoc_STRVAR(_ysynth_shutdown_doc, "Shutdown SDL audio device");
  177. /* Shutdown SDL audio */
  178. static PyObject *_ysynth_shutdown(PyObject *self, PyObject *args)
  179. {
  180. PyObject *r = NULL;
  181. PyYSynthContext *ctx;
  182. if (!PyArg_ParseTuple(args, "O!", &PyYSynthContext_Type, (PyObject**)&ctx))
  183. {
  184. ctx->active = 0;
  185. SDL_CloseAudio();
  186. Py_XDECREF(ctx->callback);
  187. r = Py_None;
  188. Py_INCREF(r);
  189. }
  190. return r;
  191. }
  192. PyDoc_STRVAR(_ysynth_set_callback_doc, "Set audio callback");
  193. /* Set Python audio callback */
  194. static PyObject *_ysynth_set_callback(PyObject *self, PyObject *args)
  195. {
  196. PyObject *r = NULL;
  197. PyYSynthContext *ctx;
  198. PyObject *callback;
  199. if (PyArg_ParseTuple(args, "O!O", &PyYSynthContext_Type, (PyObject**)&ctx,
  200. &callback)) {
  201. /* We don't have to lock SDL audio because Python's GIL will
  202. * have locked out the callback for us
  203. */
  204. Py_XDECREF(ctx->callback);
  205. ctx->callback = callback;
  206. Py_INCREF(callback);
  207. r = Py_None;
  208. Py_INCREF(r);
  209. }
  210. return r;
  211. }
  212. PyDoc_STRVAR(_ysynth_get_callback_doc, "Get audio callback");
  213. /* Get Python audio callback */
  214. static PyObject *_ysynth_get_callback(PyObject *self, PyObject *args)
  215. {
  216. PyObject *r = NULL;
  217. PyYSynthContext *ctx;
  218. if (PyArg_ParseTuple(args, "O!", PyYSynthContext_Type, (PyObject**)&ctx)) {
  219. if (ctx->callback) {
  220. Py_INCREF(ctx->callback);
  221. r = ctx->callback;
  222. } else {
  223. r = Py_None;
  224. Py_INCREF(r);
  225. }
  226. }
  227. return r;
  228. }
  229. /* Exported methods */
  230. static PyMethodDef pymod_methods[] = {
  231. {"_ysynth_init", (PyCFunction)_ysynth_init,
  232. METH_VARARGS, _ysynth_init_doc},
  233. {"_ysynth_shutdown", (PyCFunction)_ysynth_shutdown,
  234. METH_VARARGS, _ysynth_shutdown_doc},
  235. {"_ysynth_set_callback", (PyCFunction)_ysynth_set_callback,
  236. METH_VARARGS, _ysynth_set_callback_doc},
  237. {"_ysynth_get_callback", (PyCFunction)_ysynth_get_callback,
  238. METH_VARARGS, _ysynth_get_callback_doc},
  239. {"hello", (PyCFunction)pymod_hello,
  240. METH_VARARGS, hello_doc},
  241. {NULL, NULL} /* sentinel */
  242. };
  243. PyDoc_STRVAR(module_doc, "Simple test module");
  244. /* Shutdown SDL */
  245. void exitpymod(void)
  246. {
  247. SDL_Quit();
  248. }
  249. /* Module initialisation, called by Python on import */
  250. PyMODINIT_FUNC
  251. initpymod(void)
  252. {
  253. PyObject *m;
  254. /* Setup SDL audio without signal handlers */
  255. if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE) < 0)
  256. return;
  257. /* Register exit handler
  258. * XXX: Later on try to use Python's atexit module?
  259. */
  260. atexit(exitpymod);
  261. puts("Hoi, module pymod loaded.");
  262. m = Py_InitModule3("pymod", pymod_methods, module_doc);
  263. if (m == NULL)
  264. return;
  265. /* Setup exceptions */
  266. SDLError = PyErr_NewException("_ysynth.SDLError", NULL, NULL);
  267. Py_INCREF(SDLError);
  268. PyModule_AddObject(m, "SDLError", SDLError);
  269. /* Our module requires the GIL to be available */
  270. if (!PyEval_ThreadsInitialized()) {
  271. puts("Initialising multithreading for Python");
  272. PyEval_InitThreads();
  273. }
  274. return;
  275. }