Skip to content

Networking: UDP MIDI

Dale Whinham edited this page Apr 12, 2022 · 4 revisions

mt32-pi can receive raw MIDI data via a UDP socket, making it easy to write custom software that can stream MIDI to mt32-pi.

There is no handshaking protocol or session control, so only one client should be actively sending MIDI to the UDP socket at a time.

Setup

Enable Networking in mt32-pi, and ensure that the udp_midi configuration option is enabled. With networking enabled, mt32-pi will briefly display its IP address on the LCD once it connects successfully. mt32-pi will then be listening for MIDI data on UDP port 1999.

You can then direct your client software to mt32-pi's hostname or IP address.

MiSTer MidiLink

This feature is compatible with the UDP mode of the MiSTer MidiLink software by BinaryBond007.

  1. In MidiLink.INI, set UDP_SERVER to the hostname/IP address of mt32-pi.
  2. UDP_SERVER_PORT should be left at 1999.
  3. In the OSD menu of your FPGA core (e.g. AO486), the configuration should be set as follows:
    • Connection: MIDI
    • MidiLink: Remote
    • Type: UDP
  4. mt32-pi should now receive any MIDI data sent over the network by your MiSTer.

Code examples

The following Linux shell command plays a middle C note at velocity 64 on MIDI channel 2 using netcat to send a UDP packet:

echo -ne "\x91\x3c\x40" | nc -uw0 mt32-pi 1999

The following Bash script plays a chromatic scale at velocity 64 on MIDI channel 2:

#!/bin/bash

HOST="mt32-pi"

function note {
	echo -ne "\x91\x$1\x40" | nc -uw0 "$HOST" 1999
	sleep 0.35
	echo -ne "\x81\x$1\x40" | nc -uw0 "$HOST" 1999
	sleep 0.15
}

for i in {60..71}; do
	note "$(printf "%02x" "$i")"
done

The following Python 3 script creates a virtual MIDI port on the system, and forwards all MIDI data received on it to mt32-pi via UDP (requires python3-rtmidi):

#!/usr/bin/env python3

from signal import SIGINT, signal
from socket import AF_INET, SOCK_DGRAM, socket
from threading import Event

from rtmidi import MidiIn

UDP_HOST = "mt32-pi"
UDP_PORT = 1999
MIDI_PORT_NAME = "mt32-pi UDP socket"

sock = socket(AF_INET, SOCK_DGRAM)
midiin = MidiIn()
midiin.open_virtual_port(MIDI_PORT_NAME)

signal(SIGINT, lambda *_: exit(1))

print(
    f"Listening for MIDI on port '{MIDI_PORT_NAME}' and sending to"
    f" {UDP_HOST}:{UDP_PORT} (Ctrl-C to exit)..."
)

midiin.ignore_types(False, False, False)
midiin.set_callback(lambda msg, _: sock.sendto(bytes(msg[0]), (UDP_HOST, UDP_PORT)))
Event().wait()
Clone this wiki locally