West Hill 開発メモ

タグ:Audio

Unity上で楽曲をテンポ解析してBPMを推定する機能を作ってみました。

使い方
public AudioClip targetClip;

private void Start()
{
    int bpm = BpmAnalyzer.AnalyzeBpm(targetClip);
    Debug.Log("BPMは多分 " + bpm + " くらい");
}
AnalyzeBpmの中ではAudioClip.GetData()で取ってきたオーディオのサンプルデータを解析しています。

BpmAnalyzer.cs内で
サンプルデータをある程度で区切ってまとめるCreateVolumeArrayメソッドと、
実際にBPMを推定しているSearchBpmメソッドは、
処理時間が結構かかるので別スレッドから呼ぶように変更したほうが良いと思います。

※コルーチンみたいに使えるThread Ninja(Unity Asset Store)はおすすめ。
UnityEngine名前空間でもMathfなら別スレッドからでも呼べます。

また、例のシーンではメトロノームを使っていますが、実際の楽曲はテンポが動的に変わったりするので、万能ではないです。
楽曲を数秒おきに区切ってその範囲でBPMを推定する等が良いかもしれません。


参考
テンポ解析のアルゴリズム:
C/C++言語で音声ファイルのテンポ解析を行うサンプルプログラム 

AudioClip.GetDataで取れる値について:
このエントリーをはてなブックマークに追加 Clip to Evernote

UnityでオーディオをAudioClipから事前に解析する場合についてのメモ。
ss_audio_01
オーディオのサンプルデータはAudioClip.GetData
引数に入れた配列にサイズ分だけ取ってこれる。
※オーディオファイルのインポート設定がDecompress on Loadになっていないと取得できず、値が0の配列になる。

全データが必要な場合はサンプル数*チャンネル数分の配列を用意する。
//
// クリップの全サンプルデータ取得
float[] allSamples = new float[clip.samples * clip.channels];
clip.GetData(allSamples, 0);
第2引数はとってくるデータ開始位置までのオフセット。
秒数でオフセットを指定したい場合は秒数*サンプルレート*チャンネル数になる。
解析する際に数秒分のデータをスキップしたい時にもこの式が使える。
//
// オフセット2秒
float offset = 2f * clip.frequency * clip.channels;
AudioClip.GetDataで取得したデータは2chの場合、
LRLRLR…の順で-1~0と0~1の範囲に収まっていて、無音だと0になる。

このデータをゴニョゴニョした後、再生中にデータとの同期を取りたい場合、
再生中のオーディオソースからAudioSource.timeSamplesで現在の再生サンプル時間を取得できるので、これを使う。

このtimeSamplesでクリップからAudioClip.GetDataで取得した配列を参照する場合は、
timeSamples*チャンネル数が当該インデックスになる。
//
// 今ここ
float sample = samples[audioSource.timeSamples * clip.channels];

このエントリーをはてなブックマークに追加 Clip to Evernote

このページのトップヘ