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