::CriAtomExPlayerOutputAnalyzer を用いて取得可能なスペクトル解析結果は、出力周波数の半分の周波数帯をコンフィグで指定したバンド数で等分割した値となります。
このため、例えば出力周波数48kHzのプラットフォームにて、デフォルトの「バンド数=8」という設定で解析を行った場合、先頭のバンドに約3kHzまでのスペクトラムがまとめられてしまい、他のバンドと比較して非常に大きな値になってしまいます。
以下では、市販のスペクトルアナライザのように、対数スケールで周波数を分割した解析結果を得る方法を解説します。
1. 指定可能な最大分割数でCriAtomExPlayerOutputAnalyzerを生成する
::CriAtomExPlayerOutputAnalyzer を、指定可能な最大バンド数(512)で生成します。
この値は ::CriAtomExPlayerOutputAnalyzer::MaximumSpectrumBands に定義されています。
2. 解析結果を取得して対数スケール周波数で再分割する
::CriAtomExPlayerOutputAnalyzer::GetSpectrumLevels 関数により最大バンド数で等分割された解析結果を取得した上で、対数スケールに再分割します。
以下のサンプルスクリプトでは、周波数を対数スケールで16分割した結果を計算しています。
デシベル値に変換した値に対して、適度にオフセットの設定やスケーリングを行って表示を行ってください。
using UnityEngine;
public class ExampleScript : MonoBehaviour {
public CriAtomSource atomSource;
public int outputSpectrumBands = 8;
private CriAtomExPlayerOutputAnalyzer analyzer;
private float[] linearSpectrumLevels;
private float[] logSpectrumLevels;
void Start ()
{
CriAtomExPlayerOutputAnalyzer.Type[] analyzerType = new CriAtomExPlayerOutputAnalyzer.Type[1];
CriAtomExPlayerOutputAnalyzer.Config[] analyzerConfig = new CriAtomExPlayerOutputAnalyzer.Config[1];
analyzerType[0] = CriAtomExPlayerOutputAnalyzer.Type.SpectrumAnalyzer;
analyzerConfig[0] = new CriAtomExPlayerOutputAnalyzer.Config(CriAtomExPlayerOutputAnalyzer.MaximumSpectrumBands);
this.analyzer = new CriAtomExPlayerOutputAnalyzer(analyzerType, analyzerConfig);
this.atomSource.AttachToAnalyzer(analyzer);
linearSpectrumLevels = new float[CriAtomExPlayerOutputAnalyzer.MaximumSpectrumBands];
logSpectrumLevels = new float[outputSpectrumBands];
}
void OnDestroy()
{
this.analyzer.DetachExPlayer();
this.analyzer.Dispose();
}
void Update ()
{
analyzer.GetSpectrumLevels(ref linearSpectrumLevels);
SplitBandsOnLogScale(ref linearSpectrumLevels, ref logSpectrumLevels);
for (int i = 0; i < logSpectrumLevels.Length; i++) {
logSpectrumLevels[i] = 20.0f * Mathf.Log10(logSpectrumLevels[i]);
}
}
private bool SplitBandsOnLogScale(ref float[] iLinearLvs, ref float[] oLogLvs)
{
if (iLinearLvs == null || oLogLvs == null )
return false;
float lowBand, highBand, tmpVal;
int lowBandIdx, highBandIdx, i, j;
int iBandCnt = iLinearLvs.Length;
int oBandCnt = oLogLvs.Length;
for (i = 0; i < oBandCnt; ++i)
{
lowBand = Mathf.Pow((float)iBandCnt, (float)i / (float)oBandCnt);
highBand = Mathf.Pow((float)iBandCnt, (float)(i + 1) / (float)oBandCnt);
lowBandIdx = Mathf.FloorToInt(lowBand) - 1;
highBandIdx = Mathf.FloorToInt(highBand) - 1;
tmpVal = 0;
for (j = lowBandIdx; j <= highBandIdx; ++j) {
tmpVal += iLinearLvs[j];
}
tmpVal = tmpVal / (float)(highBandIdx - lowBandIdx + 1);
oLogLvs[i] = tmpVal;
}
return true;
}
public void GetSpectrumLevels(out float[] result)
{
result = this.logSpectrumLevels;
}
}