Вызов функции 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 из буфера:
Другой стратегией было бы импортировать модуль массива и использовать его для создания массива нужного типа. Ты используешь:
- PyImport_ImportModule
- PyModule_GetDict
- PyObject * array_type = PyDict_GetItemString(dict, "array");
Затем создайте массив в соответствии с необходимым типом:
PyObject *array = PyObject_CallFunction(array_type, "c", 'd');
Еще проще, вы можете просто использовать объект bytearray:
- PyByteArray_FromStringAndSize для создания байтового массива, если вы можете структурировать вещи так, чтобы вам не нужно было беспокоиться о размере элементов массива.