34 votes

Représentation graphique de la hauteur (fréquence) d'un son

Je veux tracer la hauteur d'un son dans un graphique.

Actuellement je peux parcelle de l'amplitude. Le graphique ci-dessous est créé par les données renvoyées par getUnscaledAmplitude():

alt text

AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(file)));
byte[] bytes = new byte[(int) (audioInputStream.getFrameLength()) * (audioInputStream.getFormat().getFrameSize())];
audioInputStream.read(bytes);

// Get amplitude values for each audio channel in an array.
graphData = type.getUnscaledAmplitude(bytes, 1);


public int[][] getUnscaledAmplitude(byte[] eightBitByteArray, int nbChannels)
{
    int[][] toReturn = new int[nbChannels][eightBitByteArray.length / (2 * nbChannels)];
    int index = 0;

    for (int audioByte = 0; audioByte < eightBitByteArray.length;)
    {
        for (int channel = 0; channel < nbChannels; channel++)
        {
            // Do the byte to sample conversion.
            int low = (int) eightBitByteArray[audioByte];
            audioByte++;
            int high = (int) eightBitByteArray[audioByte];
            audioByte++;
            int sample = (high << 8) + (low & 0x00ff);

            toReturn[channel][index] = sample;
        }
        index++;
    }

    return toReturn;
}

Mais j'ai besoin de montrer l'audio pitch, pas d'amplitude. La transformée de Fourier rapide apparaît pour obtenir la hauteur, mais il a besoin d'en savoir plus variables que les octets brutes que j'ai, et est très complexe et les mathématiques.

Est-il un moyen pour que je puisse faire cela?

49voto

Oli Charlesworth Points 148744

Fréquence (un objectif métrique) n'est pas la même que la hauteur (subjective de la quantité). En général, la détection de hauteur est un très épineux problème.

En supposant que vous voulez juste pour tracer le graphique de la réponse en fréquence pour l'instant, vous avez peu de choix, mais l'utilisation de la FFT, car il est LA méthode pour obtenir la réponse en fréquence de temps-domaine des données. (Eh bien, il y a d'autres méthodes, telles que la transformée en cosinus discrète, mais ils sont tout aussi délicate à mettre en œuvre, et de plus en plus difficile à interpréter).

Si vous êtes aux prises avec la mise en œuvre de la FFT, notez que c'est vraiment juste un algorithme efficace pour le calcul de la transformée de Fourier discrète (DFT); voir http://en.wikipedia.org/wiki/Discrete_Fourier_transform. La base de DFT algorithme est beaucoup plus facile (juste deux boucles imbriquées), mais fonctionne à une beaucoup plus lent (O(N^2) plutôt que de O(N log N)).

Si vous souhaitez faire quelque chose de plus complexe que de simplement tracé de la fréquence de contenu (comme la détection de hauteur, ou de fenêtrage (comme d'autres l'ont suggéré)), je crains que vous allez devoir apprendre ce que les mathématiques moyens.

24voto

Guy Sirton Points 5092

La transformée de Fourier rapide n'a pas besoin d'en savoir plus alors les octets d'entrée que vous avez. Ne soyez pas effrayés par l'article de Wikipedia. Un algorithme de FFT va prendre votre signal d'entrée (avec le commun des algorithmes de FFT le nombre d'échantillons est nécessaire pour être une puissance de 2, par exemple, 256, 512, 1024) et le retour d'un vecteur de nombres complexes avec la même taille. Parce que votre entrée est réel, pas de complexe, (partie imaginaire mis à zéro) le vecteur renvoyé sera symétrique. Seulement la moitié de celui-ci va contenir des données. Puisque vous n'avez pas de soins sur la phase, vous pouvez simplement prendre de l'ampleur des nombres complexes, qui est sqrt(a^2+b^2). Juste de prendre la absoulte valeur d'un nombre complexe peut aussi travailler, dans certaines langues, c'est l'équivalent de l'expression précédente.

Il y a des implémentations Java de la FFT disponibles, par exemple: http://www.cs.princeton.edu/introcs/97data/FFT.java.html

Le Pseudo-code ressemblera à quelque chose comme:

Complex in[1024];
Complex out[1024];
Copy your signal into in
FFT(in, out)
for every member of out compute sqrt(a^2+b^2)
To find frequency with highest power scan for the maximum value in the first 512 points in out

La sortie contient entrées pour les fréquences comprises entre zéro et la moitié de votre fréquence d'échantillonnage.

Depuis FFT suppose une répétition de signal, vous pouvez appliquer une fenêtre de votre signal d'entrée. Mais ne vous inquiétez pas à ce sujet à la première.

Vous pouvez trouver plus d'informations sur le web, par exemple: FFT pour les débutants

Aussi comme Oli notes lorsque plusieurs fréquences sont présentes à la hauteur perçue est plus complexe phénomène.

2voto

britishmutt Points 1133

Il y a plusieurs autres questions sur stackoverflow à propos de ce problème. Peut-être que cela aidera.

Au lieu de cela, vous pourriez essayer de trouver une copie de l'Audio Numérique avec Java par Craig Lindley. Je ne pense pas que c'est de l'impression, mais la copie sur mon bureau a une section sur la FFT et également un exemple d'application d'un accordeur de guitare.

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