back
- MIDI
- to control SimHub plugins
and for SimHub to control external tactile signal effects,
e.g. a VST multichannel fader plugin in VoiceMeeter
About MIDI: servers, clients, senders, receivers, control surfaces, sequencers,
                        editors, recorders, instruments
Historically, MIDI (Musical Instrument Digital Interface) was a variation on asynchronous serial communication,
using the same UART technology as in serial printers, terminals and modems,
but with idiosynchratic 31.5kbps data rate, 5-pin (ground + 2 in + 2 out) DIN connectors and 5 Volt signals,
instead of RS-232's D-subminiature 25 or 9-pin connectors with +/-12 Volt signals.
More crucially, while RS-232 is essentially point-to-point between data terminals and carriers,
MIDI can daisy-chain, with signals passed among devices that can both initiate and receive packets.
Consequently, MIDI packets include addressing for 16 channels, to selectively send and receive packets along a shared bus.
While all MIDI devices may send and receive messages, instruments are typically receivers,
while control surfaces and sequencers are typically senders.
Once IP networking is involved, server and client roles get involved.
Either senders or receivers can be either servers or clients.
Since web browsers can play music, JavaScript to behave as client instruments is relatively popular.
At any rate, code for Websocket MIDI control surface servers is relatively rare.
MIDI 1.0 messages mostly include 3 bytes, one for status and 2 for data.
- Data bytes are constrained to have msb=0, so only 7 bits for information.
- The status byte has most-significant bit = 1, 4 least significant bits for addressing 16 channels,
leaving 3 bits for message types, 7 of which (8x - Ex) are for channel messages:
Status Byte | hex | Data Byte1 | Data Byte2 |
Note off | 8x | Key number | Note Off velocity |
Note on | 9x | Key number | Note on velocity |
Polyphonic Key Pressure | Ax | Key number | Amount of pressure |
Control Change (CC) | Bx | Controller 0-120 | Controller value |
Control Mode | Bx | 79: reset all | 00 |
Control Mode | Bx | 7A: Local | 0:off 127:on |
Control Mode | Bx | 7B: All notes off | 00 |
Control Mode | Bx | 7C: Omni off | 00 |
Control Mode | Bx | 7D: Omni on | 00 |
Control Mode | Bx | 7E: Mono on | 0 or channel cnt |
Control Mode | Bx | 7F: Poly on | 00 |
Program Change | Cx | Program number | None |
Channel Pressure | Dx | Pressure value | None |
Pitch Bend | Ex | MSB | LSB |
SysEX start | F0 | many bytes | ... |
Timing code | F1 | only 1 byte | (na) |
Song position | F2 | MSB | LSB |
Timing code | F3 | only 1 byte | (na) |
Timing code | F6 | (na) | (na) |
SysEX stop | F7 | (na) | (na) |
Timing clock | F8 | MSB | LSB |
Start sequence | FA | MSB | LSB |
Continue sequence | FB | MSB | LSB |
Stop sequence | FC | MSB | LSB |
Active sensing | FE | MSB | LSB |
System reset | FF | MSB | LSB |
MIDI messages F4, F5, F9, FD are undefined.
Control Change (CC) messages are of particular interest here;
many second byte values support 127 third byte values and appropriate for sliders:
Hex 00-13 for MSB and 20-33 for corresponding LSB.
First data byte values 70-83, 85-95 are for LSB-only second data bytes
- Juan P Bello's
MIDI Code pdf
Wireless MIDI
- MIDI control of SimHub and VoiceMeeter
was first tried by Wi-Fi
e.g. from smartphone or ESP32. 
Instead, it is now by MIDIio
and KORG nanoKONTROL2.
- ESP32-S2 USB MIDI does not composite well with other devices (CDC, HID gamepad)
- Instead, send MIDI over Wi-Fi, preferably by WebSocket
- Wireless MIDI flavors
- DSMI - old protocol for Nintendo DS
- ipMIDI - proprietary $79 (60 min. free trial)
One of two MIDI-over-UDP protocols, uses "well-known" port;
Arduino can be a relatively simple client.
- Apple MIDI - AKA RTP MIDI UDP depending on DNS broadcast
Arduino must be a relatively complex server
- WebSocket MIDI - similar to Apple MIDI, except by TCP WebSocket instead of UDP
  For ESP32, AsyncUDP is bundled with Arduino core,
  but separate from AsyncTCP wanted for efficient webserver,
  making this perhaps the most efficient implementation.
 
Apple MIDI parser bundled in the
Arduino
library does not seem robust;
  alternatives exist, e.g. in librtpmidid (C++) and
MIDIMonster (C)
backend
  rtpmidid includes good-looking tests, despite C++...
- WebMIDI - NOT WebSocket MIDI; MIDI device access from web browsers
WEBMIDI.js   GitHub
examples
- Android Wireless Mixer app using DSMI
- Trajkovski Labs support page
Installation
Wireless Mixer MIDI map (CC numbers, decimal)
    Master volume = 7
    Play = 118
    Stop = 120
    Record = 119
    Left = 4
    Right = 5
    Previous = 2
    Next = 1
Slider1 = 8
Slider2 = 9
Slider3 = 10
Slider4 = 12
Slider5 = 13
Slider6 = 14
Slider7 = 15
Slider8 = 16
Slider9 = 17
Slider10 = 18
Slider11 = 19
Slider12 = 20
|
    Pan1 = 23
    Pan2 = 24
    Pan3 = 25
    Pan4 = 26
    Pan5 = 27
    Pan6 = 28
    Pan7 = 29
    Pan8 = 30
    Pan9 = 31
    Pan10 = 33
    Pan11 = 34
    Pan12 = 35
|
    Knob1-1 = 39
    Knob1-2 = 40
    Knob1-3 = 41
    Knob1-4 = 42
    Knob1-5 = 43
    Knob1-6 = 44
    Knob1-7 = 45
    Knob1-8 = 46
    Knob1-9 = 47
    Knob1-10 = 48
    Knob1-11 = 49
    Knob1-12 = 50
|
    Knob2-1 = 53
    Knob2-2 = 54
    Knob2-3 = 55
    Knob2-4 = 56
    Knob2-5 = 57
    Knob2-6 = 58
    Knob2-7 = 59
    Knob2-8 = 60
    Knob2-9 = 61
    Knob2-10 = 62
    Knob2-11 = 63
    Knob2-12 = 65
|
    Knob3-1 = 102
    Knob3-2 = 103
    Knob3-3 = 104
    Knob3-4 = 105
    Knob3-5 = 106
    Knob3-6 = 107
    Knob3-7 = 108
    Knob3-8 = 109
    Knob3-9 = 110
    Knob3-10 = 111
    Knob3-11 = 112
    Knob3-12 = 113
|
Mute1 = 66
Mute2 = 67
Mute3 = 68
Mute4 = 69
Mute5 = 70
Mute6 = 71
Mute7 = 72
Mute8 = 73
Mute9 = 74
Mute10 = 75
Mute11 = 76
Mute12 = 77
|
    Solo1 = 78
    Solo2 = 79
    Solo3 = 80
    Solo4 = 81
    Solo5 = 82
    Solo6 = 83
    Solo7 = 84
    Solo8 = 85
    Solo9 = 86
    Solo10 = 87
    Solo11 = 88
    Solo12 = 89
|
    Rec1 = 90
    Rec2 = 91
    Rec3 = 92
    Rec4 = 93
    Rec5 = 94
    Rec6 = 95
    Rec7 = 96
    Rec8 = 97
    Rec9 = 98
    Rec10 = 99
    Rec11 = 100
    Rec12 = 101
|
    ExBtn1_1 = 11
    ExBtn1_2 = 21
    ExBtn1_3 = 22
    ExBtn1_4 = 32
    ExBtn1_5 = 36
    ExBtn1_6 = 37
    ExBtn1_7 = 38
    ExBtn1_8 = 51
    ExBtn1_9 = 52
    ExBtn1_10 = 124
    ExBtn1_11 = 125
    ExBtn1_12 = 126
|
    ExBtn2_1 = 114
    ExBtn2_2 = 115
    ExBtn2_3 = 116
    ExBtn2_4 = 117
    ExBtn2_5 = 121
    ExBtn2_6 = 122
    ExBtn2_7 = 123
    ExBtn2_8 = 127
    ExBtn2_9 = 64
    ExBtn2_10 = 6
    ExBtn2_11 = 5
    ExBtn2_12 = 3(?)
|
-  
- WebMIDI over WebSocket directly from the web page
- A general purpose MIDI over WebSocket approach
  using EventEmitter JavaScript
-  
- MIDI over WebSocket
- ESPAsyncWebServer examples include WebSocket server and client
- ESP32 WebSocket Server - Random Nerd
- esp32 WebSocket client - Mischianti
- ESP32 Arduino Tutorial: Websocket client - DFRobot 2017
ESP32 Arduino: Websocket client
  ESP8266-Websocket server and client examples
  simple-client sketch
- HTML5 - WebSockets tutorial with Client-side HTML & JavaScript code
- OBS-Websockets-MIDI Bridge
-  
- PC MIDI servers
- MCPW.EXE, seemingly compatible with RTP MIDI or TCP;
  requires a separate MIDI port provider, e.g. loopMIDI
- rtpMIDI server
- mnet MIDIHub 32/64-bit WinMM MIDI driver
,
our designated bridge between IP and MIDI,
  supports ipMIDI, RTP, WebSocket, WebMIDI and Bluetooth;
  behaves as a client for UDP, but a server for ipMIDI AKA multicast IP.
It also behaves as a client for TCP WebSocket looking for servers to announce (via DNS) MIDI service.
Apple MIDI (AKA RTP) uses one UDP port for control and another for MIDI messages
Whether it wants one or two ports for TCP WebSockets is unclear.
  provides its own MIDI ports:
- as warned, MIDIHub provokes firewall pop-ups for MIDI apps
- "owned" by VoiceMeeter on initial launch
- Its documentation suggests that it can be both a websocket server and client.
mnet.log reports: WebSocketIO - server listening on port: 6504
- Web browser JavaScript is not allowed to create a WebSocket server,
but a JavaScript client to open a WebSocket to that port and try sending some MIDI messages may not be too hard;
here are an article
and sample browser code.
- mnet MIDIHub does not seem to work as described
supposedly hidden by default, multicast ports appear
- RTP ports seemingly only appear if detected by
multicast DNS
service_type evidently should be _apple-midi .
- Writing WebSocket servers
responding to pings.
- Node.js WebSocket MIDI servers
-  
- Apple MIDI over UDP
- RTP MIDI:
  Apple network MIDI (UDP),
  AppleMIDI with ESPAsyncWebServer examples
- Apple's MIDI
Network Driver Protocol Document
-  
- Hairless MIDI<->Serial Bridge
- connect serial devices (e.g. Arduinos) to send and receive MIDI signals
- LibreConnect Server
- generates websockets for serial USB-attached Arduinos
- AsyncUDP example - library provided with Expressif ESP32 core for Arduino;
may be extended for MIDI support as a learning step; AppleMIDI for Arduino supports ESP32
- AsyncTCP example - GitHub library; will be extended for MIDI support,
to avoid running both it (for webserver) and AsyncUDP
- this sketch can only make a single response per opening
- Restarting Serial Monitor for either of the above examples restarts the connection..
- ESP32_NoteOnOffEverySec.ino from
Arduino-AppleMidi-Library examples
- wESP32_NoteOnOffEverySec.ino
includes
MDNS.addService("apple-midi", "udp", AppleMIDI.getPort());
- replaced
ETH.begin(); in ETH_Heelper.h:ETH_startup() with WiFi.begin()
- MIDIHub recognizes the device, and the sketch reports:
Connected to session 4155933516 mnet (ALIENWARE-R7_144) 8 ,
...but also reports *** ListenerTimeOutException and many *** ParseException ,
which occur in AppleMIDI.hpp:parseControlPackets() ,
based on UnexpectedData returned from AppleMIDI_Parser.h: parse() returning UnexpectedData
which it does for too many reasons: signature, protocolVersion, or not having previously returned something.
- Adding debugging code to
AppleMIDI_Parser.h revealed that most ParseExceptions were an unexpected and long signature.
- Added more debugging code to understand AppleMIDI_Parser
then MIDI traffic sometimes began flowing:
ESP-ROM:esp32s2-rc4-20191025
Build:Oct 25 2019
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3ffe6100,len:0x570
load:0x4004c000,len:0xa50
load:0x40050000,len:0x28d8
entry 0x4004c18c
wESP32_NoteOnOffEverySec.ino Booting
Establishing connection to WiFi..
Establishing connection to WiFi..
Establishing connection to WiFi..
Establishing connection to WiFi..
Establishing connection to WiFi..
Connected to network as 192.168.1.185
OK, now make sure an rtpMIDI session is Enabled
Add device named Arduino with Host 192.168.1.185 Port 5004
The device should also be visible in the directory as AppleMIDI-ESP32
Select and then press the Connect button
Then open a MIDI listener and monitor incoming notes
amSignature match
amSynchronization match
*** ParticipantNotFoundException -772189380
amSignature match
amSynchronization match
*** ParticipantNotFoundException -772189380
amSignature match
amSynchronization match
*** ParticipantNotFoundException -772189380
amSignature match
amInvitation match
amProtocolVersion match
amSignature match
amInvitation match
amProtocolVersion match
amSignature match
amInvitation match
amProtocolVersion match
Connected to session 3522777916 mnet (ALIENWARE-R7_144)
first MIDI.sendNoteOn()
MIDI-OX must connect to the configured MIDIHub port (e.g. MIDIHUB PORT 2 ) after
- Without Serial Monitor running and with MidiView already watching
MIDIHUB PORT 2 ,
MIDI traffic seems to flow OK..
- MIDIHub sometimes allows both MIDI_OX and MidiView
to simultaneously read
MIDIHUB PORT .
- Arduino ipMIDI Transport on
MIDIHUB PORT 1
The ESP32_NoteOnOffipMIDI
sketch seemed too simple to work with MIDIHub.. but it sometimes does.
It seems to work more consistently when Serial Monitor is used until notes start,
  then connecting MidiView to MIDIHUB PORT 1,
but it still (also) occasionally stops for no known reason..
This page describes IP routing magic for ipMIDI.
- Arduino ESP32 Sketch Data Upload tool installation
- Download the latest esp32fs.zip file
- Unzip
esp32fs.jar into arduino-1.8.16\tools\ESP32FS\tool\
- Launch Arduino and check for ESP32 Sketch Data Upload under Tools:
- Files to be uploaded should be in a
Data folder inside the sketch folder:
- Launch that tool after uploading the sketch,
then in Serial Monitor:   SPIFFS mounted successfully
take care to select SPIFF:  
 
- ESP32-SPIFFS-RGB-sliders uses WebSockets.
The Arduino server updates all webpage clients to current slider settings;
need to sort how to separately send binary MIDI to mnet MIDIHub
- midi-websocket-fa-m client connects to mnet MIDIHUb
and attempts to send MIDI to it (so far, unsuccessfully)
- NodeJS MIDI websocket server, for debugging the above MIDI websocket client
and perhaps capturing traffic from a mnet MIDIHub client
|