Lesen Sie WAV-Daten als Byte-Array unter Android Java

Inhalt dieses Artikels

Wenn Sie nur den Sound einer WAV-Datei auf Android abspielen möchten, können Sie die MediaPlayer-Klasse usw. verwenden. Möglicherweise möchten Sie die WAV-Daten "im Voraus" lesen und mit den Daten herumspielen.

"Im Voraus" bedeutet "vor dem Abspielen des Sounds". Da Sie mit Visualizer.setDataCaptureListener mithilfe der MediaPlayer-Klasse Rohdaten und FFT abrufen können, Da dies der abgespielte Sound ist, wird er in Echtzeit verarbeitet.

Externer Link: Anzeige von Equalizern und Wellenformen mit VISUALIZER

Daher werde ich in diesem Artikel vorstellen, wie WAV-Daten in einem Byte-Array im Voraus gelesen und verarbeitet werden, während auf Header und dergleichen geachtet wird.

WAV-Daten lesen

Wenn die WAV-Datei (z. B. music.wav) im Ordner res / raw gespeichert ist, können Sie das Byte-Array mit InputStream abrufen.

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

Externer Referenzlink: WAV-Audiodatei auf AudioTrack abspielen

Header-Analyse

Die WAV-Datei hat einen Header von ungefähr 44 Bytes, gefolgt von Daten. Es scheint jedoch, dass diese 44 Bytes auf verschiedene Arten hinzugefügt werden können. Daher scheint es besser, die Daten zu erfassen, während der Inhalt des Headers ordnungsgemäß überprüft wird.

Externer Referenzlink: Informationen zur Datenstruktur der Audiodatei (Erweiterung: WAV-Datei)

Die Art des Headers heißt Chunk, und es wäre schön, 'fmt'and'data' zu kennen. (Für Details siehe den externen Link oben) Überprüfen Sie daher diese 'fmt' == 0x6d7420 und'data '== 0x64617461 und speichern Sie ihre jeweiligen Indizes.

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

Als nächstes ermitteln wir die Anzahl der Kanäle, die Abtastrate, die Anzahl der Bits (hier die Anzahl der Bytes) und die Datengröße. Die Datengröße ist im Grunde der Teil ohne den Header, aber es scheint, dass das WAV-Format frei mit einer Fußzeile angehängt werden kann. Die Tonquelle, die ich tatsächlich ausprobiert habe, enthielt ziemlich viel Fußzeile.

        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]);
        //↑ Es scheint, dass die Schreibweise nicht gut ist, also korrigieren Sie sie
        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];

Der Ort, an dem 4 Bytes gespeichert sind, wird durch ~~ Shift-Operation ~~ ByteBuffer auf int gesetzt. Außerdem wird die Headergröße berechnet, da sie später verwendet wird. Wenn der Kanal 2 ist, können die linke und die rechte Tonquelle erfasst werden. Fügen Sie sie daher in musicDataRight und musicDataLeft ein.

        byte[] bytes_temp = {0, 0, 0, 0}; //Wenn es nicht 4 Bytes sind, tritt eine BufferUnderflowException auf.
        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();

            }
        }

Die Daten werden nach Anzahl der Kanäle und Anzahl der Bytes gespeichert. Wenn ich es tun wollte, könnte ich die Formeln zusammenstellen (ich habe es tatsächlich versucht), aber ich habe sie separat geschrieben, weil dies die Lesbarkeit beeinträchtigen würde. Wenn die Anzahl der Kanäle 1 beträgt, wird links und rechts der gleiche Ton ausgegeben. Wenn die Anzahl der Kanäle oder Bytes 3 oder mehr beträgt, müssen sie separat hinzugefügt werden.

Dies ist das Ende der Prozedur zum Lesen von WAV-Daten als Byte-Array.

abschließend

Damit ist es möglich, die gelesene Wellenform als Grafik anzuzeigen und die Daten zu verarbeiten. Wie ich eingangs erwähnt habe, lassen Sie mich bitte wissen, ob es einen einfacheren Weg gibt.

Recommended Posts

Lesen Sie WAV-Daten als Byte-Array unter Android Java
So konvertieren Sie eine Datei in ein Byte-Array in Java
Konvertieren Sie ein Java-Byte-Array in eine hexadezimale Zeichenfolge
Bei der Suche nach mehreren in einem Java-Array
[Android / Java] Betreiben Sie eine lokale Datenbank in Room
So komprimieren Sie eine JAVA-CSV-Datei und verwalten sie in einem Byte-Array
Lesen Sie JSON in Java
So erstellen Sie einen Daten-URI (base64) in Java
Arbeitet als ein Team! Stellen Sie sich in Java frontal Null
Java11: Führen Sie Java-Code unverändert in einer einzelnen Datei aus
[Java] Ich möchte ein Byte-Array in eine Hexadezimalzahl konvertieren
Lesen Sie die Standardeingabe in Java
Multiplikation innerhalb eines Ruby-Arrays
Suchen Sie eine Teilmenge in Java
Importieren Sie Excel-Daten mit Java
Lesen Sie Binärdateien in Java 2
[Java] [Android] INI-Datei lesen
Importieren Sie Excel-Daten mit Java 3
Sortieren einer Liste mit einem Array vom Typ int als Element (Java) (Comparator)
Quelle zur Anzeige des Zeichenarrays mit numberPicker in Android Studio (Java)
Verwandeln Sie ein Array von Strings in eine Liste von Ganzzahlen in Java
Lesen Sie Elemente mit Kommas in CSV-Dateien ohne Aufteilung (Java).
Feststellen, ob eine benutzerdefinierte Tastatur in Android Studio (Java) aktiviert ist
Versuchen Sie, Android Hilt in Java zu implementieren
Einfaches Lesen von Textdateien in Java (Java 11 & Java 7)
3 Implementieren Sie einen einfachen Interpreter in Java
Lesen Sie die Java-Eigenschaftendatei in C #
Ich habe ein PDF mit Java erstellt.
Firestore-Daten in RecyclerView [Java] anzeigen
Lesen Sie CSV in Java (Super CSV Annotation)
Ein einfaches Beispiel für Rückrufe in Java
Bleiben Sie in einem Java Primer stecken
So erstellen Sie ein Java-Array
Ich möchte für jedes Array mit Lambda-Ausdruck in Java
[Java] [Für Anfänger] So fügen Sie Elemente direkt in ein zweidimensionales Array ein
Informationen zum Zurückgeben einer Referenz in einem Java Getter
Was ist eine Klasse in der Java-Sprache (3 /?)
Erstellen Sie Binärdaten variabler Länge in Java
[Erstellen] Ein Memorandum über das Codieren in Java
Notizen im Kopf organisieren (Java-Arrangement)
Java erstellt eine Tabelle in einem Word-Dokument
Java erstellt ein Kreisdiagramm in Excel
Was ist eine Klasse in der Java-Sprache (1 /?)
Was ist eine Klasse in der Java-Sprache (2 /?)
Erstellen Sie eine TODO-App in Java 7 Create Header
Lesen Sie Felica mit RC-S380 (PaSoRi) in Java
Spielen Sie RAW-, WAV- und MP3-Dateien in Java ab
Lassen Sie uns eine Taschenrechner-App mit Java erstellen
Lesen Sie die xlsx-Datei in Java mit Selenium
Implementieren Sie so etwas wie einen Stack in Java
Teilen Sie eine Zeichenfolge in Java mit ". (Dot)"
Erstellen einer Matrixklasse in Java Teil 1
Von Java nach C und von C nach Java in Android Studio
Eine Möglichkeit für Java / Scala-Entwickler, ihre Karriere als Dateningenieure voranzutreiben.