クーの自由研究

マスターのかえるのクーは、弟子達の召喚術により新たな依り代を得てⅡ世として復活しました。

自由研究の準備(その10)pythonライブラリのlibrosaで音楽を解析します

はじめに

LibROSAとは、音楽やオーディオ解析/分析のためのpythonパッケージです。

Brian McFee氏らにより開発され、現在も頻繁に改良されています。(2016/09時点の登録バージョンはpypi,Anaconda Cloudともに0.4.3)
開発者本人による説明(scipy2015での発表youtube)は自由研究の準備(その9)に貼りましたので参照してみてください。

MIRとは何でしょう?

LibROSAは「音楽情報検索 music information retrieval (MIR)」のための各種のモジュールを提供します。
MIRという技術/分野は日本でも注目されていますが、諸外国では音楽ビジネスや研究分野で「普通に」使われはじめている技術のようです。(この言い方は控えめすぎました。音処理に関してYoutubeSoundCloudはこの技術の「かたまり」です)

information retrieval はいわゆる「情報検索」ですが、日本語の「検索」よりも「取得」「抽出」のニュアンスが強い感じです。
音楽を条件検索するなどの「検索」以外にも、その音楽自体からいろいろな切り口の情報を取り出すオペレーションを含めて、そのように呼ばれているようです。
例えば

  • 聴く人に合った音楽を勧める(好みやシチュエーション、プレイリスト自動生成、よくある「これもどう?」購入斡旋)
  • 楽器の分離や楽器認識(ピアノの音だけ取り出すとか、シタールが使われている曲にラベル付けとか)
  • 自動採譜(好きな音楽を楽譜にしてくれるなんて素敵!)
  • 自動分類(いわゆるジャンル分け)
  • 音楽生成(なんと作っちゃうのもふくみます)
  • その他、インディースからのヒット(可能)曲発掘や売れそうなアーチスト開拓など音楽ビジネスへの応用(ビジネスしている方には、もっと「画一化」から「多様化」を誘導して欲しいなぁ。)


など、単なる「検索」以上の範囲まで含むようです。

LibROSAはどんなことができるの?

LibROSAは以下の主な機能があります。

  • 中核となる入出力機能とデジタル信号処理機能
  • 情報の表示機能(matplotlib機能を応用)
  • 特徴抽出(クロマグラム(12半音)分析や特徴量操作による楽曲データの変形)
  • オンセット特定(ハミング検索、断片検索とか、ひらたくいえばイントロあてドン)
  • ビートとテンポ(数値化や抽出)
  • スペクトログラム分離(周波数情報への分解)
  • エフェクト(元サウンドの変形)
  • 出力(エフェクト等オペレーション後の出力)
  • テンポを考慮したセグメント分け
  • 各種ユーティリティ
  • フィルタ機能

ライブラリ機能として機能毎にいくつものメソッドを持ち、機能間で相互に密接に関連しています。

インストールはどうやってやるの?

インストール

pip install librosa

で行えます。

どんな風に動くの?

それではチュートリアルを動かしてみましょう。本家はこちらです。

ビートを検出してみます

まずはチュートリアルのクイックスタートをやってみます。楽曲からビートを検出してCSV出力するサンプルです。


# ビートをトラッキング(分離)する例です。
from __future__ import print_function
import librosa

# 1. librosaで準備しているサンプル曲のファイル名を取得します。
filename = librosa.util.example_audio_file()

# 2. 波形情報を `y` へ、
# サンプリングレートを `sr` へ格納します。
y, sr = librosa.load(filename)

# 3. デフォルトの「ビートトラッカー」を実行します。
tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr)

print('Estimated tempo: {:.2f} beats per minute'.format(tempo))

# 4. ビートイベントの発生したフレーム索引をタイムスタンプ(先頭からの秒数)へ変換します。
beat_times = librosa.frames_to_time(beat_frames, sr=sr)

print('Saving output to beat_times.csv')
librosa.output.times_csv('beat_times.csv', beat_times)

Estimated tempo: 64.60 beats per minute
Saving output to beat_times.csv


と表示されました。(ボクのマシン環境のせいかubuntuでは動作し、Windowsではエラーが出ました。ubuntuでやってみたレポートとなります)。
あらかじめ準備されているサンプル曲が使われています。
example内にあるKevin_MacLeod_-_Vibe_Ace.oggが使われているようです。(どんな曲かは次のデモで貼ります)

このサンプルでは1分間に64.60 ビートであると導かれました。
beat_times.csv にはビート検出した時点の楽曲の開始からの秒数が出力されています。

中身をみてみます。


7.430
8.290
9.218
...
55.217
56.123
57.051


時間表示して音楽を聴きながらこの数字をみると、なるほどドラムがはいってくる前はビート検出されていないことがわかります。

oggファイル以外でも、audioread が読み込めるコーデックならなんでもよいようです。
手元のflacファイルでやってみましたが、OKでした。複雑なシンコペーションに惑わされることなくながらも、ほぼ正確にビート検出しています。
楽曲のスネアやバスドラムをわざと抜いているタイミングのところもビート検出しているので、他の楽器や前後のビートをみてうまくやっている感じがしています。(これは曲を貼れないのですません。お持ちの「これは無理だろう」という曲でやってみるのもおもしろいと思います。)
現在調整中なのか動かない機能(エラー)もあったので、今確認できる部分のみレポートしていきます。

Jupyter Notebookで動作するデモもあります

次はJupyter Notebookで動作するデモをやってみます。

共通部分を実行しておきます。


from __future__ import print_function
# 数学的操作をするので numpy が必要です。
import numpy as np

# グラフ表示のため、matplotlib を使います。
import matplotlib.pyplot as plt
import matplotlib.style as ms
ms.use('seaborn-muted')
%matplotlib inline

# オーディオ出力のために IPython.display を使います。
import IPython.display

# オーディオ解析にLibrosaを使います。
import librosa
# そして、表示のために display モジュールを使います。
import librosa.display

audio_path = librosa.util.example_audio_file()

# かわりに、下の行のコメントを外し貴方の好きな曲を設定してもいいですね。
# audio_path = '/path/to/your/favorite/song.mp3'

y, sr = librosa.load(audio_path)

変数 y には曲オブジェクトが設定されます。

jupyter(ipython)で曲を確認します。(下はJupyterNotebook表示のイメージです。)

f:id:np2LKoo:20160922025147j:plain

jupyter上のオーディオオブジェクトをそのまま貼れないので、かわりにsoundcloudに置いたものを張ります。(soundcloudにはoggファイルもそのままアップロードできました)

音の確認はこちらでお願いします。上のビートCSVサンプルや下のグラフを見ながら聞いてください

メルスケールのスペクトログラムを表示してみます

メルスケール(メル尺度)とはピッチ知覚の尺度です。スペクトログラムは声紋とよばれることもあり、音声、音響の分析によく使われます。横軸は時間で、縦軸は音の高さです。


# メルスケールのパワー(音圧)スペクトログラムのグラフを作って表示してみましょう。
S = librosa.feature.melspectrogram(y, sr=sr, n_mels=128)

# ログスケール(dB)に変換します。ピーク音圧を参照して使います。
log_S = librosa.logamplitude(S, ref_power=np.max)

# 新しい図を作ります。
plt.figure(figsize=(12,4))

# メルスケールのスペクトログラムを表示します。
# サンプルレートとホップ長のパラメータは時間軸の情報に使います。
librosa.display.specshow(log_S, sr=sr, x_axis='time', y_axis='mel')

# 図の上にタイトルをつけます。
plt.title('mel power spectrogram')

# カラーバーで描画します。
plt.colorbar(format='%+02.0f dB')

# 図はコンパクトに表示します。
plt.tight_layout()

f:id:np2LKoo:20160922024411j:plain最初のサンプルと同じ曲で、グラフでも最初の7秒すこしはドラムがはいっていないことがわかります。曲と一緒に聴くと、今の音は”このドットだ”というのがよくわかります。

和音とリズムを分離してみます


# effectsのhpssメソッドを使ってハーモニックとパーカッシブに分離します。
y_harmonic, y_percussive = librosa.effects.hpss(y)

# スペクトログラムはどのようになるでしょう?
# パワースペクトログラムを表示してみましょう。
S_harmonic = librosa.feature.melspectrogram(y_harmonic, sr=sr)
S_percussive = librosa.feature.melspectrogram(y_percussive, sr=sr)

# ログスケール(dB)に変換します. ピーク音圧を参照します。
log_Sh = librosa.logamplitude(S_harmonic, ref_power=np.max)
log_Sp = librosa.logamplitude(S_percussive, ref_power=np.max)

# 新しい図をつくります。
plt.figure(figsize=(12,6))

# メルスケールのスペクトログラムを表示します。
# 和音系です

plt.subplot(2,1,1)
librosa.display.specshow(log_Sh, sr=sr, y_axis='mel')
plt.title('mel power spectrogram (Harmonic)')
plt.colorbar(format='%+02.0f dB')

# リズム系です
plt.subplot(2,1,2)
librosa.display.specshow(log_Sp, sr=sr, x_axis='time', y_axis='mel')
plt.title('mel power spectrogram (Percussive)')
plt.colorbar(format='%+02.0f dB')

# 図をコンパクトに表示します。
plt.tight_layout()

librosa.effects.hpss()一発で和音とリズムを分離できます。グラフはこんな感じです。

f:id:np2LKoo:20160922032837p:plain

和音系の抽出音はこんな感じです。

ビブラフォンとベースのアタック音が一部パーカッション系にいっているのでま~るい感じになっています。利用者観点からすると、もう少し和音系からスネアとハイハットの高音部の分離がきれいにできればいいなと思います(ぜいたく)。

パーカッション系の抽出音はこんな感じです。

とてもうまく分離できているともいます。さすがに音が重なっているところは難しいですね。でも開発視点からすると、ものすごく頑張って作ってあると思います。

ソースを見て勉強させて頂きます。

音を再合成してみます

特定の周波数付近(高、中、低)を3つ再合成した例です。(長くなるのでソースは本家#Resynthesize. デモ参照してください。本家は高、中、低をそれぞれ個別に作成しています)

 

他のライブラリと共同作業してみましょう

mir_evalというライブラリを使用します。mir_evalは2014年に開催された第15回国際音楽情報検索(MIR)カンファレンスで公表されたようです。 craffelさんがメインでbmcfeeさんがサブ(コントリビュータ)で、お二方は知り合いのようです。インストール

pip install mir_eval

で行えます。

import mir_eval

# mir_evalの機能をつかって 最初に作ったbeat_times からクリック音を作ります
y_click = mir_eval.sonify.clicks(beat_times, sr, length=len(y))
# 元の音とクリック音を重ねてならしてみましょう
IPython.display.Audio(data=y + y_click, rate=sr)
# ついでにsaveしておきます
librosa.output.write_wav('click.wav', y + y_click, sr)

 最初迷って、スネアがはいるといい感じにリズムがとれて、スネアがぬけると途端に不整脈になるあたりがとても愛らしいです。

ほかにもいろいろありますので、興味のあるかたは是非本家チュートリアルをしてみてください。

世界の中心へ愛を叫んだけもの蛙(ボク)

自由研究の本編にいく予告に反し、librosaの内容を確認してました。サウンドで本編実験するにはあと、「(高速)フーリエ変換」(FFT)の確認が必要なので、まだ準備は続きます。

「王様の耳はロバの耳」という童話があります。最近ブログを書いていると、なぜかこの童話を思い浮かべます。「このブログは誰にも見てもらえていない」という思いが、「穴に向かって大声で何かを叫び、本当は誰かに聞いて欲しい」というところにつながっているのかもしれません。ボクの場合は古井戸の入り口から底へ「クー!」と叫ぶ感じでしょうか。このブログの唯一にして最大の読者はボク自身なので、まずはボクを満足させられるようがんばります。(誰もみてくれないのでいじけ気味です) 

(追記)読者登録していただけたのでボク自身が「唯一の読者」ではなくなりました。ばんざ~い。