39 votes

FFT audio Android pour récupérer une amplitude de fréquence spécifique à l'aide d'audiorecord

Je suis en train d'essayer de mettre en œuvre un code en utilisant Android pour détecter le moment où un certain nombre de plages de fréquences audio sont lus via le microphone du téléphone. J'ai mis en place la classe à l'aide de l' AudioRecord classe:

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);

L'audio est ensuite lu dans:

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

L'exécution d'une FFT est là que j'ai coincé, comme je l'ai très peu d'expérience dans ce domaine. J'ai essayé d'utiliser cette classe:

FFT en Java et Complexe de la classe pour aller avec elle

Je suis ensuite envoyer les valeurs suivantes:

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

Cela pourrait facilement être moi malentendu comment cette classe est destinée à travailler, mais les valeurs renvoyées sauter dans tous les sens et ne sont pas représentatives d'un même fréquence, même dans le silence. Quelqu'un est-il au courant de la façon d'effectuer cette tâche, ou suis-je de compliquer à l'excès des questions pour essayer de le récupérer uniquement un petit nombre de gammes de fréquences plutôt que de le dessiner comme une représentation graphique?

33voto

shams Points 1986

D'abord vous devez vous assurer que le résultat que vous obtenez est correctement converti en float/double. Je ne suis pas sûr de savoir comment la court[] version fonctionne, mais le byte[] uniquement sur la version renvoie le nombre d'octets brut version. Ce tableau d'octets doit être correctement converti en un nombre à virgule flottante. Le code pour la conversion devrait ressembler à quelque chose comme ceci:

    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;
    }

Ensuite, vous utilisez micBufferData[] pour créer votre entrée de gamme complexe.

Une fois que vous obtenez les résultats, utilisez l'ordre de grandeur des nombres complexes dans les résultats. La plupart des grandeurs doit être proche de zéro, sauf les fréquences qui ont des valeurs réelles.

Vous avez besoin de la fréquence d'échantillonnage pour convertir les indices de tableau de telles grandeurs de fréquences:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X