【Unity】オーディオビジュアライザーをつくる
前回に続き音シリーズです。今回はマイク入力の周波数成分を視覚化してUnityで表示してみたいと思います。いわゆるオーディオビジュアライザーです。
環境
Unity 2019.4.5f1
1. スクリプト
以下のスクリプトを適当なオブジェクトにアタッチし、同オブジェクトにAudioSourceもアタッチします。アタッチ後、AudioSource設定のLoopにチェックを入れます。AudioSourceには音声信号をスペクトラム解析してくれるGetSpectrumDataメソッドが用意されているので、今回はこれを使用しています。
using UnityEngine;
class MicAudioSource : MonoBehaviour {
[SerializeField] private string m_DeviceName;
private const int SAMPLE_RATE = 48000;
private const int RESOLUTION = 1024;
private AudioSource m_MicAudioSource;
[SerializeField] private LineRenderer m_LineRenderer;
private readonly Vector3[] m_Positions = new Vector3[1024];
[SerializeField, Range(1, 300)] private float m_AmpGain = 300;
private void Awake() {
m_MicAudioSource = GetComponent<AudioSource>();
}
void Start() {
string targetDevice = "";
foreach (var device in Microphone.devices) {
Debug.Log($"Device Name: {device}");
if (device.Equals(m_DeviceName)) {
targetDevice = device;
}
}
Debug.Log($"=== Device Set: {targetDevice} ===");
MicStart(targetDevice);
// LineRenderer初期化
for (int i = 0; i < RESOLUTION; i++) {
var x = 10 * (i / 512f - 1);
m_Positions[i] = new Vector3(x, 0, 0);
}
m_LineRenderer.SetPositions(m_Positions);
Debug.Log($"Sample rate: {AudioSettings.outputSampleRate}");
}
void Update() {
DrawSpectrum();
}
private void DrawSpectrum() {
if (!m_MicAudioSource.isPlaying) return;
float[] spectrum = new float[RESOLUTION];
m_MicAudioSource.GetSpectrumData(spectrum, 0, FFTWindow.BlackmanHarris);
for (int i = 0; i < RESOLUTION / 2; i++) {
m_Positions[i].y = spectrum[i] * m_AmpGain;
}
m_LineRenderer.SetPositions(m_Positions);
}
private void MicStart(string device) {
if (device.Equals("")) return;
m_MicAudioSource.clip = Microphone.Start(device, true, 1, SAMPLE_RATE);
//マイクデバイスの準備ができるまで待つ
while (Microphone.GetPosition("") <= 0) { }
m_MicAudioSource.Play();
}
}
GetSpectrumDataの第一引数(spectrum)には2のべき乗のfloat配列を渡します。GetSpectrumDataが実行されると、spectrum配列には要素数をサンプリングレートで割った各周波数成分が格納されます。
ここでのサンプリングレートは、Microphoneで設定した値ではなくUnityプロジェクトに設定されているサンプリングレートが使用されます。
プロジェクトのサンプリングレートはメニューの[Edit] > [ProjectSettings]のAudio項目の「System Sample Rate」で設定します。
初めて確認する場合は「0」が入っていますが、設定的にはデフォルトで前回の値または、44100/48000が設定されているため、改めてこのウィンドウで任意の値を設定することができます。
デフォルトでどの値が設定されているかどうかは、以下のスクリプトで確認することができます。
AudioSettings.outputSampleRate
2. LineRendererの設定
スクリプトの設定が完了したら、次はビジュアル要素となるLineRendererの設定を行います。ヒエラルキー上に空のオブジェクトを配置し、LineRendererコンポーネントをアタッチします。
LineRendererの設定として、「Width」を0.05、「Materials」にDefault-Lineをアタッチします。色も適宜変えてみてください。この辺りはお好みで構いません。
重要な要素としては、LineRendererのPositionsの値をスクリプトのRESOLUTIONで設定した値と同じ1024にします。これで得られた周波数成分ごとにpointの位置を設定して視覚化させます。最後にLineRendererがアタッチされているオブジェクトのTransformが原点(0, 0, 0)にあることを確認して設定は完了です。
3. 実行
最初に実行するとコンソールログにMicrophoneデバイスの一覧が表示されるので、マイクとつながっているデバイス名をコピーし、作成したスクリプトのインスペクタの「m_DeviceName」に貼り付けます。
デバイス名を設定した状態で、一度実行を止めて再び実行してマイクに話しかけるとLineRendererで周波数成分を確認することができます。
Microphoneデバイスの指定を間違えると、デバイス準備完了待機のループでロックしてしまいUnity(エディタ)が固まってしまうので注意してください。
今回は解説用のためエラー処理は省いています。
スクリプトの項でも触れましたが、GetSpectrumDataで得られるデータは0Hz~指定サンプリングレートまでの値が入っているため、半分以上は可聴域やマイクの収音帯域を超えるデータとなっており、そのほとんどがゼロまたはとても小さい値になっています。
そのため、音のスペクトラムを視覚化する場合は、サンプリングレートの半分以上の配列データは切り捨てるなどして調整すると良いでしょう。(上記の動画では範囲を調整しています)
4. おわりに
音声信号のスペクトラム解析となると、フーリエ変換をする必要がありますが、AudioSourceのGetSpectrumDataを使うと簡単に周波数成分を得られることが分かりました。
音量の大小だけでなく周波数成分に応じた処理をさせることで、より高度なUnityと音の連携を行うことができるようになるので、インタラクティブな作品作りに活用してみたいですね。🌱
5. 参考
凹みさんの記事はいつもお世話になっています。
https://qiita.com/niusounds/items/b8858a2b043676185a54
この記事が気に入ったらサポートをしてみませんか?