如何从 FFT 中获取低音、中音、高音数据
Posted
技术标签:
【中文标题】如何从 FFT 中获取低音、中音、高音数据【英文标题】:How to get Bass, Mid, Treble data from FFT 【发布时间】:2015-01-28 02:10:23 【问题描述】:我是整个音频处理领域的新手,我想知道如何从 FFT 输出中提取低音、中音和高音。我目前正在使用它来获取数据:https://***.com/a/20414331/2714577 使用 Naudio。
但我使用的 fftlength 为 1024(需要速度)。出于颜色目的,我正在尝试以 0-255 等格式获取这 3 个部分。
我目前有这个:
double[] data = new double[512];
void FftCalculated(object sender, FftEventArgs e)
for (int j = 0; j < e.Result.Length / 2; j++)
double magnitude = Math.Sqrt(e.Result[j].X * e.Result[j].X + e.Result[j].Y * e.Result[j].Y);
double dbValue = 20 * Math.Log10(magnitude);
data[j] = dbValue;
double d = 0;
for (int i = 20; i < 89; i++)
d += data[i];
double m = 0;
for (int i = 150; i < 255; i++)
m += data[i];
double t = 0;
for (int i = 300; i < 512; i++)
t += data[i];
Debug.Message(""+d+" |||| "+m+" |||| "+t);
返回:
这是对的吗?如何将这些数据转化为更有用的东西?
【问题讨论】:
【参考方案1】:您从傅立叶变换中得到的系数可以是正数或负数 - 您感兴趣的是幅度(即每个频率的数量),因此您需要在求和中取绝对值。
另外,我建议标准化 - 在你的总结结束时这样做:
double total = data.Sum(x => Math.Abs(x));
d /= total;
m /= total;
t /= total;
这样,您的数字将被限制在 [0-1) 范围内,如果声音更小,您将获得相同的信息(除非您不希望这样)。实际上,范围会比这要小一些,因为您的每个求和都涵盖了较小的单个范围。因此,您可能希望按其中最大的一个来缩放它们:
double largest = Math.Max(d, m, t);
d /= largest;
m /= largest;
t /= largest;
现在每个值的范围应该在 0 到 1 之间。然后,您可以乘以 255 或 256,并根据需要截断小数点。
最后一步的缺点是如果值全为零(因为输入全为零),那么您将除以零。哎呀!在这一点上,你需要准确地决定你想要什么。如果你不做这个缩放,那么一个完全高音的声音(根据你上面的分解)将有 (0,0,1) for (d,m ,t)。但是对于 (d,m,t) 来说,三者均匀混合的声音将是 (0.3333, 0.3333, 0.3333)。完全安静的声音是(0,0,0)。如果这不是您想要的,那么您需要准确定义您想要什么,然后我才能进一步帮助您。
【讨论】:
【参考方案2】:您的dbValue
已经是一个很好的数字,以分贝为单位测量相对于 1.0 的电平变为 0.0 dB
您应该平均而不是求和各个(不同的dB值)频率。
然后将大约 -80db .. 0.0dB 的 dB 范围映射到您的颜色范围。
另请注意:语音和音乐往往具有平均粉红噪声频谱。这意味着低频往往比高频具有更高的 dB。 您应该补偿这种影响(可能在平均频率之前)以获得“更好”的显示。
【讨论】:
以上是关于如何从 FFT 中获取低音、中音、高音数据的主要内容,如果未能解决你的问题,请参考以下文章