1

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でこれを手に入れました。

4

1 に答える 1

1

私はそれを理解します(私は思う:P)。最後のprintlnは基本的な周波数を提供します:)。多分誰かがそれを必要とするか、それを改善するでしょう:)

ArrayList<double[]> okna = new ArrayList<>();
            ArrayList<freqTime> lista = new ArrayList<freqTime>();

            int po2 = (int) Math.pow(2,
                    Integer.parseInt((String) potega2Input.getText()));

            po2 /= 2;
            double[] triangles = new double[po2];
            double maxWykres = 0;
            int licznik = 0;
            int licznik2 = 0;
            int T = frames.length;

            boolean wykresFlaga = false;

            for (int k = 0; k < T; k += po2) {

                licznik = 0;
                licznik2 = 0;
                double[] tmp = new double[po2];

                Complex[] zespolone = new Complex[po2];

                for (int i = k; i < k + po2; i++) {

                    if (i < T) {
                        tmp[licznik] = frames[i];
                        zespolone[licznik] = new Complex(frames[i], 0);
                        licznik2 = licznik;
                    } else {
                        tmp[licznik] = frames[licznik2];
                        zespolone[licznik] = zespolone[licznik2];

                    }
                    licznik++;
                }

                okna.add(tmp);

                FFT fft = new FFT();

                zespolone = fft.fft(zespolone);

                double maxF = 0;
                double maxFI = 0;

                double maxH = findMaxComp(zespolone);
                double[] doWykresu = new double[zespolone.length];
                for (int a = 2; a < 100; a++) {

                    for (int i = 0; i < po2; i++) {
                        doWykresu[i] = zespolone[i].abs();
                        triangles[i] =  Math.abs(i % (2 * a) - a)
                                * (maxH) / a;

                        // triangles[i] = Math.abs(i % (2 * a) - a) * (maxH)
                        // / a;

                    }

                    double sumT = 0;
                    for (int i = 0; i < po2 / 2; i++) {

                        sumT += triangles[i] * doWykresu[i];
                    }

                    if (sumT > maxF) {
                        maxF = sumT;
                        maxFI = a;
                    }

                }
                //
                // maxFI /= 2;
                //
                if (wykresFlaga == false) {
                    maxWykres = maxH;
                }
                for (int i = 0; i < po2; i++) {
                    doWykresu[i] = zespolone[i].abs();
                    triangles[i] =  Math.abs(i % (2 * maxFI) - maxFI)
                            * (maxWykres) / maxFI;

                }
                if (wykresFlaga == false) {
                    System.out.println("Max w widmie: " + maxWykres);
                    new Wykres(doWykresu, 1, triangles);
                    wykresFlaga = true;
                }
                // System.out.println((2 * 44100 / po2) * maxFI);
                System.out.println((float) (44100 / (float) po2)
                        * 2*(float) maxFI + " Znalzione a: " + maxFI);

                lista.add(new freqTime(
                        (int) ((float) (44100 / (float) po2) *2* (float) maxFI),
                        (double) ((double) po2 / 44100)));

                /*
                 * System.out.println((44100 / po2) * maxFI + " " + maxFI +
                 * " " + maxFI / 44100 + " " + 44100 / (maxFI / po2 * 44100)
                 * + " " + 44100 * maxFI / T);
                 */
                // System.out.println(zespolone[(int) maxFI/2].abs());
            }
于 2012-06-21T18:34:22.257 に答える