DAW悪戦苦闘記

DAWやMIDIを通じてDTMを楽しむ記録。MIDI検定試験にもチャレンジするなり。

PythonでSMFを操作する (2) SysEx挿入

前回記事の続き(注: かなりマニアックです)。今回はトラック1の1小節目冒頭に所定のSysExメッセージを挿入してみる。

daw-jones.hatenablog.com

下準備

midoパッケージのインポートと、Studio One から書き出したサンプルのSMFファイルをmid変数に読み込むところまでやっておく。

from mido import MidiFile, Message

# 各トラック毎の全メッセージを表示する
def dump_track(track_obj):
    for msg in track_obj:
        print(msg)

# 全トラックの全メッセージをトラック毎に表示する
def dump_smf(midi_obj):
    for i, track in enumerate(midi_obj.tracks):
        print(f"Track {i}: {track.name}")
        dump_track(track)

# Studio One から書き出したSMFを mid に読み込む
mid = MidiFile('smf_studio1.mid')

対象トラックの抽出

SysExメッセージはトラック1に挿入したいと思うので、SMFオブジェクト(上例ではmid変数に格納)を構成するトラック・リストより、トラック1を抜き出して操作することにする*1

mid.tracksの中身を見れば、構成トラックは以下の通りに7件あるが、このうち最初の要素はメタイベント用のトラックなので、トラック1は2番目の要素("Oboe"というトラック名が付いている)ということになる。

f:id:daw_jones:20170716133626p:plain

したがって、トラック1を以下のように抜き出して変数代入する(リストのインデックスはゼロベースなので、2ではなくて1)。

# トラック1を抜き出して、変数"track1"に代入する
track1 = mid.tracks[1]

このトラックの中身は以下のようになっている(11行目以降は省略)。このメッセージ・リストの2番目の要素の直後(メタメッセージの直後)にSysExメッセージを挿入する。

f:id:daw_jones:20170716134356p:plain

メッセージ・オブジェクトの生成

メッセージ・データの作成は非常に簡単で、たとえばGM2音源使用オンのためのSysExメッセージは、以下の1行で済む*2。データ値は10進数のタプルで与える。ここは協会テンプレSMFを上記と同じくmidoパッケージを使って覗いてみた結果をそのままコピーすればよい。他セットアップ用のデータも同様である(次回以降詳述)。

# SysExメッセージの作成
msg = Message('sysex', data=(126, 127, 9, 3))

本メッセージをprintすれば、以下のように中身を表示確認できる。

f:id:daw_jones:20170716140156p:plain

なお、midoパッケージにおける各種MIDIメッセージの仕様については、公式ドキュメントを参照されたい。

メッセージの挿入

トラック・オブジェクトはリストのサブクラスで、要はメッセージのリスト構造になっているので、リスト操作のメソッドが適用可能である。したがって、上記メッセージの挿入は、そのものずばりinsertメソッドで入れてしまえばできあがりである。

# 上記SysExメッセージを2番目の要素の後ろに挿入する
track1.insert(2, msg)

挿入後のトラック1の中身は、以下のようになった(冒頭5行)。

f:id:daw_jones:20170716141707p:plain

*1:元のSMFオブジェクトmidを直接修正してもよいが、ここでは分かりやすくするために該当のトラック・オブジェクトを切り出して編集操作する。[ここからはマニアックな話] Pythonではリストなどのミュータブルなオブジェクトを変数に代入しても、それはオリジナルに対する参照になるため、実は変数track1の中身を操作すると元のmid.tracks[1]にも反映される。「Pythonのリストで参照渡しでないコピーを作成する話」などを参考。

*2:ここではデルタタイムはデフォルトのゼロのままでよい。