Вызов функции Python из потока C с изменяемым массивом C

Я нахожусь в процессе создания расширения Python для небольшой звуковой библиотеки, написанной на C++. При открытии аудиопотока в качестве параметра передается функция обратного вызова (конечно, среди других параметров). Несколько упрощенный вариант использования:

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

Мое расширение Python оборачивает это внутри класса Python.

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

Теперь расширение имеет функцию обратного вызова в виде функции C, которую оно передает в библиотеку C++. Для каждого тика потока обратный вызов получает некоторую информацию о потоке вместе с пустым указателем на аудиобуфер, который обратный вызов приводит к правильному типу данных в соответствии с параметром формата потока. Мое намерение, конечно, состоит в том, чтобы эта функция обратного вызова, реализованная в C, вызывала пользовательскую функцию Python с неким массивом в качестве аргумента, который затем заполнялся бы аудиоданными, например, из wav-файла, открытого с помощью Python.

Это то, что я хочу сделать, в коде:

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: как передать изменяемый массив правильного типа из C в потоке в функцию Python, которую затем можно использовать для заполнения аудиобуфера? Может быть, это можно сделать не так, как я описал выше? Все входные данные приветствуются.

1 ответ

Решение

Я думаю, вы могли бы сделать пару вещей. Если вы используете Python 2.7, вы можете создать объект memoryview, используя новый буферный протокол:

Затем вам нужно создать объект memoryview из буфера:

Другой стратегией было бы импортировать модуль массива и использовать его для создания массива нужного типа. Ты используешь:

Затем создайте массив в соответствии с необходимым типом:

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

Еще проще, вы можете просто использовать объект bytearray:

  • PyByteArray_FromStringAndSize для создания байтового массива, если вы можете структурировать вещи так, чтобы вам не нужно было беспокоиться о размере элементов массива.
Другие вопросы по тегам