Forum Archive

CoreMidi implementation failed

eriknie

I tried to send a note to a midi application. (eventually through Bluetooth). My code to output a midi note seems fine, but I receive nothing.
Not much data found, I combined several swift/pyhtonista combinations.
Sorry for the ugly code, just try to figure out how it works, clean up later.
Not sure what i'm doing wrong here.
I you want to test is, download Synth One. it shows up in the list of destinations, but i hear no triggered note....
Been struggling for days to get this working.

My goal is to write an application for showing chords/lyrics on on iPad. I want to send a midi program change after selecting a song via bluetooth midi to mainstage.
Got the base of the application running, also the bluetooth connection running.
The bluetooth shows up in the destinations.

I isolated the midi part. in this example

from objc_util import *
from ctypes import *
import time

NSBundle.bundleWithPath_('/System/Library/Frameworks/CoreAudioKit.framework').load()
CoreMIDI = NSBundle.bundleWithPath_('/System/Library/Frameworks/CoreMIDI.framework')
CoreMIDI.load()

#NOTE: `c` is defined in objc_util as `ctypes.cdll.LoadLibrary(None)`
MIDIClientCreate = c.MIDIClientCreate
MIDIClientCreate.restype = c_int
MIDIClientCreate.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p]

MIDIObjectGetProperties = c.MIDIObjectGetProperties
MIDIObjectGetProperties.restype = c_int
MIDIObjectGetProperties.argtypes = [c_void_p, c_void_p, c_bool]

MIDIObjectGetStringProperty = c.MIDIObjectGetStringProperty
MIDIObjectGetStringProperty.restype = c_int
MIDIObjectGetStringProperty.argtypes = [c_void_p, c_void_p, c_void_p]

MIDIOutputPortCreate = c.MIDIOutputPortCreate
MIDIOutputPortCreate.restype = c_int
MIDIOutputPortCreate.argtypes = [c_void_p, c_void_p, c_void_p]

#device
MIDIGetNumberOfDevices = c.MIDIGetNumberOfDevices
MIDIGetNumberOfDevices.restype = c_int
MIDIGetNumberOfDevices.argtypes = []

MIDIGetDevice = c.MIDIGetDevice
MIDIGetDevice.restype = c_void_p
MIDIGetDevice.argtypes = [c_int]


MIDIPacketListInit = c.MIDIPacketListInit
MIDIPacketListInit.restype = c_void_p
MIDIPacketListInit.argtypes = [c_void_p]

MIDIPacketListAdd = c.MIDIPacketListAdd
MIDIPacketListAdd.restype = c_void_p
MIDIPacketListAdd.argtypes = [c_void_p, c_int, c_void_p, c_ulonglong, c_int, c_void_p]

MIDIReceived = c.MIDIReceived
MIDIReceived.restype = c_int
MIDIReceived.argtypes = [c_void_p, c_void_p]

#destinations
MIDIGetNumberOfDestinations = c.MIDIGetNumberOfDestinations
MIDIGetNumberOfDestinations.restype = c_int
MIDIGetNumberOfDestinations.argtypes = []

MIDIGetDestination = c.MIDIGetDestination
MIDIGetDestination.restype = c_void_p
MIDIGetDestination.argtypes = [c_int]

NumberOfDestinations = MIDIGetNumberOfDestinations()
print("NumberOfDestinations: ",NumberOfDestinations) 

MIDIPacketList = create_string_buffer(64)
MIDIPacket = MIDIPacketListInit(MIDIPacketList)
print("MIDIPacket:",MIDIPacket)

myPacket = (c_char * 3)(0x90,60,100) 
myPacketp = pointer(myPacket)
r = MIDIPacketListAdd(MIDIPacketList, 17, MIDIPacket,0,3,myPacketp)
print("MIDIPacketListAdd:", r)
print(repr(MIDIPacketList))
for i in range(17):
    print(i, repr(MIDIPacketList[i]) )

for i in range(NumberOfDestinations):
        time.sleep(1)
        dst = MIDIGetDestination(i)
        props = c_void_p()
        MIDIObjectGetProperties(dst, byref(props), True)
        uniqueID = c_void_p()
        MIDIObjectGetStringProperty(dst, ns('uniqueID'), byref(uniqueID))
        name = c_void_p()
        MIDIObjectGetStringProperty(dst, ns('name'), byref(name))
        print("=======================================") 
        print(i, " DESTINATION: ", ObjCInstance(props),"name: ", ObjCInstance(name))
        #print(i, " ID: ", ObjCInstance(uniqueID),"name: ", ObjCInstance(name))
        r = MIDIReceived(dst,MIDIPacketList)
        print( "send: ", r)

time.sleep(5)

print("ready")

The output:

NumberOfDestinations:  2
MIDIPacket: 4487117236
MIDIPacketListAdd: 4487117236
<ctypes.c_char_Array_64 object at 0x10b76bcc8>
0 b'\x01'
1 b'\x00'
2 b'\x00'
3 b'\x00'
4 b'\x00'
5 b'\x00'
6 b'\x00'
7 b'\x00'
8 b'\x00'
9 b'\x00'
10 b'\x00'
11 b'\x00'
12 b'\x03'
13 b'\x00'
14 b'\x90'
15 b'<'
16 b'd'
=======================================
0  DESTINATION:  {
    uniqueID = "-1336782696";
} name:  Session 1
send:  0
=======================================
1  DESTINATION:  {
    name = "AudioKit Synth One";
    uniqueID = 95433;
} name:  AudioKit Synth One
send:  0
ready
JonB

Isn't it midisend that you want? Not receive?

eriknie

That was also my first guess, but in al the examples where the destinations are used, they use MIDIReceived().
If you open een client, then you have to use MIDISend().

https://stackoverflow.com/questions/10572747/why-doesnt-this-simple-coremidi-program-produce-midi-output

I seem to miss something....

JonB

Do you need to create a virtual source? In the final example in the stack overflow, midireceived gets called with the source, not the destination.
Also wonder if time stamp needs to be setup?

JonB

for that matter, you are not creating a client?

i tried, but am getting a -50 error. ill try on another device. it may be that midi requires an entitlement that pythonista does not have.

eriknie

Thanks for al the help and comments!!!

I've seen examples that only get a destinationget and use Midi-Receive on it.

Tried many options and still am stuck.

If you create a client, than You have to select the client in the synth as input.
In the end I want to select the Bluetooth (by name) from the destinations and sent a program change via that.
The most simple example was to try to get a note on via destiantions to a virtual synth and build on that.

HELP!!

eriknie

Any other idea to send data via bluetooth from Pythonista to my macbook Pro?

I can write a python program on the macbook pro to convert it to midi (that part is easy)

JonB

See https://forum.omz-software.com/topic/2158/coremidi-using-objc_util-questions/3

Omz posts some code on how to create the client. Wradcliffe posts a link to some python coremidi wrapper which will work with minor changes, in theory. But I vaguely recall that pythonista no longer has the audio key set. When I try to create a client, I get an error...I am pretty sure you need a client before you can do anything.

eriknie

I tried all possible combination, no midi is recieved by any clients. I spent way too much time on this....
Would be nice if Pythonista had a coreMidi module installed...

Thanks for all the help!