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.
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
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.
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