web-dev-qa-db-fra.com

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

J'essaie actuellement d'implémenter du code en utilisant Android pour détecter quand un certain nombre de plages de fréquences audio spécifiques sont lues via le microphone du téléphone. J'ai configuré la classe en utilisant le 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:

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

L'exécution d'une FFT est l'endroit où je suis bloqué, car j'ai très peu d'expérience dans ce domaine. J'ai essayé d'utiliser cette classe:

FFT en Java et classe complexe pour aller avec

J'envoie ensuite 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 me faire mal comprendre comment cette classe est censée fonctionner, mais les valeurs renvoyées sautent partout et ne sont pas représentatives d'une fréquence cohérente même en silence. Quelqu'un connaît-il un moyen d'effectuer cette tâche, ou suis-je trop compliqué pour essayer de saisir uniquement un petit nombre de plages de fréquences plutôt que de le dessiner sous forme de représentation graphique?

38
user723060

Vous devez d'abord vous assurer que le résultat que vous obtenez est correctement converti en float/double. Je ne sais pas comment fonctionne la version courte [], mais la version octet [] ne renvoie que la version octet brut. Ce tableau d'octets doit ensuite être correctement converti en un nombre à virgule flottante. Le code de la conversion devrait ressembler à 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 tableau complexe d'entrée.

Une fois que vous obtenez les résultats, utilisez les amplitudes des nombres complexes dans les résultats. La plupart des grandeurs devraient être proches 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 du tableau à de telles amplitudes en fréquences:

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