Tom*_*ica 5 audio fft guitar tuner
我得到了傅立叶变换的频谱。它看起来像这样:

警察刚从附近经过
颜色代表强度。
X 轴是时间。
Y 轴是频率 - 其中 0 位于顶部。
虽然吹口哨或警笛只留下一点痕迹,但许多其他音调似乎包含很多谐波频率。
电吉他直接插入麦克风(标准调音)
真正糟糕的是,正如你所看到的,没有主要的强度——有 2-3 个频率几乎相等。
我编写了一个峰值检测算法来突出显示最重要的峰值:
function findPeaks(data, look_range, minimal_val) {
if(look_range==null)
look_range = 10;
if(minimal_val == null)
minimal_val = 20;
//Array of peaks
var peaks = [];
//Currently the max value (that might or might not end up in peaks array)
var max_value = 0;
var max_value_pos = 0;
//How many values did we check without changing the max value
var smaller_values = 0;
//Tmp variable for performance
var val;
var lastval=Math.round(data.averageValues(0,4));
//console.log(lastval);
for(var i=0, l=data.length; i<l; i++) {
//Remember the value for performance and readibility
val = data[i];
//If last max value is larger then the current one, proceed and remember
if(max_value>val) {
//iterate the ammount of values that are smaller than our champion
smaller_values++;
//If there has been enough smaller values we take this one for confirmed peak
if(smaller_values > look_range) {
//Remember peak
peaks.push(max_value_pos);
//Reset other variables
max_value = 0;
max_value_pos = 0;
smaller_values = 0;
}
}
//Only take values when the difference is positive (next value is larger)
//Also aonly take values that are larger than minimum thresold
else if(val>lastval && val>minimal_val) {
//Remeber this as our new champion
max_value = val;
max_value_pos = i;
smaller_values = 0;
//console.log("Max value: ", max_value);
}
//Remember this value for next iteration
lastval = val;
}
//Sort peaks so that the largest one is first
peaks.sort(function(a, b) {return -data[a]+data[b];});
//if(peaks.length>0)
// console.log(peaks);
//Return array
return peaks;
}
Run Code Online (Sandbox Code Playgroud)
这个想法是,我遍历数据并记住一个大于阈值的值minimal_val。如果下一个look_range值小于所选值,则认为是峰值。这个算法不是很聪明,但是很容易实现。
但是,它无法判断字符串的主要频率,就像我预期的那样:

红点突出显示最强峰
这是一个 jsFiddle来看看它是如何工作的(或者更确切地说是不工作)。
您在弦乐音调频谱中看到的是在以下位置的谐波集合:
\n\n\n\n\nf0, 2*f0, 3*f0, ...
\n
f0 是基频或音调f0 是弦乐音调的
\n\n要从频谱(FFT 的输出,绝对值,可能是对数)估计 f0,您不应该寻找最强的分量,而是寻找距离所有这些谐波之间的
\n\n一种非常好的方法是对(绝对,实数)频谱进行第二次(逆)FFT。这会在 t0 == 1/f0 处产生一条强线。
\n\n由于Wiener\xe2\x80\x93Khinchin 定理,序列 fft -> abs() -> fft-1 相当于计算自相关函数(ACF)(ACF) 。
\n\n这种方法的精度取决于 FFT(或 ACF)的长度和采样率。如果使用sinc 函数在结果的采样点之间插入“真实”最大值,则可以大大提高精度。
\n\n为了获得更好的结果,您可以校正中间频谱:大多数声音具有平均粉红色频谱。如果你放大较高频率(根据逆粉红频谱),ACF 将会“更好”(它更多地考虑高次谐波,从而提高精度)。
\n