niszetの日記

アナログCMOS系雑用エンジニアが頑張る備忘録系日記

(R) tuneRとggplot2で作るピアノロール風プロット(図差し替え…)

f:id:niszet:20171129001626p:plain# 既存パッケージだけでいけるじゃないですかー さて、tuneRというパッケージがあります。midiやwave、mp3を入力して色々出来るのですがあまり解説されている記事がないように思えます。

まぁ、今回はtuneRの解説はしないのですが…。需要があれば追々…。

TokyoR 64のLT、そして今回のHijiyamaR Final LTでtuneRでは…なのでrsmfを…とか言っていましたが、色々巡り巡ってtuneR+ggplot2でも出来ることに気づいたので責任とって解説書きます。

プロットしてみる。

さて、適当なmidiファイルは別途用意してみてください。midiデータには著作権があると思いますので、ご注意(例で使っているものはCC0扱いで公開されていたデータセットから)

コード例

コードは下記のようになります。tuneRパッケージ内の関数は明示的にtuneR::をつけていますが、libraryで読み込んでいますのでなくても動作します。

library(tuneR)
library(tidyverse)

mf <- tuneR::readMidi("hogehoge.mid")

mf %>% tuneR::getMidiNotes() %>% ggplot()+geom_segment(aes(
  x=time, y=note, xend=time+length, yend=note,
  color=as.factor(note %% 12), size=1)) + xlim(0, 50000)+
  xlab("time") +  ylab("note") + theme(legend.position="none")+
  scale_colour_brewer(palette = "Paired")

tuneR::readMidi は引数で与えたmidiファイルを読み、結果をdata.frameで返します。

tuneR::getMidiNotesは先の関数で得られたdata.frameのうち、Note(音符)情報だけを抜き出してdata.frameで返します。

曲中でテンポや拍子が変わることがあるのでそれも見ないと本当はいけませんが…割愛。

今回はシンプルに、音情報から音の高さと長さを、何も調整せずにプロットしてみます。

tuneRから得られるdata.frameの中身の説明?

上記コードの変数mf(readMidiで読んだdata.frame)をgetMidiNotes()に与えて得られるdata.frameの中身はこんな感じです。

  time length track channel note notename velocity
1 3840    240     2       0   70      a#'       92
2 4080    240     2       0   74      d''       92
3 4320    480     2       0   77      f''       92
4 4800    240     2       0   70      a#'       92
5 5040    240     2       0   75     d#''       92
6 5280    600     2       0   79      g''       92

midiにふくまれるヘッダやコントロール情報を除いて、note情報だけになりました。

一応、各列の簡単な解説…

timeはなり始めの時間、lengthはその音のなっている時間(長さ)
トラック、チャンネルはそれぞれトラック番号、チャンネル番号
noteは音の高さ、notenameはnoteの名前ですが、ドがC、レがD...です。'でオクターブ違いを表していますね。フラットはあるのだろうか?まだあまり調べ切れていません。 velocityは音量です。

なお、このlengthやtimeはheaderにある情報から何分音符を表しているかがわかるのですが、今回は割愛。

geom_segmentは始点と終点をx,yで指定するgeomです。あまり使うことはないのではないかな…。aesの引数でx,y,xend,yendを指定していますが、xに時間、yに音の高さを示していることになりますね。

colorにはas.factorした、noteを12で割ったあまりにしていますが、この12は1オクターブに含まれる、半音単位の音の数(C, C#, D, D#, E, F, F#, G, G#, A, A#, B)で、オクターブ違いを吸収しています(ドならオクターブうえでも同じ色)

xlab、ylabは軸ラベルですね。themeは凡例を消しています。

scale_colour_brewer(palette = "Paired")は単純に12音分の色があるパレットだったので、ここは任意の12色を指定してみてください。

まぁ、今回はnoteとtimeとlengthしか使わないのですが…。

出力結果

これで出力が下記のようになります。 f:id:niszet:20171128005641p:plain

おー。出来てしまった。

アレンジ

これをちょっと変更すると、、、

mf %>% tuneR::getMidiNotes() %>% ggplot()+geom_segment(aes(
  y=time, x=note, yend=time+length, xend=note,
  color=as.factor(note %% 12), size=1)) + ylim(0, 50000)+
  xlab("time") + ylab("note") + theme(legend.position="none")+
  scale_colour_brewer(palette = "Paired")

こんな感じ。縦が時間、横が音の高さとなってます

f:id:niszet:20171129001626p:plain (図のlabelが間違っていたので差し替えました@0:17)

なんか音ゲーっぽくなりましたね。

ということで、既存のパッケージから、LTで紹介したようなプロットが出来るという紹介でした。

テンポや拍子を考慮するのはちょっと工夫が必要そうですが、それはまた機会があれば。

Enjoy!!