はじめに
今回はmusic21のを用いてMIDIファイルの情報を抽出したり、操作したりする基本的な操作を紹介します。
MIDIファイルとは?
MIDIは、楽曲の演奏データが保存されたファイル形式のことです。
みなさんがイメージする音楽のファイル形式はmp3やwavが一般的だと思いますが、それらは演奏データではなく音声データです。
MIDIを演奏したときに出力される音声がmp3やwavになります。
music21とは?
music21は、pythonで音楽を扱うための音楽情報処理ライブラリです。
pythonでMIDIを扱う場合、他のモジュールとしてpretty_midiなどがありますが、MIDIファイルは情報が特殊なオブジェクトで保存されているので通常は扱いにくいことがあります。
music21はMIDIを読み取るだけでなく、作譜をしたりすることもできるので音楽処理には非常に優秀なライブリラリです。
インストールと環境構築に関してはこちらの記事がおすすめです。
MIDIを読み込む
まずはインポート
import music21 as m21
MIDIファイルを読み込みます。今回はかえるのうたの冒頭の演奏データが入ったMIDIを読み込みます。
path = './frog.mid'
frog = m21.converter.parse(path)
print(type(frog))
## <class 'music21.stream.base.Score'>
converter.parse()
を使うと、streamというオブジェクトに変換できます。
streamは楽譜データを格納できるオブジェクトになります。
MIDIファイルを使いたい場合はこちら
MIDIの可視化
show()
を使うとMIDIに格納されたデータをさまざまな形で可視化できます。
今回はその一例を紹介します。
楽譜
frog.show()
再生
専用の再生ディスプレイが出てきます。
pygame
をインストールしないと動かないことがあるので、実行する際はインストールしておきましょう。
frog.show('midi')
テキスト
MIDI内の情報の全様を{オフセット} <オブジェクト名>
としてテキスト表示します。
オフセットとは、四分音符の長さを1.0(quarterLengthといいます)としたとき、曲が始まってからどの位置にあるかを示す指標です。
次の項目で詳細を説明します。
frog.show('text')
## {0.0} <music21.metadata.Metadata object at 0x11edb10f0>
## {0.0} <music21.stream.Part 0x12a5de470>
## {0.0} <music21.stream.Measure 1 offset=0.0>
## {0.0} <music21.clef.TrebleClef>
## {0.0} <music21.tempo.MetronomeMark animato Quarter=120.0>
## {0.0} <music21.meter.TimeSignature 4/4>
## {0.0} <music21.instrument.Piano 'Piano'>
## {0.0} <music21.note.Note C>
## {1.0} <music21.note.Note D>
## {2.0} <music21.note.Note E>
## {3.0} <music21.note.Note F>
## {4.0} <music21.stream.Measure 2 offset=4.0>
## {0.0} <music21.note.Note E>
## {1.0} <music21.note.Note D>
## {2.0} <music21.note.Note C>
## {3.0} <music21.note.Rest quarter>
## {8.0} <music21.stream.Measure 3 offset=8.0>
## {0.0} <music21.note.Note E>
## {1.0} <music21.note.Note F>
## {2.0} <music21.note.Note G>
## {3.0} <music21.note.Note A>
## {12.0} <music21.stream.Measure 4 offset=12.0>
## {0.0} <music21.note.Note G>
## {1.0} <music21.note.Note F>
## {2.0} <music21.note.Note E>
## {3.0} <music21.note.Rest quarter>
## {4.0} <music21.bar.Barline type=final>
streamの内部構造
show('text')
で出力される内容はstreamの全体構造を表しています。
要約するとこんな感じになってます。
streamはlist型
と同じような仕様になっているので、append
やpop
を使って操作できます。
以下順に説明していきます。
stream.metadata
※こちらはmusic21のver8.1のアップデートにより追加されたオブジェクトです。
曲のタイトルや作曲者名・作成日付などを格納するオブジェクトらしいのですが、今回は扱わないので詳しい説明は省きます。
stream.Part
演奏パートのオブジェクトです。試しにかえるのうたに演奏パートを2つ追加してみましょう。
frog.append(m21.stream.Part())
frog.append(m21.stream.Part())
frog.show()
はい、追加されましたね。stream内では演奏パートごとに情報が格納されています。
stream.Measure
小節のオブジェクトです。1小節ごとに情報が格納されています。
len(frog[1])
## 4
frog[0]
はstream.metadataなので、frog[1]
が演奏パートになります。
4小節あるので、len
で数えると4になりますね。
こちらも試しに小節数を増やしてみましょう。
frog[1].append(m21.stream.Measure())
frog[1].append(m21.stream.Measure())
frog.show()
増えましたね。
終止線が動かないのは、かえるのうたの最後の小節に終止線のオブジェクトが残っているからですね。
note.Note / note.Rest
音符と休符のことですね。かえるのうたの2小節目だけをshow()
で見てみましょう。
frog[1][1].show('text')
## {0.0} <music21.note.Note E>
## {1.0} <music21.note.Note D>
## {2.0} <music21.note.Note C>
## {3.0} <music21.note.Rest quarter>
frog[1][1].show()
stream.Measure内にある最小オブジェクトのオフセットは、その小節が始まってからの位置を表します。
比較すると、楽譜通りの情報がテキストとして表示されているのがわかりますね。
その他のオブジェクト
小節内の最小オブジェクトは音符と休符だけではありません。
かえるのうたの1小節目だけをshow()
で見てみましょう。
frog[1][0].show('text')
## {0.0} <music21.clef.TrebleClef>
## {0.0} <music21.tempo.MetronomeMark animato Quarter=120.0>
## {0.0} <music21.meter.TimeSignature 4/4>
## {0.0} <music21.instrument.Piano 'Piano'>
## {0.0} <music21.note.Note C>
## {1.0} <music21.note.Note D>
## {2.0} <music21.note.Note E>
## {3.0} <music21.note.Note F>
frog[1][0].show()
音符以外の情報が入ってますね。これらの情報はsetup情報
として組み込まれます。
1小節目に必ず入っている情報で、あまりありませんが、曲の途中でテンポや拍子などが変化する箇所あると、その小節のオフセット{0.0}
に組み込まれます。
今回は軽く触れておきます。
clef.Clef
音部記号。ト音記号やヘ音記号のことです。
tempo.MetronomeMark
テンポ。BPMのことです。
meter.TimeSignature
拍子。何拍子/何拍のような表記ができます。
instrument.Instrument
楽器。ピアノやヴァイオリン、トランペットなどにすることもできます。
情報の抽出と操作
さて、ここまでの内容を理解した上で情報を抜きとったり変えたりする基本的な操作を紹介します。
キーの分析と変更
streamに対してanalyze('key')
を使うと、キーを解析してkey.Key
というオブジェクトで出力します。
この場合、C
だけを取り出したい場合、tonicPitchNameWithCase
を使います。
frog.analyze('key')
## <music21.key.Key of C major>
frog.analyze('key').tonicPitchNameWithCase
## 'C'
また、transpose( ,inPlace=True)
を使うと、第一引数に入力した整数だけキーを半音上げ下げできます。
frog.transpose(-1, inPlace=True) # キーを半音下げる (Bメジャーになる)
frog.show()
frog.transpose(2, inPlace=True) # キーを半音上げる (Cメジャーに戻る)
frog.show()
テンポの抽出
streamに対してmetronomeMarkBoundaries()
を使うと、stream内全てのテンポオブジェクトに関して(開始オフセット, 終了オフセット, tempo.MetronomeMark
のタプルが入ったリストが出力されます。
tempo.MetronomeMarkに対してnumber
を使うとfloat型
で取り出せます
frog.metronomeMarkBoundaries()
## [(0.0, 16.0, <music21.tempo.MetronomeMark animato Quarter=120.0>)]
tempo_metronomeMark = frog.metronomeMarkBoundaries()[0][2]
tempo_metronomeMark
## <music21.tempo.MetronomeMark animato Quarter=120.0>
tempo_metronomeMark.number
## 120.0
拍数・拍子の抽出
meter.TimeSignatureに対し、ratioString
を使うと、/
の表記が入った文字列で出力され、numerator
を使うと拍子(分子の数字)、denominator
を使うと拍数(分母の数字)を出力します。
meter_TimeSignature = frog[1][0][2]
meter_TimeSignature
## <music21.meter.TimeSignature 4/4>
meter_TimeSignature.ratioString
## '4/4'
meter_TimeSignature.ratioString = '3/4'
meter_TimeSignature.numerator
## 3
meter_TimeSignature.denominator
## 4
音符や休符情報の抽出
note.Noteに対して、name
を使うと、音階(ABC表記)を出力できます。
また、pitches[0].midi
を使うと、ノートナンバー(C4=60を基準とした音階の数値化)を出力できます。
for measure in frog[1]:
for item in measure:
if isinstance(item, m21.note.Note):
print(item, item.name ,item.pitches[0].midi)
## <music21.note.Note C> C 60
## <music21.note.Note D> D 62
## <music21.note.Note E> E 64
## <music21.note.Note F> F 65
## <music21.note.Note E> E 64
## <music21.note.Note D> D 62
## <music21.note.Note C> C 60
## <music21.note.Note E> E 64
## <music21.note.Note F> F 65
## <music21.note.Note G> G 67
## <music21.note.Note A> A 69
## <music21.note.Note G> G 67
## <music21.note.Note F> F 65
## <music21.note.Note E> E 64
全てのオブジェクトに対し、offset
を使うと、そのオブジェクトのオフセットを出力します。また、note.Note、note.Restに対してquarterLength
を使うと、四分音符を1.0としたときにどれぐらいの長さの音符・休符なのかを示す指標を出力します。
for measure in frog[1]:
for item in measure:
print(item.offset, item.quarterLength, item)
## 0.0 0.0 <music21.clef.TrebleClef>
## 0.0 0.0 <music21.tempo.MetronomeMark animato Quarter=120.0>
## 0.0 0.0 <music21.meter.TimeSignature 3/4>
## 0.0 1.0 <music21.note.Note C>
## 0.0 0.0 Piano
## 1.0 1.0 <music21.note.Note D>
## 2.0 1.0 <music21.note.Note E>
## 3.0 1.0 <music21.note.Note F>
## 0.0 1.0 <music21.note.Note E>
## 1.0 1.0 <music21.note.Note D>
## 2.0 1.0 <music21.note.Note C>
## 3.0 1.0 <music21.note.Rest quarter>
## 0.0 1.0 <music21.note.Note E>
## 1.0 1.0 <music21.note.Note F>
## 2.0 1.0 <music21.note.Note G>
## 3.0 1.0 <music21.note.Note A>
## 0.0 1.0 <music21.note.Note G>
## 1.0 1.0 <music21.note.Note F>
## 2.0 1.0 <music21.note.Note E>
## 3.0 1.0 <music21.note.Rest quarter>
## 4.0 0.0 <music21.bar.Barline type=final>
こんな感じにすれば○分音符・休符表記ができますね。
for measure in frog[1]:
for item in measure:
if isinstance(item, m21.note.Note):
print(str(4/item.quarterLength) + '分音符', item)
if isinstance(item, m21.note.Rest):
print(str(4/item.quarterLength) + '分休符', item)
## 4.0分音符 <music21.note.Note C>
## 4.0分音符 <music21.note.Note D>
## 4.0分音符 <music21.note.Note E>
## 4.0分音符 <music21.note.Note F>
## 4.0分音符 <music21.note.Note E>
## 4.0分音符 <music21.note.Note D>
## 4.0分音符 <music21.note.Note C>
## 4.0分休符 <music21.note.Rest quarter>
## 4.0分音符 <music21.note.Note E>
## 4.0分音符 <music21.note.Note F>
## 4.0分音符 <music21.note.Note G>
## 4.0分音符 <music21.note.Note A>
## 4.0分音符 <music21.note.Note G>
## 4.0分音符 <music21.note.Note F>
## 4.0分音符 <music21.note.Note E>
## 4.0分休符 <music21.note.Rest quarter>
終わりに
music21での演奏データの操作と処理の優秀さを実感しました。
今回はほんの一部を紹介しましたが、music21はこれだけではなくまだまだ更なる可能性を秘めています。
ぜひ興味のある方は自分なりに遊んでみてはいかがでしょう。
ここまで読んでくださりありがとうございました。
参考公式ドキュメント