Skip to content

Arduino MIDI Device

Arduino meets music

Hero image

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:

Terminal window
pip install mido
pip3 install python-rtmidi

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 = 440 \cdot 2^{(n-69)/12}

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

MIDI Note Number Note Names Frequency (Hz)
0 C(-1) 8.18
… … …
48 C3 130.81
49 C#3/Db3 138.59
50 D3 146.83
51 D#3/Eb3 155.56
52 E3 164.81
53 F3 174.61
54 F#3/Gb3 185.00
55 G3 196.00
56 G#3/Ab3 207.65
57 A3 220.00
58 A#3/Bb3 233.08
59 B3 246.94
60 C4 261.63
… … …
top of MIDI tuning range G#9/Ab9 13289.75

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.

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.

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.

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.

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.

MIDI Note Number Note Names Frequency (Hz)
0 C(-1) 8.18
1 C#(-1)/Db(-1) 8.66
2 D(-1) 9.18
3 D#(-1)/Eb(-1) 9.72
4 E(-1) 10.30
5 F(-1) 10.91
6 F#(-1)/Gb(-1) 11.56
7 G(-1) 12.25
8 G#(-1)/Ab(-1) 12.98
9 A(-1) 13.75
10 A#(-1)/Bb(-1) 14.57
11 B(-1) 15.43
12 C0 16.35
13 C#0/Db0 17.32
14 D0 18.35
15 D#0/Eb0 19.45
16 E0 20.60
17 F0 21.83
18 F#0/Gb0 23.12
19 G0 24.50
20 G#0/Ab0 25.96
21 A0 27.50
22 A#0/Bb0 29.14
23 B0 30.87
24 C1 32.70
25 C#1/Db1 34.65
26 D1 36.71
27 D#1/Eb1 38.89
28 E1 41.20
29 F1 43.65
30 F#1/Gb1 46.25
31 G1 49.00
32 G#1/Ab1 51.91
33 A1 55.00
34 A#1/Bb1 58.27
35 B1 61.74
36 C2 65.41
37 C#2/Db2 69.30
38 D2 73.42
39 D#2/Eb2 77.78
40 E2 82.41
41 F2 87.31
42 F#2/Gb2 92.50
43 G2 98.00
44 G#2/Ab2 103.83
45 A2 110.00
46 A#2/Bb2 116.54
47 B2 123.47
48 C3 130.81
49 C#3/Db3 138.59
50 D3 146.83
51 D#3/Eb3 155.56
52 E3 164.81
53 F3 174.61
54 F#3/Gb3 185.00
55 G3 196.00
56 G#3/Ab3 207.65
57 A3 220.00
58 A#3/Bb3 233.08
59 B3 246.94
60 C4 261.63
61 C#4/Db4 277.18
62 D4 293.66
63 D#4/Eb4 311.13
64 E4 329.63
65 F4 349.23
66 F#4/Gb4 369.99
67 G4 392.00
68 G#4/Ab4 415.30
69 A4 440.00
70 A#4/Bb4 466.16
71 B4 493.88
72 C5 523.25
73 C#5/Db5 554.37
74 D5 587.33
75 D#5/Eb5 622.25
76 E5 659.25
77 F5 698.46
78 F#5/Gb5 739.99
79 G5 783.99
80 G#5/Ab5 830.61
81 A5 880.00
82 A#5/Bb5 932.33
83 B5 987.77
84 C6 1046.50
85 C#6/Db6 1108.73
86 D6 1174.66
87 D#6/Eb6 1244.51
88 E6 1318.51
89 F6 1396.91
90 F#6/Gb6 1479.98
91 G6 1567.98
92 G#6/Ab6 1661.22
93 A6 1760.00
94 A#6/Bb6 1864.66
95 B6 1975.53
96 C7 2093.00
97 C#7/Db7 2217.46
98 D7 2349.32
99 D#7/Eb7 2489.02
100 E7 2637.02
101 F7 2793.83
102 F#7/Gb7 2959.96
103 G7 3135.96
104 G#7/Ab7 3322.44
105 A7 3520.00
106 A#7/Bb7 3729.31
107 B7 3951.07
108 C8 4186.01
109 C#8/Db8 4434.92
110 D8 4698.63
111 D#8/Eb8 4978.03
112 E8 5274.04
113 F8 5587.65
114 F#8/Gb8 5919.91
115 G8 6271.93
116 G#8/Ab8 6644.88
117 A8 7040.00
118 A#8/Bb8 7458.62
119 B8 7902.13
120 C9 8372.02
121 C#9/Db9 8869.84
122 D9 9397.27
123 D#9/Eb9 9956.06
124 E9 10548.08
125 F9 11175.30
126 F#9/Gb9 11839.82
127 G9 12543.86
top of MIDI tuning range G#9/Ab9 13289.75