|
Post by jpilarski on Aug 11, 2019 22:48:52 GMT
I am using pythonista on ios to generate some midi values but the rtmidi library can't be installed for ios and none of the other pyhton midi libraries are in pure python ( a requirement for pythonista packages) so it sounds like osc might be the best way to get midi out from pythonista. I am able to get an osc message sent out to touchosc and get it to toggle a pad off and on but now I'd like to understand how I can use the OSC module in midifire. To be honest I am just learning what sysex is and that midifire is taking an osc message and formatting it into a proper sysex message but I don't know exactly how to use it. Is it possible to get a basic example file showing how to take an osc message and make it into a midi note on and send it to a midi port. I am hoping if I saw how to do that I could build off of it. If you have any other thoughts on how I might be able to send midi out from pythonista I'd love to get your advice since clearly you know it all when it comes to midi and ios. thanks
|
|
nic
Soapbox Supremo
Troublemaker
Press any key to continue
Posts: 2,011
|
Post by nic on Aug 12, 2019 8:42:25 GMT
Hi jpilarski , Let me check I have this correct. iOS pythonista cannot see any MIDI ports at all (physical, virtual, network, bluetooth) but it can send a UDP packet to a host and destination? Or can it just not see the wifi port? I think it is the former (no ports at all) from your description. What is the final destination for the MIDI messages? Maybe there is a different way than what I describe below. MidiFire's OSC Exchange module will actually accept any data (does not need to be OSC) so in theory you could just pipe your unaltered MIDI messages to it (one per packet for simplicity) and then unpack the resultant sysex and forward the MIDI to wherever you need in MidiFire (any MIDI port). The tricky part is unpacking (decoding 7 bit back to 8 bit) the MIDI message from the sysex, though. It should be possible to write some Stream Byter code to do this. Here is how the encoding works: OSC Exchange adds an additional byte every 7 bytes to store the MSB of every value. So 7 values look like this: (0 MSB7 MSB6 MSB5 MSB4 MSB3 MSB2 MSB1) (BYTE1 & 0x7F) (BYTE2 & 0x7F) (BYTE3 & 0x7F) (BYTE4 & 0x7F) (BYTE5 & 0x7F) (BYTE6 & 0x7F) (BYTE7 & 0x7F)So, the Stream Byter code would need to reverse that encoding and then the original message could be assembled.If you were only sending non-sysex messages to start with, this code could be quite simple. If not, then it's a little more complex. That's the gist of how I would approach the problem. If you didn't want to write Stream Byter code (and it's admittedly a non trivial exercise) then I could probably have a go some time. Regards, Nic.
|
|
nic
Soapbox Supremo
Troublemaker
Press any key to continue
Posts: 2,011
|
Post by nic on Aug 12, 2019 9:26:02 GMT
Actually, given we know the exact sysex format generated by OSC Exchange for non-sysex messages, we can unpack this quite easily.
Setup MidiFire as follows:
- OSC Exchange, listening on udp port number of your choice. - Stream Byter (with code below)
Connect OSC Exchange to Stream Byter. Connect Stream Byter to your MIDI destination(s)
In your pythonista script send individual (non sysex) messages via udp to localhost:<your port number>
Paste this code into Stream Byter and press 'Install Rules'
# unpack OSC Exchange (non syx) msg IF M0 == F0 5A MAT M3 = M3 + 80 SND M3 M4 M5 XX = XX +B END
I think this should work correctly for 3 byte messages, will probably work for 1 or 2 byte messages but will definitely not work for wrapped sysex messages.
If you find it does not work, then use the Event Monitor modules (say one before and one after Stream Byter) to examine the packed and unpacked messages - it's possible the code above isn't correct!
Regards, Nic.
|
|
|
Post by jpilarski on Aug 12, 2019 17:52:25 GMT
Wow this is great and so informative. I can't wait to try it. To answer your question regarding pythonista and midi it can't see any ports but in the forum they are suggesting to use midifire as noted in this post forum.omz-software.com/topic/4506/midi. Pythonista is a well developed app and it has a good sized user base that are, according to multiple midi related posts on the forum, very interested in using midi. Not sure if this makes sense but it might be worth looking into as I bet you can find a way and perhaps there is an app that can address the current limitations. thanks again
|
|
nic
Soapbox Supremo
Troublemaker
Press any key to continue
Posts: 2,011
|
Post by nic on Aug 13, 2019 10:23:05 GMT
Hi jpilarski , Just to follow up on this. I tested my code above this morning and it seems to work fine. I will point out that from the python script that the MIDI message must be sent as binary to the UDP port, so each udp packet will be 1, 2 or 3 bytes depending upon the MIDI message you are sending. If you send it a text string it won't work. To send MIDI from MidiFire back to a script via udp, you would do the reverse operation and feed incoming MIDI messages into a Stream Byter with these rules and then onto OSC Exchange configured to send on a specific udp port: # pack for osc exchange IF ML <= 3 MAT M0 = M0 - 80 SND F0 5A 01 M0 M1 M2 F7 XX = XX +B ENDNaturally, the python script must be listening on that udp port, and each MIDI message will be received as a separate binary packet > it has a good sized user base that are, according to multiple midi related posts on the forum, very interested in using midi.So, this method works and will allow you to push/pull MIDI events to CoreMIDI via udp (mac or ios for that matter) from any scripting (or compiled) language pretty easily using MidiFire as a bridge between CoreMIDI. I could have a go at making up a MidiFire scene and posting it here that does bi-directional udp/CoreMIDI conversion to make it easy to deploy. If anyone would like this - please let me know. If I'm made aware of a demand to be able to also handle sysex with this method then I might consider writing packing/unpacking routines in Stream Byter that will work with that too, but for now, just non-sysex messages. Regards, Nic.
|
|
nic
Soapbox Supremo
Troublemaker
Press any key to continue
Posts: 2,011
|
Post by nic on Dec 10, 2019 20:34:15 GMT
And final followup.
As of v2.0 of MidiFire, raw data can be sent/received without the unpacking stuff described as above. Just set 'wrap data in sysex' to 'no' in OSC Exchange.
Regards, Nic.
|
|
|
Post by jpilarski on Aug 4, 2020 23:46:15 GMT
Here is some code for Pythonista using UDP to MidiFire #https://adamsiembida.com/how-to-send-a-udp-packet-in-python/ import socket
# addressing information of target #fill in your ip and port IPADDR = '127.0.0.1' PORTNUM = 8051
# enter the data content of the UDP packet as hex msg1 = bytearray([0x90, 0x40, 0x60]) msg2 = bytes.fromhex('903e70') #or using variable for midi note message midi_message = '903c50' midi_packet = bytes.fromhex(midi_message)
# initialize a socket, think of it as a cable # SOCK_DGRAM specifies that this is UDP s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
try: # connect the socket, think of it as connecting the cable to the address location s.connect((IPADDR, PORTNUM)) # send the command s.send(midi_packet) s.send(msg1) s.send(msg2) # close the socket except: pass # close the socket s.close()
|
|