Question

I'm in the process of creating a Python extension for a small audio library written in C++. When opening an audio stream, a callback function is passed as a parameter (among other parameters of course). A sligthly simplified use case:

AudioThingy *a = new AudioThingy();
a->openStream(..., callbackFunction);
a->startStream();

My Python extension wraps this inside a Python class.

thingy = AudioThingy()
thingy.openStream(..., pythonCallbackFunction)
thingy.startStream()

Now, the extension has a callback as a C function which it passes to the C++ library. For every stream tick the callback receives some information about the stream along with a void pointer to the audio buffer that the callback casts to the correct data type according to the stream format parameter. My intent is of course for this callback function implemented in C to call the user specified Python function with some sort of array as the argument which would then be filled with audio data from, for example, a wav-file opened with Python.

This is what i want to do, in code:

static int __audiothingy_callback(void *buffer, ...) {
  PyGILState_STATE state = PyGILState_Ensure();
  /*
      cast the void pointer to the correct data type (short, int, long, etc.)
      wrap it for Python somehow
  */
  PyEval_CallObject(the_python_function, arglist);
  PyGILState_Release(state);
  //proceed to fill the buffer with stuff passed back from python
  for (...)
    *casted_buffer++ = ????
  Py_DECREF(arglist);
  return 0;
}

TL;DR: How do I pass a mutable array of the correct type from C, in a thread, to a Python function which can then be used to populate the audio buffer? Maybe it can be done in a different way than I have described above? All input is welcome.

Was it helpful?

Solution

I think you could do a couple things. If you're using Python 2.7 you could create a memoryview object using the new buffer protocol:

Then, you'd need to create a memoryview object from the buffer:

Another strategy would be to import the array module, and use this to create an array of the desired type. You use:

Then, construct the array, according to the type needed:

PyObject *array = PyObject_CallFunction(array_type, "c", 'd');   

Even easier, you could just use a bytearray object:

  • PyByteArray_FromStringAndSize to construct a byte array if you can structure things such that you don't need to worry about the size of array elements.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top