将两个参数(int和array)传递给嵌入式Python函数

问题描述:

我需要从模块中调用Python函数,并为它设置两个参数:int和array。将两个参数(int和array)传递给嵌入式Python函数

对于我现在在调用这个函数的过程中我得到段错误,我不知道我做错了什么。有人可以指定我的错误在哪里吗?

函数在我的Python模块app.py中。它工作,如果我从Python代码调用它:

def get_model(rate, signal): 
    mfcc_train = MFCC().compute(rate, signal) 
    with open('mfcc_test', 'wb') as f: 
     pickle.dump(mfcc_train, f) 
    return clf()._fit(mfcc_train) 

我的C代码,调用上面的函数。最后普林是“呼叫之前”

#include <Python.h> 
#include <stdio.h> 
#include "wav.h" 
#include <numpy/arrayobject.h> 

int main(int argc, char *argv[]) 
{ 
    PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *pArgs; 
    uint8_t *samples = NULL; 

    wavread("test.wav", &samples); 

    printf("No. of channels: %d\n",  header->num_channels); 
    printf("Sample rate:  %d\n",  header->sample_rate); 
    printf("Bit rate:  %dkbps\n", header->byte_rate*8/1000); 
    printf("Bits per sample: %d\n\n",  header->bps); 
    printf("Sample 0:  %d\n", samples[0]); 
    printf("Sample 1:  %d\n", samples[1]); 
    // Initialize the Python Interpreter 
    printf("Before init\n"); 
    Py_Initialize(); 
    PyObject *sysPath = PySys_GetObject("path"); 
    const char *scriptDirectoryName = "."; 
    PyObject *path = PyUnicode_FromString(scriptDirectoryName); 
    int result = PyList_Insert(sysPath, 0, path); 
    printf("after init\n"); 
    // Build the name object 
    pName = PyUnicode_DecodeFSDefault(argv[1]); 
    printf("after pname %s %d\n", argv[1], pName == NULL ? 1 : 0); 

    // Load the module object 
    pModule = PyImport_Import(pName); 
    printf("after pmodule %d\n", pModule == NULL ? 1 : 0); 

    // pFunc is also a borrowed reference 
    pFunc = PyObject_GetAttrString(pModule, "get_model"); 
    printf("after pfunc\n"); 

    if (PyCallable_Check(pFunc)) 
    { 
     pArgs = PyTuple_New(2); 
     printf("after pytuple\n"); 
     PyTuple_SetItem(pArgs, 0, PyLong_FromLong(header->sample_rate)); 
     printf("after set item\n"); 
     uint8_t* array = malloc(header->datachunk_size); 
     int dims[1]; 
     dims[0] = header->datachunk_size; 
     printf("alloc\n"); 
     import_array(); 
     PyObject* pSamples = PyArray_SimpleNewFromData(1, dims, NPY_INT8, (void*)samples); 
     printf("pSamples\n"); 
     PyArray_ENABLEFLAGS((PyArrayObject*)pSamples, NPY_ARRAY_OWNDATA); 
     PyTuple_SetItem(pArgs, 1, pSamples); 
     printf("Before calling\n"); 
     pValue = PyObject_CallObject(pFunc, pArgs); 
     printf("After calling\n"); 
    } else 
    { 
     PyErr_Print(); 
    } 

    printf("pValue:  %d\n", pValue); 
    // Clean up 
    Py_DECREF(pModule); 
    Py_DECREF(pFunc); 
    Py_DECREF(pName); 

    // Finish the Python Interpreter 
    Py_Finalize(); 

    free(header); 
    free(samples); 
} 

UPD:更新的代码,其中一个问题是固定的。但是另一个问题依然存在。它在行PyObject* pSamples = PyArray_SimpleNewFromData(1, dims, NPY_INT8, (void*)samples);。我无法找出它有什么问题。

而且wav.h以防万一:

#include <inttypes.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <err.h> 
typedef struct { 
    char  chunk_id[4]; 
    uint32_t chunk_size; 
    char  format[4]; 
    char  fmtchunk_id[4]; 
    uint32_t fmtchunk_size; 
    uint16_t audio_format; 
    uint16_t num_channels; 
    uint32_t sample_rate; 
    uint32_t byte_rate; 
    uint16_t block_align; 
    uint16_t bps; 
    char  datachunk_id[4]; 
    uint32_t datachunk_size; 
}WavHeader; 
WavHeader *header; 
void wavread(char *file_name, int16_t **samples) 
{ 
    int fd; 
    if (!file_name) 
     errx(1, "Filename not specified"); 
    if ((fd = open(file_name, O_RDONLY)) < 1) 
     errx(1, "Error opening file"); 
    if (!header) 
     header = (WavHeader*)malloc(sizeof(WavHeader)); 
    if (read(fd, header, sizeof(WavHeader)) < sizeof(WavHeader)) 
     errx(1, "File broken: header"); 
    if (strncmp(header->chunk_id, "RIFF", 4) || 
     strncmp(header->format, "WAVE", 4)) 
     errx(1, "Not a wav file"); 
    if (header->audio_format != 1) 
     errx(1, "Only PCM encoding supported"); 
    if (*samples) free(*samples); 
    *samples = (int16_t*)malloc(header->datachunk_size); 
    if (!*samples) 
     errx(1, "Error allocating memory"); 
    if (read(fd, *samples, header->datachunk_size) < header->datachunk_size) 
     errx(1, "File broken: samples"); 
    close(fd); 
} 

这很难说没有的header的定义,但我认为这个问题是在该行

PyTuple_SetItem(pArgs, 0, header->sample_rate); 

PyTuple_SetItem预计Python对象和你传递它我认为是一个整数,这被误解为PyObject*

我怀疑你想

PyTuple_SetItem(pArgs, 0, PyInt_FromLong(header->sample_rate)); 

PyLong_FromLong在Python3)


第二期:你freesamples两次。首先,你将它传递给numpy的,并告诉numpy的,它拥有数据:

PyObject* pSamples = PyArray_SimpleNewFromData(1, dims, NPY_INT8, (void*)samples); 
PyArray_ENABLEFLAGS((PyArrayObject*)pSamples, NPY_ARRAY_OWNDATA); 

然后在你的代码的末尾,你释放它

free(samples); 

我怀疑你的意思是通过你的新分配array到numpy而不是samples。 (您仍然需要它们之间的数据复制过,如果是这种情况)

UPD:从评论的一个更合适的解决办法是改变从int DIMS的类型npy_intp

+0

是的,你是对。当我发现这个问题时,我忘记了更新这篇文章。但不幸的是,这不仅是我的代码中的问题。现在我遇到了这样的问题:'PyObject * pSamples = PyArray_SimpleNewFromData(1,dims,NPY_INT8,(void *)samples);'它的工作原理并不正确,因为有时我在执行结束时得到段错误,另一个副作用。 – Donz

+0

并不介意标题wav.h.这只是为了读取wav文件。但为了以防万一我将其添加到帖子中。 – Donz

+1

@Donz请参阅编辑 - 至少还有一个问题 – DavidW