1

マイクで録音した音声データから元の周波数を復元するなどの質問に取り組んでいます。

私の英語でごめんなさい...

この質問をより明確に説明させてください。次のコードIを使用して特定の周波数を生成しました。

void genTone() {
    numSamples = (int)(0.2 * sampleRate);   //duration * sampleRate;
    sample = new double[numSamples];
    generatedSnd = new byte[2 * numSamples];

    // fill out the array
    for (int i = 0; i < numSamples; ++i) {
        sample[i] = Math.sin(2 * Math.PI * i / (sampleRate/freqOfTone));
    }

    // convert to 16 bit pcm sound array
    // assumes the sample buffer is normalised.
    int idx = 0;
    for (final double dVal : sample) {
        // scale to maximum amplitude
        final short val = (short) ((dVal * 32767));
        // in 16 bit wav PCM, first byte is the low order byte
        generatedSnd[idx++] = (byte) (val & 0x00ff);
        generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
    }
}

そして、私は次のコードIIを使用してサウンドをリコアしました。

private void recordInBackground() {
    int read = 0;
    while (isRecording) {
        short data[] = new short[bufferSize];   // bufferSize = 4096

        read = audioRecorder.read(data, 0, bufferSize);
        if (read != AudioRecord.ERROR_INVALID_OPERATION) {
            try {
                float tempHammingRes[] = null;
                hamming(bufferSize);

                Complex[] complexs = new Complex[bufferSize];
                Complex[] results = new Complex[bufferSize];
                for (int i = 0; i < bufferSize; ++i) {
                    data[i] /= 32767; 
                    tempHammingRes[i] = tempHammingRes[i] * data[i];
                    complexs[i]= new Complex(tempHammingRes[i], 0);
                }

                results = FFT.fft(complexs);

                double highScore = 0.0;
                int freq = 1;

                for (int line = 1; line < bufferSize; ++line) {
                    double magnitude = Math.log(results[line].abs() + 1) / Math.log(10.0)*20.0;
                    if (magnitude > highScore) {
                        highScore = magnitude;
                        freq = line;
                    }
                }

                double currentFrequence = ComputeFrequency(freq, bufferSize);

                Log.d(TAG, "highScore = " + highScore + " freq = " + currentFrequence);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


}

ここで、コードブロックIIで、連続FFT計算間隔で同じ周波数が得られるという質問があります。たとえば、コードブロックIIから出力されるログがいくつかあります。

highScore = 151.77662972416104 freq =7999.5849609375//最初の8000

highScore = 146.33073029829455 freq = 7999.5849609375//2番目の8000

highScore = 146.44411729898255 freq = 9000.87890625

highScore = 144.43481176938155 freq = 9000.87890625

highScore = 142.78046692784702 freq = 10002.1728515625

highScore = 141.91874938214298 freq = 10002.1728515625

highScore = 136.47269911015098 freq = 11003.466796875

highScore = 136.6873278405228 freq = 11003.466796875

私は1つの8khzしか生成しませんでしたが、2つの音の周波数が得られます。また、出力トーンの持続時間を短くしたり、オーディオレコーダーの入力バッファーサイズを大きくしたりします。残念ながら、それは私がやりたいことを助けません。

私が間違っているのか、fftの出力がこのような性質のものであるのかを知っている人はいますか?

ご回答ありがとうございます!

4

2 に答える 2

1

ここにいくつかの潜在的な問題があります。私はあなたのコードを誤解している可能性がありますが、問題のように見えるので、これらのことについて言及します:

  1. ウィンドウ処理にもかかわらず、FFTには常に「サイドローブ」があります。この目的にはおそらく理想的なハミングウィンドウを選択しましたが、サイドローブを目撃している可能性があります。すべきではありませんが、genToneとrecordInBackgroundの間で何かが起こっている場合(たとえば、スピーカーからサウンドを再生して再録音している場合)、サイドローブデータをプライマリと同じくらい目立たせるのに十分なノイズと歪みが発生する可能性がありますデータ。

  2. FFTの結果を最後まで読んでいるようです。FFTの前半のみに関連する結果が含まれ、後半は前半の鏡像です。わずかな数値誤差のため、前半よりも後半の方が結果が大きくなる可能性があります。この問題は、周波数の計算が間違っている可能性があることも示唆しています。ここでこれをカバーします(そしてもっと!):fft別名ピッチを使用した周波数検出

  3. データをビットリバースしますが、入ってこないのです。何をしているのかによっては問題ないかもしれませんが、これだけのコードからは間違っています。FFTはそれを「透視」できますが、効果的に大量のノイズが発生します。

また、FFTの結果の絶対値の対数を計算しようとしていることにも気づきました。これは、計算に時間がかかるようにするためだけに役立ちます。あなたの目的のために、magnitude = results [line] .abs()は問題ありません。

于 2012-09-10T14:33:24.690 に答える
0

AudioRecorderが入力信号と同期していません。したがって、そこから取得するデータブロックがトーンを2つの部分に分割している可能性が非常に高くなります。そのため、同じ頻度で2つの連続したログを取得します。

于 2012-10-02T20:35:34.687 に答える