使用 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的主要内容,如果未能解决你的问题,请参考以下文章