Java で wav ファイルの基本周波数を検出するには、コム フィルター/変換を使用する必要があります。ZCRも実装する必要がありましたが、これは簡単でした。
今私はこれを持っています:
int best = 0, best_step = 0;
for (int step = 3; step < 400; ++step) {
int sum = 0;
for (i = 1; i < 10 && i * step < spectrum.length; ++i) {
for (int di = 0; di < i; ++di) {
sum += spectrum[i * step + di] / i;
}
}
sum *= 100;
comb.add(sum);
}
int sum = 0;
for (i = 0; i < comb.size(); ++i) {
sum = comb.get(i); // 3 * comb[i] - comb[i-1] - comb[i+1];
System.out.println(i + " - " + sum);
if (sum > best) {
best_step = i;
best = sum;
}
}
そして私の問題は、このコードが間違った周波数を検出することです。;( アルゴリズム/実装 (任意の言語) を検索しましたが、何も見つかりませんでした。
注、自己相関などは使用できません。くし型フィルタリングでなければなりません。
編集:私のコードのもう少しの説明:
wav ファイルを読み込み、フレームを配列フレームに配置します。次に、fft を作成し、Complex の配列 (widmo という名前) (複素数を処理するための単純な構造) を作成します。
次に、複素数の絶対値を配列スペクトルに入れます。
double[] spectrum = new double[widmo.length];
for (i = 0; i + 1 < widmo.length; ++i) {
spectrum[i] = widmo[i].abs();
}
ArrayList<Integer> comb = new ArrayList<Integer>();
int best = 0, best_step = 0;
for (int step = 3; step < 400; ++step) {
int sum = 0;
for (i = 1; i < 10 && i * step < spectrum.length; ++i) {
for (int di = 0; di < i; ++di) {
sum += spectrum[i * step + di] / i;
}
}
// sum /= step + 100; // ta linijka pozwala usunąć sporo
// niespodziewanych skoków częstotliwości
sum *= 100;
comb.add(sum);
}
int sum = 0;
for (i = 0; i < comb.size(); ++i) {
sum = comb.get(i); // 3 * comb[i] - comb[i-1] - comb[i+1];
// ctx.fillRect(i, canvas.height, 1, -sum);
System.out.println(i + " - " + sum);
// tmp.add(new freqTime(sum,));
if (sum > best) {
best_step = i;
best = sum;
}
}
System.out.println();
System.out.println(best_step);
System.out.println(4 * 44100);
System.out.println((frames.length / numChanels));
System.out.println(best_step * 44100
/ (frames.length / numChanels));
最後println
は私の基本周波数を表示するはずですが、そうではありません。
私は友人からJavaScriptでこれを手に入れました。