|
|
|
@@ -1,5 +1,6 @@ |
|
|
|
#include <python2.7/Python.h> |
|
|
|
#include <Python.h> |
|
|
|
#include <SDL/SDL.h> |
|
|
|
#include <numpy/arrayobject.h> |
|
|
|
|
|
|
|
/* SDL error handling */ |
|
|
|
PyObject *SDLError; |
|
|
|
@@ -45,24 +46,16 @@ PyTypeObject PyYSynthContext_Type = { |
|
|
|
0, /*tp_hash*/ |
|
|
|
}; |
|
|
|
|
|
|
|
PyDoc_STRVAR(hello_doc, "Print hello message from Python module"); |
|
|
|
|
|
|
|
/* SDL Audio callback */ |
|
|
|
void _sdl_audio_callback(void *user, Uint8 *stream, int len) |
|
|
|
{ |
|
|
|
PyYSynthContext *ctx = (PyYSynthContext*)user; |
|
|
|
PyObject |
|
|
|
*channels, |
|
|
|
*chan, |
|
|
|
*py_sample, |
|
|
|
*left, |
|
|
|
*right, |
|
|
|
*r = NULL; |
|
|
|
PyObject *r, *args; |
|
|
|
NPY_AO *channels; |
|
|
|
PyGILState_STATE gstate; |
|
|
|
int i, j; |
|
|
|
int sample; |
|
|
|
int local_len = len / sizeof(Sint16) / 2; |
|
|
|
Sint16 *local_stream = (Sint16*)stream;; |
|
|
|
npy_int dims[2] = {local_len, 2}; |
|
|
|
|
|
|
|
/* This function is called from SDL's own thread, so we need to |
|
|
|
* register it with the Python interpreter before calling any |
|
|
|
@@ -70,82 +63,31 @@ void _sdl_audio_callback(void *user, Uint8 *stream, int len) |
|
|
|
*/ |
|
|
|
gstate = PyGILState_Ensure(); |
|
|
|
|
|
|
|
do { |
|
|
|
if (ctx->callback) { |
|
|
|
/* Build list of doubles */ |
|
|
|
channels = PyTuple_New(ctx->channels); |
|
|
|
if (!channels) |
|
|
|
break; |
|
|
|
|
|
|
|
/* Fill tuple with channel lists */ |
|
|
|
for (i = 0; i < ctx->channels; i++) { |
|
|
|
/* Allocate new channel list */ |
|
|
|
chan = PyList_New(local_len); |
|
|
|
if (!chan) { |
|
|
|
Py_DECREF(channels); |
|
|
|
break; |
|
|
|
} |
|
|
|
PyTuple_SET_ITEM(channels, i, chan); |
|
|
|
|
|
|
|
/* Fill channel with 0.0 floats */ |
|
|
|
for (j = 0; j < local_len; j++) { |
|
|
|
py_sample = PyFloat_FromDouble(0.0); |
|
|
|
if (!py_sample) |
|
|
|
break; |
|
|
|
PyList_SET_ITEM(chan, j, py_sample); |
|
|
|
} |
|
|
|
if (j != local_len) |
|
|
|
break; |
|
|
|
} |
|
|
|
if (i != ctx->channels) |
|
|
|
break; |
|
|
|
|
|
|
|
/* Finally execute the callback */ |
|
|
|
r = PyObject_CallObject(ctx->callback, channels); |
|
|
|
} |
|
|
|
} while (0); |
|
|
|
/* Setup NumPy array for use within the Python synthesizer */ |
|
|
|
channels = PyArray_New(&PyArray_Type, 2, dims, NPY_INT16, NULL, NULL, 2, 0, NULL); |
|
|
|
|
|
|
|
if (channels) |
|
|
|
args = Py_BuildValue("(O)", channels); |
|
|
|
|
|
|
|
/* Finally execute the callback */ |
|
|
|
if (args) |
|
|
|
r = PyObject_CallObject(ctx->callback, (PyObject*)args); |
|
|
|
|
|
|
|
/* Print stacktrace if necessary */ |
|
|
|
if (!r) { |
|
|
|
if (PyErr_Occurred()) |
|
|
|
PyErr_Print(); |
|
|
|
} else { |
|
|
|
left = PyTuple_GetItem(channels, 0); |
|
|
|
right = PyTuple_GetItem(channels, 1); |
|
|
|
|
|
|
|
/* Make sure we won't exceed list length.. the callee shouldn't change |
|
|
|
* the list length though */ |
|
|
|
local_len = local_len > PyList_Size(left) ? |
|
|
|
PyList_Size(left) : local_len; |
|
|
|
local_len = local_len > PyList_Size(right) ? |
|
|
|
PyList_Size(right) : local_len; |
|
|
|
|
|
|
|
/* Try to convert both lists to audio stream */ |
|
|
|
for (i = 0; i < local_len; i++) { |
|
|
|
|
|
|
|
/* With the courtesy of microsynth, float to sample conversion ;-) */ |
|
|
|
sample = (int)(32767.5 * PyFloat_AsDouble(PyList_GetItem(left, i))); |
|
|
|
|
|
|
|
/* Clip samples */ |
|
|
|
if (sample > 32767) sample = 32767; |
|
|
|
if (sample < -32768) sample = -32768; |
|
|
|
|
|
|
|
local_stream[i * 2] = (Sint16)sample; |
|
|
|
|
|
|
|
sample = (int)(32767.5 * PyFloat_AsDouble(PyList_GetItem(right, |
|
|
|
i))); |
|
|
|
|
|
|
|
/* Clip samples */ |
|
|
|
if (sample > 32767) sample = 32767; |
|
|
|
if (sample < -32768) sample = -32768; |
|
|
|
|
|
|
|
local_stream[i * 2 + 1] = (Sint16)sample; |
|
|
|
} |
|
|
|
/* Copy array data to local_stream */ |
|
|
|
memcpy(local_stream, channels->data, len); |
|
|
|
|
|
|
|
/* Free the call's return value, probably Py_None */ |
|
|
|
Py_DECREF(r); |
|
|
|
} |
|
|
|
|
|
|
|
/* Free arguments */ |
|
|
|
Py_XDECREF(args); |
|
|
|
|
|
|
|
/* Free the channels */ |
|
|
|
Py_XDECREF(channels); |
|
|
|
|
|
|
|
@@ -154,6 +96,8 @@ void _sdl_audio_callback(void *user, Uint8 *stream, int len) |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
PyDoc_STRVAR(hello_doc, "Print hello message from Python module"); |
|
|
|
|
|
|
|
/* Output hello message */ |
|
|
|
static PyObject *pymod_hello(PyObject *self, PyObject *args) |
|
|
|
{ |
|
|
|
@@ -293,14 +237,14 @@ static PyMethodDef pymod_methods[] = { |
|
|
|
{NULL, NULL} /* sentinel */ |
|
|
|
}; |
|
|
|
|
|
|
|
PyDoc_STRVAR(module_doc, "Simple test module"); |
|
|
|
|
|
|
|
/* Shutdown SDL */ |
|
|
|
void exitpymod(void) |
|
|
|
{ |
|
|
|
SDL_Quit(); |
|
|
|
} |
|
|
|
|
|
|
|
PyDoc_STRVAR(module_doc, "Simple test module"); |
|
|
|
|
|
|
|
/* Module initialisation, called by Python on import */ |
|
|
|
PyMODINIT_FUNC |
|
|
|
initpymod(void) |
|
|
|
@@ -332,6 +276,8 @@ initpymod(void) |
|
|
|
PyEval_InitThreads(); |
|
|
|
} |
|
|
|
|
|
|
|
import_array(); |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
|