LoginSignup
10
5

MIDIキーボードをゲームのコントローラーにしてみた話

Last updated at Posted at 2022-12-20

音が出せるだけじゃないはず

MIDIキーボードは音楽活動に使われるイメージが大きいですが、仕組みを考えるともっと幅広い使い方ができるように思えます。一つ一つの鍵盤がスイッチだと考えれば、押したらオン、離せばオフのようなシンプルな仕組みと捉えられるはずです!
そこで今回は、実際にPythonを使ってMIDIキーボードの入力を取得して、いろいろと遊んでみました。

MIDI入力を取得する

まずはとにかく入力を見てみたいですよね。どんな仕組みでキーボードが動いているのか確認してみます。

pygame.midi

pygame.midiを使うと、PythonでMIDI入力を取得できるらしいです。
pygame自体はPythonではおなじみのゲーム制作ライブラリですが、その中にmidiを取得できる機能が付属していました。早速動作確認。

import pygame.midi as m

### midiキーボードを初期化
m.init()
i = m.Input( m.get_default_input_id() )

while True:
    if i.poll(): # MIDIを受信するとTrue

        # MIDI入力を取得
        midi_events = i.read(4)
        print(f'events: {midi_events}')

こんな感じに書くと、midi_eventsの中に取得したMIDI入力が入るらしい。

events:[[[status, data1, data2, data3], timestamp]]

events: [[[144, 67, 45, 0], 10]]
events: [[[248, 0, 0, 0], 20]]
events: [[[248, 0, 0, 0], 40]]
events: [[[144, 67, 0, 0], 55]]
...

status : オン(144)かオフ(248)
data1 : ノート番号(C:60 C♯:61 D:62 ...)
data2 : 音量(0 ~ 127)
data3 : チャンネル
timestamp : 経過時間

と意外にもいろんな情報が入ってました。それぞれ何か使えそうですね。

特定のキーをスイッチにしてみる

先ほど確認した入力をもとに、特定のキーをスイッチにしてprintさせてみます。

note = midi_events[0][0][1] # ノート番号

if note == 60: # C3
    print('hello')
hello
hello

設定したノート番号60、C3を一回だけ押してみました。あれ?
押した時に1回、離した時にもう1回反応しました。出力を確認すると、

events:[[[status, data1, data2, data3], timestamp]]

events:[[[144, 60, 50, 0], 10]]
events:[[[144, 60, 0, 0], 40]]

キーを離した時、同じ音を音量0で入力した扱いになっていることが分かりました。また気になるのが、statusは144でオン。ややこしい。
MIDIではキーを離した時も1つのイベントと捉えられるようです。はえー。

コードを修正

note, vol = midi_events[0][0][1:2] # 情報を取得

if vol != 0 and note == 60: # C3
    print('hello')
hello

キーを離した時音量は0になるので、音量が0でないことを確認するように修正したら、無事スイッチの形ができました。

コントローラーを作れるのでは

PCゲームは、マウスでの視点移動が必要なゲームを除けば、操作の全てがキーボードで完結します。またキーボードの操作も、wキーを長押しして前に移動、spaceキーでジャンプ、xキーで何かを発動するなど、キーの押し離しのみで非常にシンプルです。
ということは、midiキーボードはコントローラーとして使うことができるのでは...?と思いました。

仕組みを考える

PyAutoGUIを使って、PCのキーボードを直接制御することができます。
例えばpyautogui.press('x')でxキーを押せたり。
MIDIキーボードのキー1つ1つを新しいキーとしてPCに認識させるのは難しいので、今回はこれを使うことにしました。

# ド
if note == 60:
    key = 'x'

if note == 61:
...

# 長押し判定
try:
    if vol != 0:
        pyautogui.keyDown(key)
    else:
        pyautogui.keyUp(key)

except ValueError: # 何も押してない時
    pass

流石にコードを直す

1つ1つのキーで条件分岐していたらキリがないので、こんな感じのjsonで設定できるようにしました。

[
    {
        "midi" : 60,
        "key" : "f"
    },
    {
        "midi" : 61,
        "key" : "r"
    }
]

できた

完成した全コードはGitHubで配布してます。
使い方も記載したので、是非使ってみてください!

追記(2024/3/21): 全体的に動かなくなっていたので、仕様含め更新しました。

実際に動かしてみる(ゲームはMuseDash)
IMG_6598_AdobeExpress.gif
シンプルな操作の音ゲーなら簡単に対応できました。遅延も無く(ここすごい)長押しも問題なくゲームセンターの筐体のような感覚で遊べました!楽しい!
(マイクラにも挑戦中ですが、キー配置に苦戦中です...)

おわりに

意外にも操作性はかなり高く、音楽関係を超えた場面でのMIDIの可能性を感じました。もっといろんな使い方が見つかりそうです。
今家にあるMIDIキーボードは音の強弱にも対応しているので、その機能と組み合わせたゲームを自作するのもまた面白そうですね。
以上、ロマンをお届けしました!

10
5
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
5