web-dev-qa-db-ja.com

Android audio FFTを使用して、audiorecordを使用して特定の周波数の大きさを取得します

現在、Androidを使用して、特定のオーディオ周波数範囲が電話のマイクを介して再生されるタイミングを検出するためのコードを実装しようとしています。AudioRecordクラス:

int channel_config = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int format = AudioFormat.ENCODING_PCM_16BIT;
int sampleSize = 8000;
int bufferSize = AudioRecord.getMinBufferSize(sampleSize, channel_config, format);
AudioRecord audioInput = new AudioRecord(AudioSource.MIC, sampleSize, channel_config, format, bufferSize);

次に、音声が読み込まれます。

short[] audioBuffer = new short[bufferSize];
audioInput.startRecording();
audioInput.read(audioBuffer, 0, bufferSize);

この分野での経験が非常に少ないため、FFTを実行することで立ち往生しています。私はこのクラスを使用しようとしています:

JavaのFFT および それに付随する複雑なクラス

その後、次の値を送信しています。

Complex[] fftTempArray = new Complex[bufferSize];
for (int i=0; i<bufferSize; i++)
{
    fftTempArray[i] = new Complex(audio[i], 0);
}
Complex[] fftArray = fft(fftTempArray);

これは、このクラスがどのように機能するかを誤解しやすいのですが、返される値はあちこちに飛び回っており、沈黙の中でさえ一貫した頻度を表していません。このタスクを実行する方法を知っている人はいますか、それともグラフィカル表現として描画するのではなく、少数の周波数範囲のみを取得しようとする問題を過度に複雑にしていますか?

38
user723060

まず、取得する結果がfloat/doubleに正しく変換されることを確認する必要があります。 short []バージョンがどのように機能するかはわかりませんが、byte []バージョンは生のバイトバージョンのみを返します。このバイト配列は、浮動小数点数に適切に変換する必要があります。変換のコードは次のようになります。

    double[] micBufferData = new double[<insert-proper-size>];
    final int bytesPerSample = 2; // As it is 16bit PCM
    final double amplification = 100.0; // choose a number as you like
    for (int index = 0, floatIndex = 0; index < bytesRecorded - bytesPerSample + 1; index += bytesPerSample, floatIndex++) {
        double sample = 0;
        for (int b = 0; b < bytesPerSample; b++) {
            int v = bufferData[index + b];
            if (b < bytesPerSample - 1 || bytesPerSample == 1) {
                v &= 0xFF;
            }
            sample += v << (b * 8);
        }
        double sample32 = amplification * (sample / 32768.0);
        micBufferData[floatIndex] = sample32;
    }

次に、micBufferData []を使用して入力複素数配列を作成します。

結果を取得したら、結果で複素数の大きさを使用します。実際の値を持つ周波数を除き、ほとんどの強度はゼロに近いはずです。

配列インデックスをそのような大きさの周波数に変換するには、サンプリング周波数が必要です。

private double ComputeFrequency(int arrayIndex) {
    return ((1.0 * sampleRate) / (1.0 * fftOutWindowSize)) * arrayIndex;
}
33
shams