PythonでMIDIを扱うために、MIDI機器からのMIDIイベントを逐次的にモニターできるものを探していました。pygameというモジュールが使えそうなので試してみることにします。
私の環境はWindows 10 Home, Python 3.8.6です。Pythonはwww.python.orgからダウンロードしました。pygameは以下のコマンドでインストールできます。
> pip install pygame
余談ですが、pipインストールで以下のようなSSLのエラーに遭遇しました。いろいろ試したのですがpythonをインストールし直すことでしか解決できませんでした。
ERROR: No matching distribution found for pprint Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming
the ssl certificate: HTTPSConnectionPool(host='pypi.org', port=443): Max retries
exceeded with url: /simple/pip/ (Caused by SSLError(SSLCertVerificationError
(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get
local issuer certificate (_ssl.c:1108)'))) - skipping
pygameのドキュメントは、www.pygame.orgにあります。以下に関数の簡単な説明を書いておきます。
以下にサンプルプログラムを掲載します。
import pygame.midi as m m.init() # MIDIデバイスを初期化 i_num=m.get_count() # MIDIデバイスの数 for i in range(i_num): print(m.get_device_info(i)) # MIDIデバイスの情報を表示 [結果] pygame 2.0.0 (SDL 2.0.12, python 3.8.6) Hello from the pygame community. https://www.pygame.org/contribute.html (b'MMSystem', b'Microsoft MIDI Mapper', 0, 1, 0) // 入力 (b'MMSystem', b'loopMIDI Port', 1, 0, 0) // 入力 (b'MMSystem', b'nanoKEY2', 1, 0, 0) // 入力 (b'MMSystem', b'Microsoft GS Wavetable Synth', 0, 1, 0) // 出力 (b'MMSystem', b'loopMIDI Port', 0, 1, 0) // 出力 (b'MMSystem', b'nanoKEY2', 0, 1, 0) // 出力
import pygame.midi as m m.init() i = m.Input(2) # デバイス番号を2とする while True: if i.poll(): # MIDIが受信されると1 midi_events = i.read(4) # 読み取る入力イベントの数 print ("midi_events:" + str(midi_events)) [結果] pygame 2.0.0 (SDL 2.0.12, python 3.8.6) Hello from the pygame community. https://www.pygame.org/contribute.html midi_events:[[[144, 48, 55, 0], 1396]] midi_events:[[[128, 48, 64, 0], 1644]] midi_events:[[[144, 48, 54, 0], 2331]] midi_events:[[[128, 48, 64, 0], 2495]] ... ...
このプログラムで、18バイトのSystem Exclusive (0xF0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xF7)を受信してみます。読み取る入力イベントの数を4と設定しているので、1回目は0xF0から0x0Eまでのは4x4の16バイト、2回目に0x0Fと0xF7の2バイトの2回に分けて受信します。
midi_events:[[[240, 0, 1, 2], 41131], [[3, 4, 5, 6], 41131],
[[7, 8, 9, 10], 41131], [[11, 12, 13, 14], 41131]] //1回目の受信 midi_events:[[[15, 247, 0, 0], 41131]] //2回目の受信
import pygame.midi as m m.init() i = m.Input(2) o = m.Output(0) while True: if i.poll(): # MIDIが受信されると1 midi_events = i.read(4) for j in range(len(midi_events)): status=midi_events[j][0][0] data1 =midi_events[j][0][1] data2 =midi_events[j][0][2] if(status==0x80 or status==0x90): #Note OnかOFFならMIDI送信 o.write_short(status,data1,data2) i.close()
import pygame.midi as m for note in range(128): print(note," : ",end="") print(m.midi_to_ansi_note(note)," : ",end="") print(m.midi_to_frequency(note), " Hz") [結果] ... 60 : C4 : 261.6 Hz 61 : C#4 : 277.2 Hz 62 : D4 : 293.7 Hz 63 : D#4 : 311.1 Hz 64 : E4 : 329.6 Hz 65 : F4 : 349.2 Hz 66 : F#4 : 370.0 Hz 67 : G4 : 392.0 Hz 68 : G#4 : 415.3 Hz 69 : A4 : 440.0 Hz 70 : A#4 : 466.2 Hz 71 : B4 : 493.9 Hz 72 : C5 : 523.3 Hz ...