RPi Pico でMIDIキーボード

目次
いつかは欲しい MIDI キーボード。
でも、どうせ弾けない(挫折済み)なので、プログラミングで解決する。
実際には、RPi Pico をMIDIキーボード(USB)にしてみる。
Pico の配線
GPIO2, GPIO3, GPIO4 にそれぞれスイッチを接続。 スイッチの反対側は、GNDに接続する。

これで、ソフトウェアPULL UPすれば、GPIOは、
- スイッチ押下でFalse
- スイッチフリーでTrue
となる。
MIDI Driver
CircuitPython のMIDIドライバを利用する。
ドキュメント
github
github から Code をzip download し、 adafruit_midi を Pico 上にコピーする。

サンプルプログラム1
GP2, GP3, GP4 を押すと、それぞれ C, D, E の音声が再生される。
midi_01.py · Gistpython
import time
import board
import digitalio
import busio
import usb_midi
import time
import adafruit_midi
from adafruit_midi.note_off import NoteOff
from adafruit_midi.note_on import NoteOn
class Button:
"""
Midi Key Button
"""
def __init__(self, pin, notes):
self.status = False
self.notes = notes
self.io_ = digitalio.DigitalInOut(pin)
self.io_.switch_to_input(pull=digitalio.Pull.UP)
def value(self):
return self.io_.value
#
# 3 button
#
Buttons = []
Buttons.append(Button(board.GP2, [60])) # middle C
Buttons.append(Button(board.GP3, [62])) # middle D
Buttons.append(Button(board.GP4, [64])) # middle E
# Set USB MIDI up on channel 0
midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0)
# key press LED
led = digitalio.DigitalInOut(board.GP25)
led.direction = digitalio.Direction.OUTPUT
while True:
# key press changing?
is_change = False
for button in Buttons:
if button.value() != button.status:
is_change = True
break
if is_change is False:
# nothing todo
time.sleep(0.1)
continue
is_press = False
for button in Buttons:
if button.value() != button.status:
# press or relase key
if button.value():
# LED off and sound off
for note in button.notes:
midi.send(NoteOff(note, 0))
else:
# LED on and sound on, velocity=100
is_press = True
for note in button.notes:
time.sleep(0.11)
midi.send(NoteOn(note, 100))
button.status = button.value()
led.value = is_pressサンプルの実行は、ampyで。
bash
ampy -p /dev/tty.usbmodem1XXXXX run midi_01.pyMIDI 再生装置
あっさり、Macを使う。 ソフトウェアは、GarageBand。
GrageBand を起動して、楽器を選択していれば自動的にMIDIキーボードを検出して、反応してくれる。

再生動画
和音の再生
サンプルプログラム2
midi_02.py · Gistpython
import time
import board
import digitalio
import busio
import usb_midi
import time
import adafruit_midi
from adafruit_midi.note_off import NoteOff
from adafruit_midi.note_on import NoteOn
c3 = 60
d3 = 62
e3 = 64
f3 = 65
g3 = 67
a3 = 69
b3 = 71
c4 = 72
d4 = 74
e4 = 76
class Button:
"""
Midi Key Button
"""
def __init__(self, pin, notes):
self.status = False
self.notes = notes
self.io_ = digitalio.DigitalInOut(pin)
self.io_.switch_to_input(pull=digitalio.Pull.UP)
def value(self):
return self.io_.value
#
# 3 button
#
Buttons = []
Buttons.append(Button(board.GP2, [c3, e3, a3])) # C major C/E/A
Buttons.append(Button(board.GP3, [g3, c3, d4])) # G major
Buttons.append(Button(board.GP4, [e3, g3, b3])) # E miner
# Set USB MIDI up on channel 0
midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0)
# key press LED
led = digitalio.DigitalInOut(board.GP25)
led.direction = digitalio.Direction.OUTPUT
while True:
# key press changing?
is_change = False
for button in Buttons:
if button.value() != button.status:
is_change = True
break
if is_change is False:
# nothing todo
time.sleep(0.1)
continue
is_press = False
for button in Buttons:
if button.value() != button.status:
# press or relase key
if button.value():
# LED off and sound off
for note in button.notes:
midi.send(NoteOff(note, 0))
else:
# LED on and sound on, velocity=100
is_press = True
for note in button.notes:
time.sleep(0.11)
midi.send(NoteOn(note, 100))
button.status = button.value()
led.value = is_pressせっかくなので、和音を再生してみる。
bash
ampy -p /dev/tty.usbmodem1XXXXX run midi_02.py各キーに、C, G, Em を割り当てる。
GarageBand で打ち込むと、こんな感じ。

1番目のトラックは、各和音の再生開始時間が同じ。 2番目のトラックは、各和音の再生開始時間を0.11秒ずらしているので、ちょっとギターっぽい。
もちろん、キーの同時押し再生も可能。
このままアルペジオとかできそう。
