Arduino MIDI Device

post hero image

Introduction

Arduino boards uses MIDIUSB library to interact as MIDI devices. Arduino board will use the code placed within Arduino Projects GitLab repository. Python control scripts use mido library, let’s open a terminal and install the required libraries:

pip install mido
pip3 install python-rtmidi

MIDI Notes Number

Notes number ranges from 0 to 127 (which is the range of seven bit data). These numbers relate directly to the note to be generated. The octave is indicated after the letter note name but to confuse things a bit, middle C on a piano (which is indicated by the MIDI note number 60) is sometimes designated as as C3 and sometimes as C4, depending on the manufacturer.

The frequency is evaluated assuming equal tuning based on A4 equal 440 Hz:

f=4402(n69)/12f = 440 \cdot 2^{(n-69)/12}

The full table is at the bottom of this post to allow a better readability.

MIDI Note NumberNote NamesFrequency (Hz)
0C(-1)8.18
48C3130.81
49C#3/Db3138.59
50D3146.83
51D#3/Eb3155.56
52E3164.81
53F3174.61
54F#3/Gb3185.00
55G3196.00
56G#3/Ab3207.65
57A3220.00
58A#3/Bb3233.08
59B3246.94
60C4261.63
top of MIDI tuning rangeG#9/Ab913289.75

MIDI Write

The board must communicate both when the pitch (note) starts and when it ends. The channel is set to 0 and the velocity to 64. Let’s take any MIDIUSB library compatible board and upload USBMIDI_write_test.ino sketch.

You can run a program like VMPK or Ardour 8 to see the MIDI notes being played. Remind to select the right MIDI device.

MIDI Read

Upload USBMIDI_read_test.ino sketch on the Arduino board. Open a terminal window and run the following python script:

#!/usr/bin/env python3

# ~~~ write-to-device.py ~~~

import mido # pip install mido
import time

if __name__ == "__main__":
    # get the list of all the MIDI devices conneted
    input_names = mido.get_input_names()

    # choose the name of the USB MIDI device
    # you want to send messages to
    usb_midi_device_name = input_names[1]

    try:
        # open the selected MIDI output port
        with mido.open_output(usb_midi_device_name) as port:
            print(f"Sending MIDI messages to {usb_midi_device_name}")

            # send Note On message
            note_on = mido.Message('note_on', note=60, velocity=64, channel=0)
            port.send(note_on)
            print(f"Note On sent: {note_on}")

            # wait for a short duration
            time.sleep(1)

            # send Note Off message
            note_off = mido.Message('note_off', note=60, velocity=64, channel=0)
            port.send(note_off)
            print(f"Note Off sent: {note_off}")

    except KeyboardInterrupt:
        print("Exiting...")

If you open the board’s Serial Monitor, you should see the note n° 60 being turned on and off.

Project Idea: you could build a matrix led that changes according to the given input MIDI signals.

MIDI Loop

Upload USBMIDI_loop_test.ino sketch on the Arduino board.

Open the first terminal window and run the following script to read the incoming MIDI messages:

#!/usr/bin/env python3

# ~~~ read-MIDI-device.py ~~~

import mido

if __name__ == "__main__":
    # list available MIDI ports
    input_names = mido.get_input_names()
    print(">>> available MIDI ports:")
    print(input_names)
    
    # select desired port
    # i.e. "Arduino MKR WiFi 1010:Arduino MKR WiFi 1010 MIDI 1 20:0"
    input_port_name = input_names[1]
    inport = mido.open_input(input_port_name)

    # loop to receive messages
    while True:
        for message in inport.iter_pending():
            print(message)

Then, open another terminal window and run the previously defined write-to-device.py Python script. You should now see the note n° 60 being turned on and off both on Arduino’s Serial Monitor and on the first terminal window.

Please Note: You can also run read-MIDI-device.py script to test MIDI Write section’s sketch.

Arduino MIDI Piano Project

Frizting schematic

The most easy usage of this schematic is sending a single note (starting from C3) for each switch button attached to the board. The following allows you to play one or more note until you press the corresponding buttons: USBMIDI_switch_btn_write.ino.


Let’s talk about the possibility of both sending singles notes, like it does, or whole chords with a single button. It’s amazing! You could use a couple of buttons to switch the main note (C, C#, …) and the remaining buttons to choose between a variety of chord types like major, minor, 7th, aug, dim, maj7, 5th (very punk) and many more.

Conclusion

MIDI Events

MIDI events are specified by status bytes, where the most significant 4 bits indicate the event type, and the least significant 4 bits specify the MIDI channel (if applicable). Here are the most common MIDI events along with their corresponding status bytes:

Note Off: stops the sounding of a note. Status byte range: 0x80 - 0x8F. Note Off on channel 1 is 0x80, channel 2 is 0x81, and so on.

Note On: starts the sounding of a note. Status byte range: 0x90 - 0x9F. Note On on channel 1 is 0x90, channel 2 is 0x91, and so on.

Aftertouch (Polyphonic Key Pressure): sends the pressure level of a single note. Status byte range: 0xA0 - 0xAF.

Control Change: changes the value of a control (e.g., modulation wheel, sustain pedal). Status byte range: 0xB0 - 0xBF.

Program Change: Selects a specific program (instrument) on a channel. Status byte range: 0xC0 - 0xCF.

Aftertouch (Channel Pressure): Sends the pressure level for all notes on a channel. Status byte range: 0xD0 - 0xDF.

Pitch Bend Change: Changes the pitch of all notes on a channel. Status byte range: 0xE0 - 0xEF.

System Exclusive (SysEx): used for manufacturer-specific messages. Status byte: 0xF0 (start) or 0xF7 (continued).

Timing Clock: used for synchronizing MIDI devices. Status byte: 0xF8.

Start Sequence: Starts the playback of a sequence. Status byte: 0xFA.

Continue Sequence: Continues the playback of a paused sequence. Status byte: 0xFB.

Stop Sequence: Stops the playback of a sequence. Status byte: 0xFC.

Active Sensing: Indicates that the MIDI device is still functioning. Status byte: 0xFE.

System Reset: Resets all MIDI devices in the system. Status byte: 0xFF.

These are the main MIDI events and their corresponding status bytes. They are used to control MIDI devices and communicate musical information in MIDI files and streams.

Full Table

MIDI Note NumberNote NamesFrequency (Hz)
0C(-1)8.18
1C#(-1)/Db(-1)8.66
2D(-1)9.18
3D#(-1)/Eb(-1)9.72
4E(-1)10.30
5F(-1)10.91
6F#(-1)/Gb(-1)11.56
7G(-1)12.25
8G#(-1)/Ab(-1)12.98
9A(-1)13.75
10A#(-1)/Bb(-1)14.57
11B(-1)15.43
12C016.35
13C#0/Db017.32
14D018.35
15D#0/Eb019.45
16E020.60
17F021.83
18F#0/Gb023.12
19G024.50
20G#0/Ab025.96
21A027.50
22A#0/Bb029.14
23B030.87
24C132.70
25C#1/Db134.65
26D136.71
27D#1/Eb138.89
28E141.20
29F143.65
30F#1/Gb146.25
31G149.00
32G#1/Ab151.91
33A155.00
34A#1/Bb158.27
35B161.74
36C265.41
37C#2/Db269.30
38D273.42
39D#2/Eb277.78
40E282.41
41F287.31
42F#2/Gb292.50
43G298.00
44G#2/Ab2103.83
45A2110.00
46A#2/Bb2116.54
47B2123.47
48C3130.81
49C#3/Db3138.59
50D3146.83
51D#3/Eb3155.56
52E3164.81
53F3174.61
54F#3/Gb3185.00
55G3196.00
56G#3/Ab3207.65
57A3220.00
58A#3/Bb3233.08
59B3246.94
60C4261.63
61C#4/Db4277.18
62D4293.66
63D#4/Eb4311.13
64E4329.63
65F4349.23
66F#4/Gb4369.99
67G4392.00
68G#4/Ab4415.30
69A4440.00
70A#4/Bb4466.16
71B4493.88
72C5523.25
73C#5/Db5554.37
74D5587.33
75D#5/Eb5622.25
76E5659.25
77F5698.46
78F#5/Gb5739.99
79G5783.99
80G#5/Ab5830.61
81A5880.00
82A#5/Bb5932.33
83B5987.77
84C61046.50
85C#6/Db61108.73
86D61174.66
87D#6/Eb61244.51
88E61318.51
89F61396.91
90F#6/Gb61479.98
91G61567.98
92G#6/Ab61661.22
93A61760.00
94A#6/Bb61864.66
95B61975.53
96C72093.00
97C#7/Db72217.46
98D72349.32
99D#7/Eb72489.02
100E72637.02
101F72793.83
102F#7/Gb72959.96
103G73135.96
104G#7/Ab73322.44
105A73520.00
106A#7/Bb73729.31
107B73951.07
108C84186.01
109C#8/Db84434.92
110D84698.63
111D#8/Eb84978.03
112E85274.04
113F85587.65
114F#8/Gb85919.91
115G86271.93
116G#8/Ab86644.88
117A87040.00
118A#8/Bb87458.62
119B87902.13
120C98372.02
121C#9/Db98869.84
122D99397.27
123D#9/Eb99956.06
124E910548.08
125F911175.30
126F#9/Gb911839.82
127G912543.86
top of MIDI tuning rangeG#9/Ab913289.75