Serial Write in GhPython, for MIDI

Dear forum,
Is there a way to send MIDI messages from GhPython?
I need to open a serial port and set the baud rate to 31250.
Then I need to send some bytes through that port, for example 0x90 0x3c 0x40
I assume it would be useful with a Serial Library, but how do I install that?
I have tried the Firefly Serial Write, but I can’t get the proper output (some bytes are changed and others are added).
Thanks a lot!

Hi Marten,

I wrote some Rhino Python to serial port code a few years back to run my Vinyl Cutter direct from Rhino with HPGL format.

It would not take much work to move the serial port code over to GHPython, I kind of remember doing this myself at some point.

Anyway - sample code attached to get you started - let me know if you have any questions.

Cheers

DK

210703_DK_Get_Plot_Size.py (1.9 KB)
210703_DK_Plot_Curves.py (4.5 KB)
210703_DK_Set_Com_Port.py (564 Bytes)

2 Likes

Wow, thanks a lot DK! Very kind of you to share this. I will give it a go!

You could use Firefly’s OSC Send and Receive. I have used that before to send realtime midi to Grasshopper. I just made a small script that takes midi and converts it to OSC. You could do the same in reverse? But it very much depends on the capabilities of the other end.

The good thing about OSC is, that you can send it over the network easily.

I hope it helps you. That’s how I fed Midi into GH and it worked very well. I remember GH using the Midi data to transform instances and it was running at something like 15fps, which for GH is just crazy fast.

1 Like

Thanks Armin, that’s an interesting idea! I’ll be sending the Midi data to a synth, so I guess the conversion from OSC to Midi would then need to happen somewhere between Grasshopper and the synth?

It does. There are several ways to do this and it depends a bit how the Synth is connected to the PC. I made my own little patch for that using vvvv (I used vvvv beta for that, which is free and works fine for something small and simple like that). There is also other software that can do that. One is Chataigne (Chataigne | Chataigne) which is a free software and has some amazing capabilities that go beyond just converting between formats.

Chataigne or any other software/piece of code would listen to OSC and convert it to midi. The midi is then sent to either a Midi Interface or the virtual midi port of the Synth (if it has USB).

1 Like

Thanks Armin, that sounds very promising! I’ll see if I can hook it up properly. My synth (Dreadbox Typhon) supports Midi over USB so it should work!

Hi David,
Here is my attempt to bring your script into GhPython. Unfortunately I can’t seem to open the COM port. I can open it with Firefly, so the actual port seems to work. Would you be able to look at it and perhaps see what I have done wrong? Thanks!
/Mårten
230824 open serial port error.gh (8.7 KB)

import rhinoscriptsyntax as rs

import System.IO.Ports as ports
import time

if Open:
    print 'Trying port ' + Port
    print 'Baud rate ' 
    print Baud
    try:
        Myport = ports.SerialPort(Port)
        Port_Write = ports.SerialPort.Write
        Myport.Baudrate = Baud
        Myport.ReadTimeout = 5000 # milliseconds
        Myport.Close()
        Myport.Open()
    except:
        print 'Serial Port not available'
        
if Send:
    Port_Write(Myport, 'A')
    Port_Write(Myport, 'B')
    Port_Write(Myport, 'C')

Morning mate,

A couple a suggestions on tool chains for Serial Port testing:

Virtual Serial Ports:

This lets you set up a virtual port to port connection that you send characters over.

PuTTY:

https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html

A simple to setup Serial Terminal Client.

You have your code drop data one end of the virtual connection and have PuTTY attached to the other end to see the result.

In saying all of that, there was a typo in your code:

Myport.Baudrate = Baud

should be

Myport.BaudRate = Baud

Attached is the version I got working.

Cheers

DK

230825 open serial port working.gh (5.5 KB)

1 Like

Wow! Thank you so much David for debugging and also great with the Virtual port + Terminal Client! Will hopefully have this working soon!
Cheers
/Mårten

1 Like

I can send data to the Serial Port now. But I can still not send the byte 144 (\x90), which is replaced by a question mark (see image below). I had this same issue in Firefly and the reason seems to be that the number is greater than 127. I have tried to send the Byte directly, but then I get “Expected str, got bytes”. All MIDI commands include bytes that are >127 so it’s crucial to be able to do this.
Is there some other way to send bytes that are >127?
230825 send byte error.gh (6.6 KB)
Skärmbild 2023-08-25 160159

I’m thinking that might be the terminal not able to render the character as it is not ASCII. So it was sent fine, just not understood on arrival.

Other though is you may need to encode your data as bytes in Python before sending as well.

Cheers

DK

1 Like

Hi! I tried to send a value higher than 127 from another terminal and that displayed properly, so I don’t think there’s a problem with the Terminal Monitor. (See image below). But when I send values from GhPython that are >127 they arrive as 63 (3F = ?). Not sure where they get converted, but I suspect it is inside Grasshopper somewhere. I get the same when I try Serial Write in Firefly (plus the added Newline char, 0A).

When I try to send bytes directly I get an error in GhPython saying “Runtime error (ArgumentTypeException) : expected str, got bytes”. Is there perhaps some alternate way to send bytes directly to the Serial Port?
Cheers

Printing bytes that are >127 seems to work fine:

There is a remark on Microsoft SerialPort Write here that states:

By default, SerialPort uses ASCIIEncoding to encode the characters. ASCIIEncoding encodes all characters greater than 127 as (char)63 or ‘?’. To support additional characters in that range, set Encoding to UTF8Encoding, UTF32Encoding, or UnicodeEncoding.

So, I guess the problem is not within Grasshopper, but rather in the way Windows handles the SerialPort data?
Also there seems to be a different format for sending a byte array. I’ll try to make that work.

Write(Byte[], Int32, Int32)

Ok, finally I have something that works! I switched to C# and it was a lot easier to get the formatting correct. Here is the C# Code and my GH file is attached.

using System.IO.Ports;

#---------------------

    if(x)
    {
      SerialPort _serialPort = new SerialPort(portName, baudRate);
      _serialPort.Open();
      byte[] midiData = {144, 60, 70};
      _serialPort.Write(midiData, 0, 3);
      _serialPort.Close();
    }


230826 c_sharp_success.gh (6.0 KB)

1 Like