2024年9月18日水曜日

MIDIファイルを入力とした分析補遺:ピアノロールデータの公開(2024.9.20更新)

1.本稿の背景

 マーラー作品のMIDI化状況についてのWebでの調査結果を2016年1月3日に公開後、2019年9月に「MIDIファイルを入力としたマーラー作品の五度圏上での重心遷移計算について」と題して、それまで実施してきた五度圏上での重心遷移計算の結果について報告するとともに、重心計算の元となったMIDIファイルから抽出した基本データについても公開しました。MIDIファイルからのデータ抽出や抽出されたデータの加工はC言語による自作のプログラムで、データ分析はR言語で行って来ました。近年機械学習やデータ分析はPython言語で構築されるのが一般的ですが、PythonでMIDIデータの操作をする場合にはpretty_midiIというライブラリを利用できることがわかった(書籍での紹介例としては、2023年10月発行の北原鉄朗『音楽で身につけるディープラーニング』, オーム社があります)ので調べてみると、pretty_midiIではMIDIデータの読み書きが出来るだけではなく、ピアノロール配列を作成する機能があり、更に拍(beat)毎、強拍(downbeat)毎のピアノロール配列の作成も容易にできることがわかりました。

 pretty_midiは、公式ページ(pretty_midi 0.2.10 documentation)によれば2014年の論文Colin Raffel and Daniel P. W. Ellis. Intuitive Analysis, Creation and Manipulation of MIDI Data with pretty_midi. In 15th International Conference on Music Information Retrieval Late Breaking and Demo Papers, 2014 で報告された時点でベータリリースされていたようですから、実は私がMIDIファイルを入力としたデータ分析を企図した時点で既に利用可能であり、最初から選択肢として存在していた筈なのですが、プログラミング言語としてはC言語が一番身近で、データ分析環境としてはR言語をずっと用いてきたこともあり、偶々当時、C言語でのMIDIデータの操作についての情報を取得できたことからC言語でプログラムを自作してしまったために、MIDIデータの操作に関して他の手段を調査するということをして来ませんでした。その後、本稿に直接関連するところでは、Google Magentaによる機械学習の実験をGoogle Colaboratory上で試行したことがきっかけで、Colaboratory上でPythonのコードに触れるようになりました。現時点ではMagentaをColaboratory上で動かすことができなくなってしまっていますが、その代替手段として自分でPythonのライブラリを使って機械学習の実験を行うことを企図しているうちに、既存のデータ分析もColaboratory上に統合できれば便利だと思うようになり、ようやくPythonでのMIDIデータの操作に関する調査を行うことにした、というのが経緯となります。

 早速Colaboratory上でpretty_midiIライブラリを使って、これまでマーラー作品の分析で用いてきたMIIDIファイルを読み込んで、ピアノロールを作成することができるようになり、更に拍(beat)毎、強拍(downbeat)毎のピアノロール配列の作成をして、結果をMIDIファイルとして出力することができるようになったのですが、テストしているうちに、基本セットのMIDIファイルの中に読み込みエラーが発生するものが出てきました。自作のC言語プログラムでは問題なく読めていたファイルであり、原因は個別に調査が必要ですが、自作のC言語プログラムの方は、こちらはこちらで読み込みエラーが発生するMIDIファイルが存在します。偶々、分析に利用している基本セットにはエラーが発生するファイルが含まれなかった、というよりは読み込みエラーが発生するようなファイルは除外するような形で基本セットを構成してきたということになりますが、MIDIファイルを作成した際のシーケンサ等のプログラムの仕様によるものか、全てのファイルが読み込める訳ではないというのは、現時点ではde facto standardであるpretty_midiIでも既に生じているし、今後更に別のファイルでも生じうる可能性はあるわけで、仮にpretty_midiIの仕様が機能的には完全に上位互換であったとしても、自作のプログラムは代替手段として無意味ではなさそうです。

 本ブログでの分析に関連する具体的なところでは、例えば第9交響曲第2楽章、第3楽章のMIDIファイルをpretty_midiIで読み込むとエラーが発生してしまうため、ピアノロール形式のデータの作成自体できませんので、自作のプログラムの出力結果で代替する他ありません。客観的には調査不足のために車輪の再発明をしてしまったということになるのかも知れませんが、結果的には全くの無意味というわけではなかったことになりそうです。更に言えば、他人の作成したライブラリに依存した環境だと、ある日突然動かせなくなるということが起きて困るというのは、Google Magentaのケースで経験したことですが、そうした懸念なく、自作のプログラムの不具合を気にするだけで集計・分析をやって来れたことを思えば、一定の意義があったという見方もできるように思います。

 ところがそう思って確認してみると、MIDIファイルから抽出した公開済の基本データ(MIDIファイルの分析:基本データにて公開)の中には、各種基本データの計算の入力となる、いわば元データに相当するものか含まれていません。しかも、もともと五度圏上での重心遷移計算が目的だったため、元データはピアノロール形式のデータ(MIDIノート0~127の各時点毎の出現を表す)ではなく、それをピッチクラスで集計したもの(12音の各時点毎の出現を表す)でした。そこで自作のC言語プログラムを数年ぶりに改造して、ピアノロール形式のデータをタブ区切りのファイルとして出力できるようにしたので、従来より分析に用いて生きたマーラーの作品のMIDIファイルの基本データセットについてその出力結果を公開することにしました。なお元々のピッチクラスで集計したデータについてはピアノロール形式のデータから容易に計算できるため公開データには含めません。一方で、ピアノロール形式のデータの更に元となる、MIDIファイルの解析結果自体(pretty_midiライブラリではpretty_midi.PrettyMIDIの各instrumentのNoteの情報に加え、key_signature_changes及びtime_signature_changesに相当する情報)については、別のところで述べたように元となったMIDIファイルの入手が既に困難になっている場合もあることから、その代替の役割を果たすことが考えられますが、こちらは既にMIDIファイルの分析:MIDIファイル解析結果のページで公開済です。

 その一方で、実際にはpretty_midiIのピアノロール形式取得の仕様は、これまで本ブログの分析で使用してきた自作のプログラムと同一ではなく、従って、今回公開するピアノロール形式のデータはpretty_midiIの関数get_piano_roll()で取得できるものとは細かい部分で異なりますので、単に共有データの仕様を記載するだけではなく、pretty_midiIの仕様との相違点について以下に記載することにします。


2.公開データの仕様

pianoroll.zipを解凍するとpianorollフォルダが収められており、その中には以下の作品のピアノロールファイルが収められています。

  • 第1~9交響曲(楽章毎):m1_1~m9_4
  • 第10交響曲クック版(楽章毎):m101~105
  • 交響曲「大地の歌」:erde_1~6
  • 歌曲集「さすらう若者の歌」:ges1~4
  • リュッケルト歌曲集(「私はやわらかな香りをかいだ」:duft、「私の歌をのぞき見しないで」:blicke、「真夜中に」:mitternacht、「美しさのゆえに愛するなら」:liebst、「私はこの世に忘れられ」:gekommen
  • 「魚に説教するパドヴァの聖アントニウス」:antonius、「夏の交替」:mahler_jugend-11、「ラインの小伝説」:rheinlegendchen,「美しいトランペットが鳴り響く所」:trompeten、「いま太陽は晴れやかに昇る」:nunwilld
元となったMIDIデータに関する情報は、同梱されたexperimental_MidiFileName.pdfに記載されています。

各楽章・曲毎に、各拍毎のピアノロール(APL)、各小節頭拍毎のピアノロール(BPL)に加え、参考データとして拍子の基本音符の1/4の長さ(4分音符を基本とする拍子なら16分音符)単位のピアノロール(PL)があります。例えば「私はやわらかな香りをかいだ」のピアノロールでは以下の通りになります。

  • duft_PL.out:拍子の基本音符の1/4の長さ(4分音符を基本とする拍子なので、16分音符)単位でサンプリングした結果のピアノロール
  • duft_APL.out:各拍(4分音符を基本とする拍子なので4分音符)単位でサンプリングした結果のピアノロール
  • duft_BPL.out:各小節単位(小節頭拍毎)でサンプリングした結果のピアノロール
ピアノロールファイルのフォーマットは各行が各時点に対応し、タブ区切りの各列がMIDIノート番号0~127の音が鳴っているかどうかを表します。各列の値は、音が鳴っていない場合は0、鳴っている場合はその音が鳴っているチャネルの数(その音を鳴らしている楽器の種類数)を表しています。

これをpretty_midiライブラリのget_piano_roll()の仕様と比べると、PLについてはget_piano_roll()の引数fs拍子の基本音符の1/4の長さ(基本音符が4分音符ならば16分音符)に相当する値を指定した時に計算されるピアノロールに対応し、APLおよびBPLについては、get_piano_roll()の引数timeに以下の指定をした時に計算されて返ってくるピアノロール形式のデータに概ね対応しています。(より正確には引数fsに渡すサンプリング周波数を、get_tempo_changes()が返す四分音符単位でのテンポの変更を加味した上で与えるべきでしょうが。)
  • APLの場合:get_beats()が返す、拍子の変化、テンポの変化を考慮した拍の位置(時点)のリストに基づいてtimeを指定した場合に概ね対応します。但し複合拍子の場合、get_beats()は3拍毎の位置を返す点が異なります。テンポの変化がなければfsに拍子のベースの音符に相当する値(4/4なら4分音符, 3/8なら8分音符)を指定したものと同じになります。一方、本記事で公開するピアノロールデータは、ベースの音符が異なる拍子が混在する場合には、音価の短い音符単位となります。例えば2/4と3/8が混在する作品の場合には、8分音符単位での出力となります。
  • BPLの場合:get_downbeats()が返す、拍子の変化、テンポの変化を考慮した強拍の位置(時点)のリストに基づいてtimeを指定した場合に対応します。
pretty_midiでは時点の指定が秒数に変換されて為されるのに対して、公開するデータを作成するプログラムはMIDIファイルにおけるTime Base(時間方向の分解能)に基づく時点の指定によって計算をしている点が異なりますが、恐らくその点は結果に大きく影響することはないものと思われます。一方で、ここで公開するピアノロール形式のデータ作成においては、サンプリングをする拍の先頭から基本の拍の1/8の音価(つまり4分音符なら32分音符)未満の遅延を許容し、かつ基本の拍の1/8の音価未満の持続で終わることなく、更に音の鳴り始めから鳴り終わりまでの持続が基本の拍の1/8の音価以上の音を、その拍で鳴っている音と判定することで、MIDIデータにしばしば生じる微妙なタイミングのずれに対して若干の頑健性を持たせています。(逆にその結果として、短い音価の音符で更にスタカート奏法などの指定があって実現される音価が32分音符より短い場合や装飾音、アルペジオの構成音などは拾えないことになります。)そのため各時点で音が鳴っているかどうかの判定基準の違いが結果の差異に影響する可能性があります。pretty_midiの仕様詳細はpretty_midiのソースコードを眺めればわかることですが、現時点では未調査です。拍毎、小節毎のサンプリングをしようとした場合に限っては、一旦秒数に変換してから処理するのは却って遠回りなように思えること、本稿で公開するピアノロールデータの仕様は、その如何に関わらず明確であるため、ここではpretty_midi側の詳細の深追いはしないことにします。

またget_piano_roll()が返すピアノロールデータでは音が鳴っている場所の数値(0でない正の値)は音量を表すのに対して、本稿で公開するピアノロールデータではその音を鳴らしている楽器の種類数を表している点が異なります。本ブログの分析においては、基本的にMIDIファイルに含まれる音量の情報は用いていません。また、今回対象となった作品は管弦楽作品なので大きな違いにはなりませんが、楽器がピアノの場合、本稿で公開するデータでは、サステインペダルに関するコントロール・チェンジ(CC64)は見ていません。pretty_midiのget_piano_roll()では引数pedal_thresholdでサステインペダルのON/OFFの閾値を与えることができ、サステインペダルの効果をピアノロールデータに反映することができます。

(2024.9.18公開,19記事、データとも更新、20サステインペダルに関して追記)。

[ご利用にあたっての注意] 公開するデータは自由に利用頂いて構いません。あくまでも実験的な試みを公開するものであり、作成者は結果の正しさは保証しません。このデータを用いることによって発生する如何なるトラブルに対しても、作成者は責任を負いません。入力として利用させて頂いたMIDIファイルに起因する間違い、分析プログラムの不具合に起因する間違いなど、各種の間違いが含まれる可能性があることをご了承の上、ご利用ください。

0 件のコメント:

コメントを投稿