CRIWARE Unity Plugin Manual  Last Updated: 2024-07-12
将频谱分析结果转换为对数频率尺度
使用 CriWare.CriAtomExPlayerOutputAnalyzer 获得的频谱分析结果所分布在的频段是通过“输出采样率的一半除以配置中所指定的频段数量”得到的。
因此,例如在输出采样率为48kHz的平台上,如果使用默认设置“频段数 = 8”进行分析,则在第一个频段会集中3kHz左右以下的所有频谱成分,和其他频段相比,这将是一个非常大的值。
下面我们将解释如何通过对数尺度划分频率来获得分析结果,类似市售的频谱分析仪。

1. 使用可指定的最大分割数生成 CriAtomExPlayerOutputAnalyzer
使用可以指定的最大频段数(512)生成 CriWare.CriAtomExPlayerOutputAnalyzer
该值通过 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;
}
}