いつかは欲しい 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.py

MIDI 再生装置

あっさり、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秒ずらしているので、ちょっとギターっぽい。

もちろん、キーの同時押し再生も可能。

このままアルペジオとかできそう。