4

I have the following midi wrapper for Python3:

#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;
}

With the following setup.py file:

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])

I then run this python code, but it gives me:

import midi
m = midi.Midi()

but it outputs simply on Mavericks:

INIT
END

I.e. it finds no devices.

I have also tried this:

#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));


}
}

With the following make file:

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)

Which correctly lists my midi devices. What am I doing wrong?

Baz
  • 12,713
  • 38
  • 145
  • 268
  • MIDIGetNumberOfDestinations() returns "The number of destinations in the system, or 0 if an error occurred". Have you tried to debug it somehow? – twil Nov 28 '13 at 17:51
  • @twil What can I debug? The function returns 2 when its called from a very simple c function and 0 when called using the Python's C API. I think the problem is a linker one even though I get no errors when I run python setup install. For example, I can change "CoreMIDI" to "Foo" in the setup.py file and I get no errors. – Baz Nov 29 '13 at 09:21
  • Why are you calling `MIDIGetNumberOfDestinations()` in the Python example, but `MIDIGetNumberOfDevices()` in the C example? – Kurt Revis Nov 30 '13 at 08:35

1 Answers1

3

The problem was that my IAC Driver was offline. The driver is offline by default.

Baz
  • 12,713
  • 38
  • 145
  • 268