android - 字节数组音频连接Android

标签 android arrays audio byte concatenation

我正在尝试连接字节数组音频。(音频是 .wav,并被转换为字节数组)。 我当前的代码似乎是串联的。但是当我播放结果时,它只播放最终数组中的第一个字节样本。 你知道为什么下一个字节不播放吗?

     int length = 0;
     for (byte[] array : ListSamplesByte) {
     length += array.length;
     }
     byte[] result = new byte[length];
     int pos = 0;
     for (byte[] array : ListSamplesByte) {
         System.arraycopy(array, 0, result, pos, array.length);
         pos += array.length;
     }

     byte[] playByte = result;
     MediaPlayer.playAudio(playByte);

编辑 1:所有文件都是 44100Hz,16 位 PCM。即使所有字节数组都一样,也只播放第一个。我认为问题与未添加或删除的 block 中的 header 或字节有关。

最佳答案

我找到了解决方案。 这是连接的过程,请注意我所有的 wav 文件都具有相同的采样率和 channel 。

首先我需要一些关于 WAV 文件结构的知识。 wav 文件由标题(前 44 个字节)和原始数据组成。 http://soundfile.sapp.org/doc/WaveFormat/

1) 将您的 wav 文件转换为字节数组

2) 查看 HeaderInformation() 下面的函数,它接受字节数组参数,它创建一个 InputDataStream 并读取字节数组以获取标题信息,最重要的是获取 ChunkSize 长度(字节 4 -8)和原始数据长度(字节44)。

 public class AudioConcatenate {
 long myChunkSize;
 long mySubChunk1Size;
 int myFormat;
 long myChannels;
 long mySampleRate;
 long myByteRate;
 int myBlockAlign;
 int myBitsPerSample;
 long myDataSize;
 long totalChunkSize;

 byte[] myData;
 int byteRate=176400;
 long longSampleRate=44100;

 protected ArrayList<Long> ListDataSize= new ArrayList<Long>();
 protected ArrayList<byte[]> ListDataByte = new ArrayList<byte[]>();
 protected ArrayList<Long> ListChunkSize = new ArrayList<>();

 public AudioConcatenate(){
 }

 protected void HeaderInformation(byte[] SoundSample) {
 myData = null;
 DataInputStream inFile = newDataInputStream(newByteArrayInputStream(sample));
 byte[] tmpLong = new byte[4];
 byte[] tmpInt = new byte[2];

    try {
        while (inFile.available() > 0) {
            String chunkID = "" + (char) inFile.readByte() + (char) inFile.readByte() + (char) inFile.readByte() + (char) inFile.readByte();
            inFile.read(tmpLong); // read the ChunkSize
            myChunkSize = byteArrayToLong(tmpLong)+silenceArray.length;
            String format = "" + (char) inFile.readByte() + (char) inFile.readByte() + (char) inFile.readByte() + (char) inFile.readByte();
            String subChunk1ID = "" + (char) inFile.readByte() + (char) inFile.readByte() + (char) inFile.readByte() + (char) inFile.readByte();
            inFile.read(tmpLong); // read the SubChunk1Size
            mySubChunk1Size = byteArrayToLong(tmpLong);
            inFile.read(tmpInt); // read the audio format.  This should be 1 for PCM
            myFormat = byteArrayToInt(tmpInt);
            inFile.read(tmpInt); // read the # of channels (1 or 2)
            myChannels = byteArrayToInt(tmpInt);
            inFile.read(tmpLong); // read the samplerate
            mySampleRate = byteArrayToLong(tmpLong);
            inFile.read(tmpLong); // read the byterate
            myByteRate = byteArrayToLong(tmpLong);
            inFile.read(tmpInt); // read the blockalign
            myBlockAlign = byteArrayToInt(tmpInt);
            inFile.read(tmpInt); // read the bitspersample
            myBitsPerSample = byteArrayToInt(tmpInt);
            String dataChunkID = "" + (char) inFile.readByte() + (char) inFile.readByte() + (char) inFile.readByte() + (char) inFile.readByte();
            inFile.read(tmpLong); // read the size of the data
            myDataSize = byteArrayToLong(tmpLong)+silenceArray.length;
            // read the data chunk
            myData = new byte[(int) myDataSize];
            inFile.read(myData);

            ListDataSize.add(myDataSize);
            ListDataByte.add(FinalDataArray);
            ListChunkSize.add(myChunkSize);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
}

函数末尾byte[]的三个arraylist分别用于存储chunk Size、存储原始数据的byte数组、数据的byte数组大小。这样,每次您为声音调用该函数时,它都会存储基本数据。

4) 一旦你为多重声音调用了这个函数。 我们需要重新创建 wav header ,它将计算多个声音的长度。我们必须计算 ChunkSize 的总大小,以及原始数据的总大小。

public long  TotalDataSize(){
    int i;
    long sum = 0;
    for(i = 0; i < ListDataSize.size(); i++) {
        sum += ListDataSize.get(i);
    }
    return sum;
}


public long TotalChunkSize(){
    int i;
    long sum = 0;
    for(i = 0; i < ListChunkSize.size(); i++) {
        sum += ListChunkSize.get(i);
    }
    return sum;
}

We create the header and we include the new size, total chunkSize at byte [4-8], total data byte[40-43] 

  public byte[] WriteHeader(){
    byte[] header = new byte[44];
    long totalDataSize= TotalDataSize();
    long totalChunkSize=TotalChunkSize();

    header[0] = 'R';  // RIFF/WAVE header
    header[1] = 'I';
    header[2] = 'F';
    header[3] = 'F';
    header[4] = (byte) (totalChunkSize & 0xff);
    header[5] = (byte) ((totalChunkSize >> 8) & 0xff);
    header[6] = (byte) ((totalChunkSize >> 16) & 0xff);
    header[7] = (byte) ((totalChunkSize >> 24) & 0xff);
    header[8] = 'W';
    header[9] = 'A';
    header[10] = 'V';
    header[11] = 'E';
    header[12] = 'f';  // 'fmt ' chunk
    header[13] = 'm';
    header[14] = 't';
    header[15] = ' ';
    header[16] = 16;  // 4 bytes: size of 'fmt ' chunk
    header[17] = 0;
    header[18] = 0;
    header[19] = 0;
    header[20] = 1;  // format = 1
    header[21] = 0;
    header[22] = (byte) 2;
    header[23] = 0;
    header[24] = (byte) (longSampleRate & 0xff);
    header[25] = (byte) ((longSampleRate >> 8) & 0xff);
    header[26] = (byte) ((longSampleRate >> 16) & 0xff);
    header[27] = (byte) ((longSampleRate >> 24) & 0xff);
    header[28] = (byte) (byteRate & 0xff);
    header[29] = (byte) ((byteRate >> 8) & 0xff);
    header[30] = (byte) ((byteRate >> 16) & 0xff);
    header[31] = (byte) ((byteRate >> 24) & 0xff);
    header[32] = (byte) (2 * 16 / 8);  // block align
    header[33] = 0;
    header[34] = 16;  // bits per sample
    header[35] = 0;
    header[36] = 'd';
    header[37] = 'a';
    header[38] = 't';
    header[39] = 'a';
    header[40] = (byte) (totalDataSize & 0xff);
    header[41] = (byte) ((totalDataSize >> 8) & 0xff);
    header[42] = (byte) ((totalDataSize >> 16) & 0xff);
    header[43] = (byte) ((totalDataSize >> 24) & 0xff);
    return header;
}

6) 连接函数: 首先我们创建一个新的 ArrayList“ListFinalSound”来构造最终的声音。 我们首先添加新的 header ,然后添加 byte[] 原始数据。

 public byte[] ConcatenateSound(){

 ListFinalSound.add(WriteHeader()); 
 for (byte[] arrayRawData : ListDataByte) {
     ListFinalSound.add(arrayRawData); 
  }

 /* sum the length of each byte array to get the total and create later a new  byte array of the total length.**/
 int length = 0;
 for (byte[] array : ListFinalSound) {
 length += array.length;
 }

/* we concatenate with the use of System.arraycopy.
 For each loop it'll increment the position and concatenate the byte array**/

 byte[] ConcatenateSounds = new byte[length];
 int pos = 0;
 for (byte[] array : ListFinalSound) {
 System.arraycopy(array, 0, ConcatenateSounds, pos, array.length); 
 pos += array.length;
 }
 return ConcatenateSounds;
}     

7) ConcatenateSound() 函数返回连接。

关于android - 字节数组音频连接Android,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39487208/

相关文章:

java - 如何在 Java 中获取声音文件的总时间?

java - 必须有 Java 运行时环境或 Java 开发工具包才能运行 eclipse

c - 返回字符串中的第 i 个单词

c++ - 将字符串添加到未知大小的数组 C++

linux - 如何使用 bash 脚本从 base64 转换后的文件中播放声音?

android - (Android) 如何判断音效是否在音池中播放

javascript - 无法解析我的 Phonegap 项目中的 JSON 字符串错误

java - 对于 Android SDK 17 或更低版本,如何从 uri 获取选定的 xls 文件路径?

android - 带方向箭头的背景

javascript - 如何有效地检查数组中的任何子字符串是否包含在另一个字符串中