Pythonのmidiライブラリ「mido」でコード解析ツールを作った

Python

Pythonでmidiデータを扱うのに便利なライブラリ「mido」と、それを使って作ったコード進行自動解析ツールを紹介します。

プログラマ且つDTMerの人はmidiをプログラミング言語からコントロールしてみると結構楽しいですよ。

レポジトリはこちら

ツール本体の解説は記事の後半にあります。

midoの使い方の基本

ファイルを開く

DAWを使っているとmidiファイルを直接触らないため、自前のマルチトラックのファイルがありませんでした。
なのでネットでたまたま見つけたoasisのmidiファイルを開きます。
file.tracksは文字通りmido.MidiTrackのリストです。

トラックの削除

2本入っているアコギがまったく同じトラック名なのが気に食わないので削除します。

トラック、メッセージの追加

トラックもmido.Messageのリストのように扱えます。

Messageにはノートオン・オフやCCなどの演奏用のメッセージと、トラック名やテンポなどを示すメタメッセージがあります。
timeというのは絶対時間ではなく、前のメッセージからの経過時間です。

ファイルの保存

上で行ったトラックやノートの追加はあくまでもメモリ上での動作なので、ファイル自体は一切変更されていないことに気をつけなければいけません。

元のファイルに上書きする際はこのコードでOKです。

file.save('oasis.mid')

別ファイルに保存する場合は別の名前をつけましょう。

その他の使い方

コード進行解析のために必要だったのは既存のファイルの取り扱いだけだったので、私は他の利用方法は試していません。

ただmidiポートを開いてリアルタイムで送受信することもできるようですし、SysExにも対応しています。

何かおもしろいものができたら私に教えてください!

コード進行解析ツールの解説

コード解釈ライブラリ

与えられたmidiノートから何のコードか判断するライブラリとして、
PyChoreを使用しています。

5年前に開発が止まっているしPython3にも対応していないんですが、色々試した中で一番無難なコード解釈をしてくれると思って採用しました。

music21pychordも試しました。

music21はどんな複雑なコードにも名前をつけてくれるんですが、
combinatorial I (I1)
とか
Stravinsky’s Petrouchka-chord
なんて返ってきても反応に困りますよね?
(I1ってなに?)

pychordは逆に黙っちゃうことが多いし・・・。

そういうわけでPyChoreをPython3コードに自動変換して使用することにしました。

解析方法

機械学習なんかは全く取り入れていないので、

「たくさんあるmidiノートの中からどれをコードトーンとして選ぶか」

の基準は自分で明確に決めて実装する必要があります。

私が基準として使ったのは、単純ですが

「設定された時間区分の中で多くの時間を占めているかどうか」

です。

1小節なら1小節のなかで、一番鳴っている時間が長いmidiノートの上位複数を抜き出し、PyChoreのアルゴリズムに突っ込んで結果を得ています。
(1小節にするか2拍にするか、ノートをいくつ抜き出すかはコマンドライン引数で設定します)

いくつか特徴:

  • PyChoreは展開系をonコードと解釈することが多いので、その場合はルートを省く
  • 曲の頭の「空白=>グリッサンド」なんかがコードとして認識されないように、極端に短いノートは除く
  • 無音の小節はBLANK、PyChoreが解釈できないコードは構成音をそのまま表示する

出力

とりあえず「コード4つのリストのリスト」で出しています。
4に理由はありません。4小節ならとりあえず見やすいと思っただけです。

精度

ここが一番気になるところだと思います。

自分で何曲か試してみましたが、まあまあ良いんじゃないでしょうか?

ルートを精確に把握しているわけではないので正しいコードネームではないと思います。
でも、当然ですが実際に鳴っている音を拾っているので、表示されたコードを演奏しておけばおかしなことにはならないはずです。

まとめ

プログラムはPythonのワンライナー(?)にハマってたときに書いたやつなので正直すごく読みにくいと思います。
アルゴリズムの改善点なんかがあれば連絡ください。

オーディオからコード解析するわけではないので「めちゃ便利!」ではないですが、適当に弾いたmidiデータのコード進行を拾うのが面倒なときなんかに使っていただけたらと思います。