Lire les données WAV sous forme de tableau d'octets sur Android Java

Contenu de cet article

Si vous souhaitez simplement lire le son du fichier WAV sur Android, vous pouvez utiliser la classe MediaPlayer, etc. Vous voudrez peut-être lire les données WAV «à l'avance» et jouer avec les données.

«À l'avance» signifie «avant de jouer le son». Parce que si vous utilisez la classe MediaPlayer, vous pouvez obtenir les données brutes et FFT avec Visualizer.setDataCaptureListener, Puisqu'il s'agit du son en cours de lecture, il sera traité en temps réel.

Lien externe: afficher les égaliseurs et les formes d'onde à l'aide de VISUALIZER

Par conséquent, dans cet article, je vais vous présenter comment lire à l'avance les données WAV dans un tableau d'octets et les gérer tout en faisant attention aux en-têtes et autres.

Lire les données WAV

Si le fichier WAV (par exemple music.wav) est stocké dans le dossier res / raw, vous pouvez obtenir le tableau d'octets avec InputStream.

        try {
            InputStream is = getResources().openRawResource(R.raw.music);
            wavData = new byte[is.available()];
            String readBytes = String.format(Locale.US, "read bytes = %d", is.read(wavData));
            Log.e(TAG, readBytes);
            is.close();
        } catch (Exception e){
            e.printStackTrace();
        }

Lien externe de référence: Lire le fichier audio WAV sur AudioTrack

Analyse d'en-tête

Le fichier WAV a un en-tête d'environ 44 octets, suivi de données. Cependant, il semble que ces 44 octets puissent être ajoutés de différentes manières, il semble donc préférable d'acquérir les données tout en vérifiant correctement le contenu de l'en-tête.

Lien externe de référence: À propos de la structure des données du fichier son (extension: fichier WAV)

Le type d'en-tête s'appelle chunk, et il serait bon de savoir "fmt" et "data". (Pour plus de détails, veuillez consulter le lien externe ci-dessus) Par conséquent, vérifiez ces 'fmt' == 0x6d7420 et'data '== 0x64617461 et enregistrez leurs index respectifs.

        int fmtIdx = 0;
        for(int i = 0; i < wavData.length - 4; i ++){
            if(wavData[i] == 0x66 && wavData[i + 1] == 0x6d
                    && wavData[i + 2] == 0x74 && wavData[i + 3] == 0x20){ // 'fmt ' chunk
                fmtIdx = i;
                Log.i("Test", "fmtIdx:" + fmtIdx);
                break;
            }
        }
        if(fmtIdx == 0){
            Log.e(TAG, "No fmt chunk");
        }

        int dataIdx = 0;
        for(int i = 0; i < wavData.length - 4; i ++){
            if(wavData[i] == 0x64 && wavData[i + 1] == 0x61
                    && wavData[i + 2] == 0x74 && wavData[i + 3] == 0x61){ // 'data' chunk
                dataIdx = i;
                Log.i("Test", "dataIdx:" + dataIdx);
                break;
            }
        }
        if(dataIdx == 0){
            Log.e(TAG, "No data chunk");
        }

Ensuite, obtenons le nombre de canaux, la fréquence d'échantillonnage, le nombre de bits (ici, le nombre d'octets) et la taille des données. La taille des données est essentiellement la partie excluant l'en-tête, mais il semble que le format WAV puisse être librement attaché avec un pied de page, alors obtenez-le. La source sonore que j'ai réellement essayée contenait une bonne quantité de pied de page.

        int wavChannel = (int)(wavData[fmtIdx + 10]);
        Log.i("Test", "wavChannel:" + wavChannel);

        //int wavSamplingRate = ((int)(wavData[fmtIdx + 15]) << 24) + ((int)(wavData[fmtIdx + 14]) << 16)
        //        + ((int)(wavData[fmtIdx + 13]) << 8) + (int)(wavData[fmtIdx + 12]);
        //↑ Il semble que la manière d'écrire n'est pas bonne, alors corrigez-la
        byte[] bytes1 = {wavData[fmtIdx + 15], wavData[fmtIdx + 14], wavData[fmtIdx + 13], wavData[fmtIdx + 12]};
        int wavSamplingRate = ByteBuffer.wrap(bytes1).getInt();

        Log.i("Test", "wavSamplingRate:" + wavSamplingRate);

        int wavByte = (int)(wavData[fmtIdx + 22]) / 8;
        Log.i("Test", "wavByte:" + wavByte);

        //int wavDataSize = ((int)(wavData[dataIdx + 7]) << 24) + ((int)(wavData[dataIdx + 6]) << 16)
        //        + ((int)(wavData[dataIdx + 5]) << 8) + (int)(wavData[dataIdx + 4]);
        byte[] bytes2 = {wavData[dataIdx + 7], wavData[dataIdx + 6], wavData[dataIdx + 5], wavData[dataIdx + 4]};
        int wavDataSize = ByteBuffer.wrap(bytes2).getInt();

        Log.i("Test", "wavDataSize:" + wavDataSize);

        int wavHeaderSize = dataIdx + 8;

        int[] musicDataRight = new int[wavDataSize / wavByte / wavChannel];
        int[] musicDataLeft = new int[wavDataSize / wavByte / wavChannel];

L'endroit où sont stockés 4 octets est défini sur int par ~~ opération de décalage ~~ ByteBuffer. En outre, la taille de l'en-tête est calculée car elle sera utilisée ultérieurement. Lorsque le canal est 2, les sources sonores gauche et droite peuvent être acquises, alors mettez-les dans musicDataRight et musicDataLeft.

        byte[] bytes_temp = {0, 0, 0, 0}; //Si ce n'est pas 4 octets, BufferUnderflowException se produira.
        if(wavByte == 1 && wavChannel == 1){
            for(int i = 0, j = wavHeaderSize; i < musicDataRight.length; i ++, j ++){
                musicDataRight[i] = (int)wavData[j];
                musicDataLeft[i]  = (int)wavData[j];
            }
        } else if(wavByte == 1 && wavChannel == 2){
            for(int i = 0, j = wavHeaderSize; i < musicDataRight.length; i ++, j += 2){
                musicDataRight[i] = (int)wavData[j];
                musicDataLeft[i]  = (int)wavData[j + 1];
            }
        } else if(wavByte == 2 && wavChannel == 1){
            for(int i = 0, j = wavHeaderSize; i < musicDataRight.length; i ++, j += 2){
                //musicDataRight[i] = ((int)wavData[j + 1] << 8) + (int)wavData[j];
                //musicDataLeft[i]  = ((int)wavData[j + 1] << 8) + (int)wavData[j];
                bytes_temp[2] = wavData[j + 1];
                bytes_temp[3] = wavData[j];
                musicDataRight[i] = ByteBuffer.wrap(bytes_temp).getInt();
                musicDataLeft[i] = ByteBuffer.wrap(bytes_temp).getInt();

            }
        } else if(wavByte == 2 && wavChannel == 2){
            for(int i = 0, j = wavHeaderSize; i < musicDataRight.length; i ++, j += 4){
                //musicDataRight[i] = ((int)wavData[j + 1] << 8) + (int)wavData[j];
                //musicDataLeft[i]  = ((int)wavData[j + 3] << 8) + (int)wavData[j + 2];
                bytes_temp[2] = wavData[j + 1];
                bytes_temp[3] = wavData[j];
                musicDataRight[i] = ByteBuffer.wrap(bytes_temp).getInt();
                bytes_temp[2] = wavData[j + 3];
                bytes_temp[3] = wavData[j + 2];
                musicDataLeft[i] = ByteBuffer.wrap(bytes_temp).getInt();

            }
        }

Les données sont stockées par le nombre de canaux et le nombre d'octets. Si je voulais le faire, je pourrais rassembler les formules (je l'ai en fait essayé), mais je les ai écrites séparément car cela réduirait la lisibilité. Lorsque le nombre de canaux est 1, le même son est mis à gauche et à droite. De plus, si le nombre de canaux ou d'octets est de 3 ou plus, il est nécessaire de les ajouter séparément.

C'est la fin de la procédure de lecture des données WAV sous forme de tableau d'octets.

en conclusion

Avec cela, il est possible d'afficher la forme d'onde lue sous forme de graphique et de traiter les données. Cependant, comme je l'ai mentionné au début, veuillez me dire s'il existe un moyen plus simple.

Recommended Posts

Lire les données WAV sous forme de tableau d'octets sur Android Java
Comment convertir un fichier en tableau d'octets en Java
Convertir un tableau d'octets Java en une chaîne hexadécimale
Lors de la recherche de plusieurs dans un tableau Java
[Android / Java] Exploitez une base de données locale dans la salle
Comment compresser un fichier JAVA CSV et le gérer dans un tableau d'octets
Lire JSON en Java
Comment créer un URI de données (base64) en Java
Travailler comme une équipe! Face Null de front en Java
Java11: exécuter le code Java dans un seul fichier tel quel
[Java] Je souhaite convertir un tableau d'octets en un nombre hexadécimal
Lire l'entrée standard en Java
Multiplication dans un tableau Ruby
Rechercher un sous-ensemble en Java
Importer des données Excel avec Java
Lire des fichiers binaires dans Java 2
[Java] [Android] Lire le fichier ini
Importer des données Excel avec Java 3
Tri d'une liste avec un tableau de type int comme élément (Java) (Comparator)
Source pour afficher le tableau de caractères avec numberPicker dans Android Studio (Java)
Convertir un tableau de chaînes en une liste d'entiers en Java
Lire les éléments contenant des virgules dans les fichiers CSV sans fractionnement (Java)
Déterminer si un clavier personnalisé est activé dans Android Studio (Java)
Essayez d'implémenter Android Hilt en Java
Lisez facilement les fichiers texte en Java (Java 11 et Java 7)
3 Implémentez un interpréteur simple en Java
Lire le fichier de propriétés Java en C #
J'ai créé un PDF avec Java.
Afficher les données Firestore dans RecyclerView [Java]
Lire CSV en Java (annotation Super CSV)
Un exemple simple de rappels en Java
Restez coincé dans un Java Primer
Comment créer un tableau Java
Je veux ForEach un tableau avec une expression Lambda en Java
[Java] [Pour les débutants] Comment insérer des éléments directement dans un tableau à deux dimensions
A propos du renvoi d'une référence dans un Java Getter
Qu'est-ce qu'une classe en langage Java (3 /?)
Créer des données binaires de longueur variable en Java
[Création] Un mémorandum sur le codage en Java
Organisation des notes dans la tête (Java-Arrangement)
Java crée un tableau dans un document Word
Java crée un graphique circulaire dans Excel
Qu'est-ce qu'une classe en langage Java (1 /?)
Qu'est-ce qu'une classe en langage Java (2 /?)
Créer une application TODO dans Java 7 Créer un en-tête
Lire Felica en utilisant RC-S380 (PaSoRi) en Java
Lecture de fichiers RAW, WAV, MP3 en Java
Créons une application de calcul avec Java
Lire le fichier xlsx en Java avec Selenium
Implémenter quelque chose comme une pile en Java
Diviser une chaîne avec ". (Dot)" en Java
Création d'une classe de matrice dans Java Partie 1
De Java à C et de C à Java dans Android Studio
Un moyen pour les développeurs Java / Scala de faire progresser leur carrière en tant qu'ingénieurs de données.