使用 Python C API 时 MIDIGetNumberOfDestinations 返回 0

Posted

技术标签:

【中文标题】使用 Python C API 时 MIDIGetNumberOfDestinations 返回 0【英文标题】:MIDIGetNumberOfDestinations returning 0 when using Python C API 【发布时间】:2013-11-25 14:39:37 【问题描述】:

我有以下 Python3 的 midi 包装器:

#include <Python.h>
#include "structmember.h"
#include <CoreMIDI/CoreMIDI.h>
#include "stdio.h"

#define MESSAGESIZE 3

// CFStringRef to char*
char * MYCFStringCopyUTF8String(CFStringRef aString) 
  if (aString == NULL) 
    return NULL;
  

  CFIndex length = CFStringGetLength(aString);
  CFIndex maxSize =
  CFStringGetMaximumSizeForEncoding(length,
                                    kCFStringEncodingUTF8);
  char *buffer = (char *)malloc(maxSize);
  if (CFStringGetCString(aString, buffer, maxSize,
                         kCFStringEncodingUTF8)) 
    return buffer;
  
  return NULL;


typedef struct 
    PyObject_HEAD
 Midi;

static void Midi_dealloc(Midi* self)

    Py_TYPE(self)->tp_free((PyObject*)self);


static int Midi_init(Midi *self)

    ItemCount nDests = MIDIGetNumberOfDestinations();
    printf("INIT\n");
    for (ItemCount i = 0 ; i < nDests ; ++i) 

       // Grab a reference to current device
       MIDIDeviceRef device = MIDIGetDevice(i);
       CFStringRef name = nil;
       MIDIObjectGetStringProperty(device, kMIDIPropertyName, &name);
       printf("%s\n", MYCFStringCopyUTF8String(name));
    
    printf("END\n");    
    return 0;


static PyObject * Midi_add(Midi* self, PyObject *args)

      return Py_None;


static PyObject * Midi_bend(Midi* self, PyObject *args)

       return Py_None;


static PyObject * Midi_play(Midi* self)

    return Py_None;


static PyMethodDef Midi_methods[] = 

    "add", (PyCFunction)Midi_add, METH_VARARGS, "Add note",
    "bend", (PyCFunction)Midi_bend, METH_VARARGS, "Bend note",
    "play", (PyCFunction)Midi_play, METH_NOARGS, "Play Notes",
    NULL  /* Sentinel */
;

static PyTypeObject MidiType = 
    PyVarObject_HEAD_INIT(NULL, 0)
    "midi.Midi",             /* tp_name */
    sizeof(Midi),             /* tp_basicsize */
    0,                         /* tp_itemsize */
    (destructor)Midi_dealloc, /* tp_dealloc */
    0,                         /* tp_print */
    0,                         /* tp_getattr */
    0,                         /* tp_setattr */
    0,                         /* tp_reserved */
    0,                         /* tp_repr */
    0,                         /* tp_as_number */
    0,                         /* tp_as_sequence */
    0,                         /* tp_as_mapping */
    0,                         /* tp_hash  */
    0,                         /* tp_call */
    0,                         /* tp_str */
    0,                         /* tp_getattro */
    0,                         /* tp_setattro */
    0,                         /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT |
        Py_TPFLAGS_BASETYPE,   /* tp_flags */
    "Midi objects",           /* tp_doc */
    0,                     /* tp_traverse */
    0,                     /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Midi_methods,             /* tp_methods */
    0,                  /* tp_members */
    0,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    (initproc)Midi_init,      /* tp_init */
;

static PyModuleDef midimodule = 
    PyModuleDef_HEAD_INIT,
    "midi",
    "Midi Module",
    -1,
    NULL, NULL, NULL, NULL, NULL
;

PyMODINIT_FUNC
PyInit_midi(void) 

    PyObject* m;

    MidiType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&MidiType) < 0)
        return NULL;

    m = PyModule_Create(&midimodule);
    if (m == NULL)
        return NULL;

    Py_INCREF(&MidiType);
    PyModule_AddObject(m, "Midi", (PyObject *)&MidiType);
    return m;

使用以下 setup.py 文件:

from distutils.core import setup, Extension

module = Extension('midi', sources = ['midi.c'],  extra_link_args=['-framework', 'CoreMIDI', '-framework', 'CoreFoundation'])

setup (name = 'Midi',
       version = '1.0',
       description = 'Midi Controller',
       ext_modules = [module])

然后我运行这个 python 代码,但它给了我:

import midi
m = midi.Midi()

但它只是在 Mavericks 上输出:

INIT
END

即它找不到任何设备。

我也试过这个:

#import <CoreMIDI/CoreMIDI.h>

char * MYCFStringCopyUTF8String(CFStringRef aString) 
  if (aString == NULL) 
    return NULL;
  

  CFIndex length = CFStringGetLength(aString);
  CFIndex maxSize =
  CFStringGetMaximumSizeForEncoding(length,
                                    kCFStringEncodingUTF8);
  char *buffer = (char *)malloc(maxSize);
  if (CFStringGetCString(aString, buffer, maxSize,
                         kCFStringEncodingUTF8)) 
    return buffer;
  
  return NULL;


int main(int argc, char *argv[])

  // How many MIDI devices do we have?
  ItemCount deviceCount = MIDIGetNumberOfDevices();

  // Iterate through all MIDI devices
  for (ItemCount i = 0 ; i < deviceCount ; ++i) 

    // Grab a reference to current device
    MIDIDeviceRef device = MIDIGetDevice(i);
    CFStringRef name = nil;
    MIDIObjectGetStringProperty(device, kMIDIPropertyName, &name);
    printf("%s\n", MYCFStringCopyUTF8String(name));




使用以下make文件:

SRCS =      midi2.c
OBJS =      midi2.o
LIBS =      -framework CoreMIDI -framework CoreFoundation 
TARGET =    Midi2 

$(TARGET):  $(OBJS)
    $(CC) -o $(TARGET) $(SRCS) $(LIBS)

all:    $(TARGET)

clean:
    rm -f $(OBJS) $(TARGET)

正确列出了我的 MIDI 设备。我做错了什么?

【问题讨论】:

MIDIGetNumberOfDestinations() 返回“系统中目标的数量,如果发生错误,则返回 0”。您是否尝试过以某种方式对其进行调试? @twil 我可以调试什么?该函数在从非常简单的 c 函数调用时返回 2,在使用 Python 的 C API 调用时返回 0。我认为问题出在链接器上,即使我在运行 python setup install 时没有出错。例如,我可以在 setup.py 文件中将“CoreMIDI”更改为“Foo”,并且不会出现错误。 为什么在 Python 示例中调用 MIDIGetNumberOfDestinations(),而在 C 示例中调用 MIDIGetNumberOfDevices() 【参考方案1】:

问题是我的 IAC 驱动程序离线。驱动默认离线。

【讨论】:

以上是关于使用 Python C API 时 MIDIGetNumberOfDestinations 返回 0的主要内容,如果未能解决你的问题,请参考以下文章

为啥在使用 Python/C API 时会出现此段错误?

Python C API - 创建关键字

Python C API:T_INT 未在此范围内声明

Python C API 和 C++ 函数

如何使用 ctypes 在 python 中正确包装 C API?

扩展Python模块系列----异常和错误处理