Android аудио FFT для отображения основной частоты - PullRequest
4 голосов
/ 30 ноября 2011

Я некоторое время работал над проектом Android, который отображает основную частоту входного сигнала (в качестве тюнера). Я успешно реализовал класс AudioRecord и получаю от него данные. Однако мне трудно выполнить БПФ для этих данных, чтобы получить основную частоту входного сигнала. Я просматривал сообщение здесь и использую FFT в Java и Сложный класс , чтобы использовать его.

Я успешно использовал функцию FFT, найденную в FFT в Java, но я не уверен, что получаю правильные результаты. Для величины БПФ (sqrt [re re + im im]) я получаю значения, которые начинаются с высокой, около 15000 Гц, а затем медленно уменьшаются до примерно 300 Гц. Не кажется правильным.

Кроме того, что касается необработанных данных с микрофона, данные кажутся нормальными, за исключением того, что первые 50 значений или около того всегда являются числом 3, если только я снова не нажму кнопку настройки, пока еще в приложении, а затем получить только около 15. Это нормально?

Вот немного моего кода.

Прежде всего, я конвертирую короткие данные (полученные с микрофона) в двойные, используя следующий код из поста , который я просматривал . Этот фрагмент кода мне не совсем понятен, но я думаю, что он работает.

//Conversion from short to double
double[] micBufferData = new double[bufferSizeInBytes];//size may need to change
final int bytesPerSample = 2; // As it is 16bit PCM
final double amplification = 1.0; // choose a number as you like
for (int index = 0, floatIndex = 0; index < bufferSizeInBytes - bytesPerSample + 1; index += bytesPerSample, floatIndex++) {
    double sample = 0;
    for (int b = 0; b < bytesPerSample; b++) {
        int v = audioData[index + b];
        if (b < bytesPerSample - 1 || bytesPerSample == 1) {
            v &= 0xFF;
        }
        sample += v << (b * 8);
    }
    double sample32 = amplification * (sample / 32768.0);
    micBufferData[floatIndex] = sample32;
}

Затем код продолжается следующим образом:

//Create Complex array for use in FFT
Complex[] fftTempArray = new Complex[bufferSizeInBytes];
for (int i=0; i<bufferSizeInBytes; i++)
{
    fftTempArray[i] = new Complex(micBufferData[i], 0);
}

//Obtain array of FFT data
final Complex[] fftArray = FFT.fft(fftTempArray);
final Complex[] fftInverse = FFT.ifft(fftTempArray);

//Create an array of magnitude of fftArray
double[] magnitude = new double[fftArray.length];
for (int i=0; i<fftArray.length; i++){
    magnitude[i]= fftArray[i].abs();
}


fft.setTextColor(Color.GREEN);
fft.setText("fftArray is "+ fftArray[500] +" and fftTempArray is "+fftTempArray[500] + " and fftInverse is "+fftInverse[500]+" and audioData is "+audioData[500]+ " and magnitude is "+ magnitude[1] + ", "+magnitude[500]+", "+magnitude[1000]+" Good job!");
for(int i = 2; i < samples; i++){
    fft.append(" " + magnitude[i] + " Hz");
}

Этот последний бит просто для проверки, какие значения я получаю (и чтобы держать меня в здравом уме!). В упомянутом выше посте говорится о необходимости частоты дискретизации и даётся следующий код:

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

Как мне реализовать этот код? Я не совсем понимаю, откуда fftOutWindowSize и arrayIndex?

Любая помощь очень ценится!

Дастин

Ответы [ 3 ]

3 голосов
/ 23 января 2013

В последнее время я работаю над проектом, который требует почти того же. Возможно, вам больше не нужна помощь, но я все равно выскажу свои мысли. Возможно, кому-то это понадобится в будущем.

  1. Я не уверен, работает ли функция short to double, я тоже не понимаю этот фрагмент кода. Записано для преобразования байта в двойное число.
  2. В коде: "double[] micBufferData = new double[bufferSizeInBytes];" Я думаю, что размер micBufferData должен быть "bufferSizeInBytes / 2", поскольку каждая выборка занимает два байта, а размер micBufferData должен быть номером выборки.
  3. Алгоритмы БПФ требуют размера окна БПФ, и это должно быть число, которое является степенью 2. Однако многие алгоритмы могут получить произвольное число в качестве входных данных, и они сделают все остальное. В документе эти алгоритмы должны иметь требования ввода. В вашем случае размер массива Complex может быть вводом алгоритмов FFT. И я действительно не знаю деталей алгоритма FFT, но я думаю, что обратный алгоритм не нужен.
  4. Чтобы использовать код, который вы дали наконец, вы должны сначала найти индекс пика в массиве образцов. Я использовал двойной массив в качестве ввода вместо Complex, поэтому в моем случае это что-то вроде: double maxVal = -1;int maxIndex = -1;

    for( int j=0; j < mFftSize / 2; ++j ) {
        double v = fftResult[2*j] * fftResult[2*j] + fftResult[2*j+1] * fftResult[2*j+1];
        if( v > maxVal ) {
            maxVal = v;
            maxIndex = j;
        }
    }
    

    2 * j - действительная часть, а 2 * j + 1 - мнимая часть. maxIndex - это индекс требуемой пиковой величины (подробнее здесь ), и используйте его как вход для функции ComputeFrequency. Возвращаемое значение - это частота требуемого массива выборок.

Надеюсь, это кому-нибудь поможет.

2 голосов
/ 23 января 2013

Я подозреваю, что странные результаты вы получаете, потому что вам может понадобиться распаковать FFT.Как это сделать, будет зависеть от используемой вами библиотеки (см., Например, здесь , чтобы узнать, как она упакована в GSL).Упаковка может означать, что реальные и мнимые компоненты не находятся в ожидаемых вами позициях в массиве.

Если у вас есть другие вопросы о размере и разрешении окна, если вы создаете тюнер, я бы посоветовалпробуем размер окна около 20 мс (например, 1024 сэмпла при 44,1 кГц).Для тюнера вам нужно довольно высокое разрешение, чтобы вы могли попробовать заполнение нулями с коэффициентом 8 или 16, что даст вам разрешение 3-6 Гц.

2 голосов
/ 30 ноября 2011

Вы должны выбрать размер окна FFT в зависимости от ваших требований к временному разрешению, а не просто использовать размер аудиобуфера при создании временного массива FFT.

Индекс массива - это ваш int i, как он используетсяв вашей величине [i] напечатать заявление.

Основная частота основного тона для музыки часто отличается от пиковой величины FFT, поэтому вы можете исследовать некоторые алгоритмы оценки основного тона.

...