CRIWARE Unity Plugin Manual  Last Updated: 2024-04-24
スペクトル解析結果を対数周波数スケールに変換する
CriWare.CriAtomExPlayerOutputAnalyzer を用いて取得可能なスペクトル解析結果は、出力周波数の半分の周波数帯をコンフィグで指定したバンド数で等分割した値となります。
このため、例えば出力周波数48kHzのプラットフォームにて、デフォルトの「バンド数=8」という設定で解析を行った場合、先頭のバンドに約3kHzまでのスペクトラムがまとめられてしまい、他のバンドと比較して非常に大きな値になってしまいます。
以下では、市販のスペクトルアナライザのように、対数スケールで周波数を分割した解析結果を得る方法を解説します。

1. 指定可能な最大分割数でCriAtomExPlayerOutputAnalyzerを生成する
CriWare.CriAtomExPlayerOutputAnalyzer を、指定可能な最大バンド数(512)で生成します。
この値は CriWare.CriAtomExPlayerOutputAnalyzer::MaximumSpectrumBands に定義されています。

2. 解析結果を取得して対数スケール周波数で再分割する
CriWare.CriAtomExPlayerOutputAnalyzer::GetSpectrumLevels 関数により最大バンド数で等分割された解析結果を取得した上で、対数スケールに再分割します。

以下のサンプルスクリプトでは、周波数を対数スケールで16分割した結果を計算しています。
デシベル値に変換した値に対して、適度にオフセットの設定やスケーリングを行って表示を行ってください。
public class ExampleScript : MonoBehaviour {
/* 解析対象の CriAtomSource */
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);
/* CriAtomSource にアタッチ */
this.atomSource.AttachToAnalyzer(analyzer);
/* CriAtomExPlayerOutputAnalyzerの出力結果を記録する配列 */
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;
}
}